diff --git a/build.gradle b/build.gradle
index 69922b16..58465b32 100644
--- a/build.gradle
+++ b/build.gradle
@@ -44,13 +44,15 @@ reckon {
 repositories {
     mavenLocal()
     flatDir { dirs 'lib' }
-    maven { name 'entity-reach-attributes'; url 'https://maven.jamieswhiteshirt.com/libs-release' }
+    maven { name 'entity-reach-attributes'; url 'https://maven.jamieswhiteshirt.com/libs-release'; content { includeGroup "com.jamieswhiteshirt" } }
     maven { name 'trinkets'; url 'https://maven.ladysnake.org/releases' }
     maven { name 'mod-menu'; url 'https://maven.terraformersmc.com/' }
     maven { name 'minelp-snapshot'; url 'https://repo.minelittlepony-mod.com/maven/snapshot' }
     maven { name 'minelp-releases'; url 'https://repo.minelittlepony-mod.com/maven/release' }
     maven { name 'TerraformersMC'; url 'https://maven.terraformersmc.com/' }
     maven { name 'Nodium'; url 'https://maven.cafeteria.dev/releases/' }
+    maven { name 'Greenhouse Maven For Farmers delight'; url 'https://maven.greenhouseteam.dev/releases/' }
+    maven { name 'Porting Lib For Farmers delight'; url = 'https://mvn.devos.one/releases/' }
     maven { name 'Modrinth'; url 'https://api.modrinth.com/maven' }
     maven { name 'JitPack'; url 'https://jitpack.io'; content { includeGroup "com.github.Virtuoel" } }
 }
@@ -80,11 +82,13 @@ dependencies {
 
     modImplementation "com.terraformersmc.terraform-api:terraform-wood-api-v1:${project.terraformer_api_version}"
     include "com.terraformersmc.terraform-api:terraform-wood-api-v1:${project.terraformer_api_version}"
-    
+
     modImplementation "me.luligabi:NoIndium:${project.nodium_version}"
     include "me.luligabi:NoIndium:${project.nodium_version}"
 
-    modCompileOnly "maven.modrinth:farmers-delight-fabric:${project.farmers_delight_version}", { exclude group: "net.fabricmc.fabric-api" }
+    modImplementation "vectorwing:FarmersDelight-Refabricated:${project.farmers_delight_version}", {
+      exclude group: "net.fabricmc"
+    }
     if (project.use_pehkui == '1') {
       modCompileOnly "maven.modrinth:pehkui:${project.pehkui_version}", { exclude group: "net.fabricmc.fabric-api" }
       modCompileOnly "com.github.Virtuoel:KanosConfig:0.4.1", { exclude group: "net.fabricmc.fabric-api" }
@@ -103,6 +107,10 @@ dependencies {
     }
 }
 
+remapJar {
+    addNestedDependencies = true
+}
+
 processResources {
     inputs.property "version", project.version.toString()
 
diff --git a/gradle.properties b/gradle.properties
index f56cd269..e821a843 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -5,7 +5,7 @@ org.gradle.daemon=false
   # check these on https://fabricmc.net/develop
   minecraft_version=1.20.1
   yarn_mappings=1.20.1+build.10
-  loader_version=0.15.3
+  loader_version=0.15.7
   fabric_version=0.91.0+1.20.1
 
 # Mod Properties
@@ -22,8 +22,8 @@ org.gradle.daemon=false
 # Dependencies
   fabwork_version=1.2.0
   modmenu_version=7.0.0-beta.2
-  minelp_version=4.10.4+1.20.1
-  kirin_version=1.15.4+1.20
+  minelp_version=4.10.6+1.20.1
+  kirin_version=1.15.5-beta.1+1.20.1
   reach_attributes_version=2.3.4
   trinkets_version=3.7.1
   terraformer_api_version=7.0.0-beta.1
@@ -33,7 +33,7 @@ org.gradle.daemon=false
   use_pehkui=0
   use_sodium=1
 
-  farmers_delight_version=1.4.3
+  farmers_delight_version=1.20.1-2.0.9
   pehkui_version=3.7.8+1.14.4-1.20.1
   iris_version=1.6.17+1.20.1
   sodium_version=mc1.20.1-0.5.8
diff --git a/src/main/java/com/minelittlepony/unicopia/Debug.java b/src/main/java/com/minelittlepony/unicopia/Debug.java
index 8cc8847e..2e3533df 100644
--- a/src/main/java/com/minelittlepony/unicopia/Debug.java
+++ b/src/main/java/com/minelittlepony/unicopia/Debug.java
@@ -51,7 +51,7 @@ public interface Debug {
         )).forEach((namespace, entries) -> {
             @SuppressWarnings("deprecation")
             var unregistered = entries.stream()
-                .filter(entry -> !entry.getValue().getRegistryEntry().isIn(UTags.HAS_NO_TRAITS) && SpellTraits.of(entry.getValue()).isEmpty())
+                .filter(entry -> !entry.getValue().getRegistryEntry().isIn(UTags.Items.HAS_NO_TRAITS) && SpellTraits.of(entry.getValue()).isEmpty())
                 .map(entry -> {
                     String id = entry.getKey().getValue().toString();
 
diff --git a/src/main/java/com/minelittlepony/unicopia/UConventionalTags.java b/src/main/java/com/minelittlepony/unicopia/UConventionalTags.java
index 44e8571e..6b54e607 100644
--- a/src/main/java/com/minelittlepony/unicopia/UConventionalTags.java
+++ b/src/main/java/com/minelittlepony/unicopia/UConventionalTags.java
@@ -7,32 +7,64 @@ import net.minecraft.registry.tag.TagKey;
 import net.minecraft.util.Identifier;
 
 public interface UConventionalTags {
-    TagKey<Item> APPLES = item("apples");
-    TagKey<Item> ACORNS = item("acorns");
-    TagKey<Item> PINECONES = item("pinecones");
-    TagKey<Item> PINEAPPLES = item("pineapples");
-    TagKey<Item> BANANAS = item("bananas");
-    TagKey<Item> STICKS = item("sticks");
-    TagKey<Item> SEEDS = item("seeds");
-    TagKey<Item> GRAIN = item("grain");
-    TagKey<Item> NUTS = item("nuts");
-    TagKey<Item> MUSHROOMS = item("mushrooms");
-    TagKey<Item> MUFFINS = item("muffins");
-    TagKey<Item> MANGOES = item("mangoes");
-    TagKey<Item> OATMEALS = item("oatmeals");
+    interface Blocks {
+        TagKey<Block> CONCRETE_POWDERS = block("concrete_powders");
+        TagKey<Block> CONCRETES = block("concretes");
+        TagKey<Block> GLAZED_TERRACOTTAS = block("glazed_terracottas");
+        TagKey<Block> CORAL_BLOCKS = block("coral_blocks");
+        TagKey<Block> CORAL_FANS = block("coral_fans");
+        TagKey<Block> CORALS = block("corals");
 
-    TagKey<Item> FRUITS = item("fruits");
-
-    TagKey<Item> COOKED_FISH = item("cooked_fish");
-
-    TagKey<Item> CROPS_PEANUTS = item("crops/peanuts");
-    TagKey<Item> TOOL_KNIVES = item("tools/knives");
-
-    static TagKey<Item> item(String name) {
-        return TagKey.of(RegistryKeys.ITEM, new Identifier("c", name));
+        private static TagKey<Block> block(String name) {
+            return TagKey.of(RegistryKeys.BLOCK, new Identifier("c", name));
+        }
     }
 
-    static TagKey<Block> block(String name) {
-        return TagKey.of(RegistryKeys.BLOCK, new Identifier("c", name));
+    interface Items {
+        TagKey<Item> CONCRETE_POWDERS = item("concrete_powders");
+        TagKey<Item> CONCRETES = item("concretes");
+        TagKey<Item> GLAZED_TERRACOTTAS = item("glazed_terracottas");
+        TagKey<Item> CORAL_BLOCKS = item("coral_blocks");
+        TagKey<Item> CORAL_FANS = item("coral_fans");
+        TagKey<Item> CORALS = item("corals");
+
+        TagKey<Item> APPLES = item("apples");
+        TagKey<Item> ACORNS = item("acorns");
+        TagKey<Item> PINECONES = item("pinecones");
+        TagKey<Item> PINEAPPLES = item("pineapples");
+        TagKey<Item> BANANAS = item("bananas");
+        TagKey<Item> STICKS = item("sticks");
+        TagKey<Item> SEEDS = item("seeds");
+        TagKey<Item> GRAIN = item("grain");
+        TagKey<Item> NUTS = item("nuts");
+        TagKey<Item> MUSHROOMS = item("mushrooms");
+        TagKey<Item> MUFFINS = item("muffins");
+        TagKey<Item> MANGOES = item("mangoes");
+        TagKey<Item> OATMEALS = item("oatmeals");
+        TagKey<Item> COOKIES = item("cookies");
+
+        TagKey<Item> FRUITS = item("fruits");
+        TagKey<Item> WORMS = item("worms");
+        TagKey<Item> ROCKS = item("rocks");
+
+        TagKey<Item> RAW_INSECT = item("raw_insect");
+        TagKey<Item> COOKED_INSECT = item("cooked_insect");
+        TagKey<Item> ROTTEN_INSECT = item("rotten_insect");
+
+        TagKey<Item> RAW_FISH = item("raw_fish");
+        TagKey<Item> COOKED_FISH = item("cooked_fish");
+        TagKey<Item> ROTTEN_FISH = item("rotten_fish");
+        TagKey<Item> RAW_MEAT = item("raw_meat");
+        TagKey<Item> COOKED_MEAT = item("cooked_meat");
+        TagKey<Item> ROTTEN_MEAT = item("rotten_meat");
+        TagKey<Item> DESSERTS = item("desserts");
+        TagKey<Item> CANDY = item("candy");
+
+        TagKey<Item> CROPS_PEANUTS = item("crops/peanuts");
+        TagKey<Item> TOOL_KNIVES = item("tools/knives");
+
+        private static TagKey<Item> item(String name) {
+            return TagKey.of(RegistryKeys.ITEM, new Identifier("c", name));
+        }
     }
 }
diff --git a/src/main/java/com/minelittlepony/unicopia/UTags.java b/src/main/java/com/minelittlepony/unicopia/UTags.java
index 71120481..83e9cb37 100644
--- a/src/main/java/com/minelittlepony/unicopia/UTags.java
+++ b/src/main/java/com/minelittlepony/unicopia/UTags.java
@@ -11,58 +11,6 @@ import net.minecraft.util.Identifier;
 import net.minecraft.world.dimension.DimensionType;
 
 public interface UTags {
-    TagKey<Item> FRESH_APPLES = item("fresh_apples");
-
-    TagKey<Item> FALLS_SLOWLY = item("falls_slowly");
-    TagKey<Item> PIES = item("pies");
-    TagKey<Item> CAN_CUT_PIE = item("can_cut_pie");
-
-    TagKey<Item> MAGIC_FEATHERS = item("magic_feathers");
-
-    TagKey<Item> SHADES = item("shades");
-    TagKey<Item> CHANGELING_EDIBLE = item("food_types/changeling_edible");
-    TagKey<Item> SPOOKED_MOB_DROPS = item("spooked_mob_drops");
-    TagKey<Item> HAS_NO_TRAITS = item("has_no_traits");
-    TagKey<Item> IS_DELIVERED_AGGRESSIVELY = item("is_delivered_aggressively");
-    TagKey<Item> FLOATS_ON_CLOUDS = item("floats_on_clouds");
-    TagKey<Item> COOLS_OFF_KIRINS = item("cools_off_kirins");
-    TagKey<Item> LOOT_BUG_HIGH_VALUE_DROPS = item("loot_bug_high_value_drops");
-
-    TagKey<Item> SHELLS = item("food_types/shells");
-
-    TagKey<Item> POLEARMS = item("polearms");
-    TagKey<Item> HORSE_SHOES = item("horse_shoes");
-    TagKey<Item> APPLE_SEEDS = item("apple_seeds");
-
-    TagKey<Item> BASKETS = item("baskets");
-    TagKey<Item> BADGES = item("badges");
-    TagKey<Item> WOOL_BED_SHEETS = item("wool_bed_sheets");
-    TagKey<Item> BED_SHEETS = item("bed_sheets");
-    TagKey<Item> CLOUD_JARS = item("cloud_jars");
-
-    TagKey<Block> FRAGILE = block("fragile");
-    TagKey<Block> INTERESTING = block("interesting");
-    TagKey<Block> CATAPULT_IMMUNE = block("catapult_immune");
-    TagKey<Block> JARS = block("jars");
-
-    TagKey<Block> CRYSTAL_HEART_BASE = block("crystal_heart_base");
-    TagKey<Block> CRYSTAL_HEART_ORNAMENT = block("crystal_heart_ornament");
-    TagKey<Block> UNAFFECTED_BY_GROW_ABILITY = block("unaffected_by_grow_ability");
-    TagKey<Block> KICKS_UP_DUST = block("kicks_up_dust");
-
-    TagKey<Block> POLEARM_MINEABLE = block("mineable/polearm");
-
-    TagKey<EntityType<?>> TRANSFORMABLE_ENTITIES = entity("transformable");
-
-    TagKey<StatusEffect> PINEAPPLE_EFFECTS = effect("pineapple_effects");
-
-    TagKey<DamageType> BREAKS_SUNGLASSES = damage("breaks_sunglasses");
-    TagKey<DamageType> SPELLBOOK_IMMUNE_TO = damage("spellbook_immune_to");
-    TagKey<DamageType> FROM_ROCKS = damage("from_rocks");
-    TagKey<DamageType> FROM_HORSESHOES = damage("from_horseshoes");
-
-    TagKey<DimensionType> HAS_NO_ATMOSPHERE = dimension("has_no_atmosphere");
-
     interface Items {
         TagKey<Item> ZAP_LOGS = item("zap_logs");
         TagKey<Item> WAXED_ZAP_LOGS = item("waxed_zap_logs");
@@ -72,6 +20,67 @@ public interface UTags {
         TagKey<Item> CLOUD_STAIRS = item("cloud_stairs");
         TagKey<Item> CLOUD_BLOCKS = item("cloud_blocks");
         TagKey<Item> CHITIN_BLOCKS = item("chitin_blocks");
+
+        TagKey<Item> FRESH_APPLES = item("fresh_apples");
+
+        TagKey<Item> FALLS_SLOWLY = item("falls_slowly");
+        TagKey<Item> PIES = item("pies");
+        TagKey<Item> CAN_CUT_PIE = item("can_cut_pie");
+
+        TagKey<Item> MAGIC_FEATHERS = item("magic_feathers");
+
+        TagKey<Item> SHADES = item("shades");
+        TagKey<Item> SPOOKED_MOB_DROPS = item("spooked_mob_drops");
+        TagKey<Item> HAS_NO_TRAITS = item("has_no_traits");
+        TagKey<Item> IS_DELIVERED_AGGRESSIVELY = item("is_delivered_aggressively");
+        TagKey<Item> CONTAINER_WITH_LOVE = item("container_with_love");
+        TagKey<Item> FLOATS_ON_CLOUDS = item("floats_on_clouds");
+        TagKey<Item> COOLS_OFF_KIRINS = item("cools_off_kirins");
+        TagKey<Item> LOOT_BUG_COMMON_DROPS = item("loot_bug_common_drops");
+        TagKey<Item> LOOT_BUG_RARE_DROPS = item("loot_bug_rare_drops");
+        TagKey<Item> LOOT_BUG_EPIC_DROPS = item("loot_bug_epic_drops");
+
+        TagKey<Item> SHELLS = item("shells");
+        TagKey<Item> SPECIAL_SHELLS = item("special_shells");
+        TagKey<Item> ROCK_STEWS = item("rock_stews");
+        TagKey<Item> BAKED_GOODS = item("baked_goods");
+
+        TagKey<Item> HIGH_QUALITY_SEA_VEGETABLES = item("food_types/high_quality_sea_vegetables");
+        TagKey<Item> LOW_QUALITY_SEA_VEGETABLES = item("food_types/low_quality_sea_vegetables");
+
+        TagKey<Item> POLEARMS = item("polearms");
+        TagKey<Item> HORSE_SHOES = item("horse_shoes");
+        TagKey<Item> APPLE_SEEDS = item("apple_seeds");
+
+        TagKey<Item> BASKETS = item("baskets");
+        TagKey<Item> BADGES = item("badges");
+        TagKey<Item> WOOL_BED_SHEETS = item("wool_bed_sheets");
+        TagKey<Item> BED_SHEETS = item("bed_sheets");
+        TagKey<Item> CLOUD_JARS = item("cloud_jars");
+
+        TagKey<Item> GROUP_FORAGING = item("groups/foraging");
+        TagKey<Item> GROUP_EARTH_PONY = item("groups/earth_pony");
+        TagKey<Item> GROUP_UNICORN = item("groups/unicorn");
+        TagKey<Item> GROUP_PEGASUS = item("groups/pegasus");
+        TagKey<Item> GROUP_BAT_PONY = item("groups/bat_pony");
+        TagKey<Item> GROUP_SEA_PONY = item("groups/sea_pony");
+        TagKey<Item> GROUP_CHANGELING = item("groups/changeling");
+
+        TagKey<Item> FORAGE_BLINDING = item("forage/blinding");
+        TagKey<Item> FORAGE_DANGEROUS = item("forage/dangerous");
+        TagKey<Item> FORAGE_FILLING = item("forage/filling");
+        TagKey<Item> FORAGE_SAFE = item("forage/safe");
+        TagKey<Item> FORAGE_NAUSEATING = item("forage/nauseating");
+        TagKey<Item> FORAGE_PRICKLY = item("forage/prickly");
+        TagKey<Item> FORAGE_GLOWING = item("forage/glowing");
+        TagKey<Item> FORAGE_RISKY = item("forage/risky");
+        TagKey<Item> FORAGE_STRENGHENING = item("forage/strenghtening");
+        TagKey<Item> FORAGE_SEVERE_NAUSEATING = item("forage/severe/nauseating");
+        TagKey<Item> FORAGE_SEVERE_PRICKLY = item("forage/severe/prickly");
+
+        private static TagKey<Item> item(String name) {
+            return TagKey.of(RegistryKeys.ITEM, Unicopia.id(name));
+        }
     }
 
     interface Blocks {
@@ -83,29 +92,58 @@ public interface UTags {
         TagKey<Block> CLOUD_STAIRS = block("cloud_stairs");
         TagKey<Block> CLOUD_BLOCKS = block("cloud_blocks");
         TagKey<Block> CHITIN_BLOCKS = block("chitin_blocks");
+
+        TagKey<Block> FRAGILE = block("fragile");
+        TagKey<Block> INTERESTING = block("interesting");
+        TagKey<Block> CATAPULT_IMMUNE = block("catapult_immune");
+        TagKey<Block> JARS = block("jars");
+
+        TagKey<Block> CRYSTAL_HEART_BASE = block("crystal_heart_base");
+        TagKey<Block> CRYSTAL_HEART_ORNAMENT = block("crystal_heart_ornament");
+        TagKey<Block> UNAFFECTED_BY_GROW_ABILITY = block("unaffected_by_grow_ability");
+        TagKey<Block> KICKS_UP_DUST = block("kicks_up_dust");
+
+        TagKey<Block> POLEARM_MINEABLE = block("mineable/polearm");
+
+        TagKey<Block> BUTTERFLIES_SPAWNABLE_ON = block("butterflies_spawn_on");
+
+        private static TagKey<Block> block(String name) {
+            return TagKey.of(RegistryKeys.BLOCK, Unicopia.id(name));
+        }
     }
 
-    static TagKey<Item> item(String name) {
-        return TagKey.of(RegistryKeys.ITEM, Unicopia.id(name));
+    interface Entities {
+        TagKey<EntityType<?>> TRANSFORMABLE = entity("transformable");
+
+        private static TagKey<EntityType<?>> entity(String name) {
+            return TagKey.of(RegistryKeys.ENTITY_TYPE, Unicopia.id(name));
+        }
     }
 
-    static TagKey<Block> block(String name) {
-        return TagKey.of(RegistryKeys.BLOCK, Unicopia.id(name));
+    interface DamageTypes {
+        TagKey<DamageType> BREAKS_SUNGLASSES = damage("breaks_sunglasses");
+        TagKey<DamageType> SPELLBOOK_IMMUNE_TO = damage("spellbook_immune_to");
+        TagKey<DamageType> FROM_ROCKS = damage("from_rocks");
+        TagKey<DamageType> FROM_HORSESHOES = damage("from_horseshoes");
+
+        private static TagKey<DamageType> damage(String name) {
+            return TagKey.of(RegistryKeys.DAMAGE_TYPE, Unicopia.id(name));
+        }
     }
 
-    static TagKey<EntityType<?>> entity(String name) {
-        return TagKey.of(RegistryKeys.ENTITY_TYPE, Unicopia.id(name));
+    interface DimensionTypes {
+        TagKey<DimensionType> HAS_NO_ATMOSPHERE = dimension("has_no_atmosphere");
+
+        private static TagKey<DimensionType> dimension(String name) {
+            return TagKey.of(RegistryKeys.DIMENSION_TYPE, new Identifier("c", name));
+        }
     }
 
-    static TagKey<StatusEffect> effect(String name) {
-        return TagKey.of(RegistryKeys.STATUS_EFFECT, Unicopia.id(name));
-    }
+    interface StatusEffects {
+        TagKey<StatusEffect> PINEAPPLE_EFFECTS = effect("pineapple_effects");
 
-    static TagKey<DamageType> damage(String name) {
-        return TagKey.of(RegistryKeys.DAMAGE_TYPE, Unicopia.id(name));
-    }
-
-    static TagKey<DimensionType> dimension(String name) {
-        return TagKey.of(RegistryKeys.DIMENSION_TYPE, new Identifier("c", name));
+        private static TagKey<StatusEffect> effect(String name) {
+            return TagKey.of(RegistryKeys.STATUS_EFFECT, Unicopia.id(name));
+        }
     }
 }
diff --git a/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyGrowAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyGrowAbility.java
index 61ab54d5..0454681e 100644
--- a/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyGrowAbility.java
+++ b/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyGrowAbility.java
@@ -10,10 +10,10 @@ import com.minelittlepony.unicopia.ability.data.Hit;
 import com.minelittlepony.unicopia.ability.data.Pos;
 import com.minelittlepony.unicopia.block.UBlocks;
 import com.minelittlepony.unicopia.entity.player.Pony;
-import com.minelittlepony.unicopia.item.TransformCropsRecipe;
-import com.minelittlepony.unicopia.item.URecipes;
 import com.minelittlepony.unicopia.particle.MagicParticleEffect;
 import com.minelittlepony.unicopia.particle.ParticleUtils;
+import com.minelittlepony.unicopia.recipe.TransformCropsRecipe;
+import com.minelittlepony.unicopia.recipe.URecipes;
 import com.minelittlepony.unicopia.server.world.BlockDestructionManager;
 import com.minelittlepony.unicopia.util.TraceHelper;
 import com.minelittlepony.unicopia.util.VecHelper;
@@ -108,7 +108,7 @@ public class EarthPonyGrowAbility implements Ability<Pos> {
             }
         }
 
-        if (w.getBlockState(pos).isIn(UTags.UNAFFECTED_BY_GROW_ABILITY)) {
+        if (w.getBlockState(pos).isIn(UTags.Blocks.UNAFFECTED_BY_GROW_ABILITY)) {
             return 0;
         }
 
diff --git a/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyStompAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyStompAbility.java
index b702400f..285266c9 100644
--- a/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyStompAbility.java
+++ b/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyStompAbility.java
@@ -162,7 +162,7 @@ public class EarthPonyStompAbility implements Ability<Hit> {
 
             ParticleUtils.spawnParticle(player.getWorld(), UParticles.GROUND_POUND, player.getX(), player.getY() - 1, player.getZ(), 0, 0, 0);
             BlockState steppingState = player.getSteppingBlockState();
-            if (steppingState.isIn(UTags.KICKS_UP_DUST)) {
+            if (steppingState.isIn(UTags.Blocks.KICKS_UP_DUST)) {
                 ParticleUtils.spawnParticle(player.getWorld(), new BlockStateParticleEffect(UParticles.DUST_CLOUD, steppingState), player.getBlockPos().down().toCenterPos(), Vec3d.ZERO);
             }
 
@@ -227,7 +227,7 @@ public class EarthPonyStompAbility implements Ability<Hit> {
             w.syncWorldEvent(WorldEvents.BLOCK_BROKEN, pos, Block.getRawIdFromState(state));
         }
 
-        if (state.isIn(UTags.KICKS_UP_DUST)) {
+        if (state.isIn(UTags.Blocks.KICKS_UP_DUST)) {
             if (w.random.nextInt(4) == 0 && w.isAir(pos.up()) && w.getFluidState(pos.up()).isEmpty()) {
                 ParticleUtils.spawnParticle(w, new BlockStateParticleEffect(UParticles.DUST_CLOUD, state), pos.up().toCenterPos(), VecHelper.supply(() -> w.random.nextTriangular(0, 0.1F)));
             }
diff --git a/src/main/java/com/minelittlepony/unicopia/ability/ScreechAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/ScreechAbility.java
index ac244ea0..60319ba1 100644
--- a/src/main/java/com/minelittlepony/unicopia/ability/ScreechAbility.java
+++ b/src/main/java/com/minelittlepony/unicopia/ability/ScreechAbility.java
@@ -110,7 +110,7 @@ public class ScreechAbility implements Ability<Numeric> {
 
 
             if (living.getWorld().random.nextInt(MOB_SPOOK_PROBABILITY) == 0) {
-                RegistryUtils.pickRandom(living.getWorld(), UTags.SPOOKED_MOB_DROPS).ifPresent(drop -> {
+                RegistryUtils.pickRandom(living.getWorld(), UTags.Items.SPOOKED_MOB_DROPS).ifPresent(drop -> {
                     living.dropStack(drop.getDefaultStack());
                     living.playSound(USounds.Vanilla.ENTITY_ITEM_PICKUP, 1, 0.1F);
                     UCriteria.SPOOK_MOB.trigger(player.asEntity());
diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/RainboomAbilitySpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/RainboomAbilitySpell.java
index a3339212..13445ea2 100644
--- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/RainboomAbilitySpell.java
+++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/RainboomAbilitySpell.java
@@ -64,7 +64,7 @@ public class RainboomAbilitySpell extends AbstractSpell {
         });
         EFFECT_RANGE.translate(source.getOrigin()).getBlockPositions().forEach(pos -> {
             BlockState state = source.asWorld().getBlockState(pos);
-            if (state.isIn(UTags.FRAGILE) && source.canModifyAt(pos, ModificationType.PHYSICAL)) {
+            if (state.isIn(UTags.Blocks.FRAGILE) && source.canModifyAt(pos, ModificationType.PHYSICAL)) {
                 source.asWorld().breakBlock(pos, true);
             }
         });
diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/crafting/SpellCraftingRecipe.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/crafting/SpellCraftingRecipe.java
index 99528460..3badf6d4 100644
--- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/crafting/SpellCraftingRecipe.java
+++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/crafting/SpellCraftingRecipe.java
@@ -9,7 +9,7 @@ import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
 import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
 import com.minelittlepony.unicopia.container.inventory.SpellbookInventory;
 import com.minelittlepony.unicopia.item.EnchantableItem;
-import com.minelittlepony.unicopia.item.URecipes;
+import com.minelittlepony.unicopia.recipe.URecipes;
 import com.minelittlepony.unicopia.util.InventoryUtil;
 import com.mojang.datafixers.util.Pair;
 
diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/crafting/SpellDuplicatingRecipe.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/crafting/SpellDuplicatingRecipe.java
index 0b29c917..8d228a2c 100644
--- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/crafting/SpellDuplicatingRecipe.java
+++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/crafting/SpellDuplicatingRecipe.java
@@ -4,6 +4,7 @@ import com.google.gson.JsonObject;
 import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
 import com.minelittlepony.unicopia.container.inventory.SpellbookInventory;
 import com.minelittlepony.unicopia.item.*;
+import com.minelittlepony.unicopia.recipe.URecipes;
 import com.minelittlepony.unicopia.util.InventoryUtil;
 
 import net.minecraft.item.ItemStack;
diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/crafting/SpellEnhancingRecipe.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/crafting/SpellEnhancingRecipe.java
index 7aebd7e5..d63a2e86 100644
--- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/crafting/SpellEnhancingRecipe.java
+++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/crafting/SpellEnhancingRecipe.java
@@ -4,6 +4,7 @@ import com.google.gson.JsonObject;
 import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
 import com.minelittlepony.unicopia.container.inventory.SpellbookInventory;
 import com.minelittlepony.unicopia.item.*;
+import com.minelittlepony.unicopia.recipe.URecipes;
 
 import net.minecraft.item.ItemStack;
 import net.minecraft.network.PacketByteBuf;
diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/crafting/SpellShapedCraftingRecipe.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/crafting/SpellShapedCraftingRecipe.java
index cc0dcc0f..e07e1ab3 100644
--- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/crafting/SpellShapedCraftingRecipe.java
+++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/crafting/SpellShapedCraftingRecipe.java
@@ -2,7 +2,7 @@ package com.minelittlepony.unicopia.ability.magic.spell.crafting;
 
 import com.google.gson.JsonObject;
 import com.minelittlepony.unicopia.item.EnchantableItem;
-import com.minelittlepony.unicopia.item.URecipes;
+import com.minelittlepony.unicopia.recipe.URecipes;
 import com.minelittlepony.unicopia.util.InventoryUtil;
 
 import net.minecraft.inventory.RecipeInputInventory;
diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/crafting/SpellbookRecipe.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/crafting/SpellbookRecipe.java
index 89043ce8..49b781aa 100644
--- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/crafting/SpellbookRecipe.java
+++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/crafting/SpellbookRecipe.java
@@ -5,7 +5,7 @@ import java.util.List;
 import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
 import com.minelittlepony.unicopia.container.inventory.SpellbookInventory;
 import com.minelittlepony.unicopia.item.UItems;
-import com.minelittlepony.unicopia.item.URecipes;
+import com.minelittlepony.unicopia.recipe.URecipes;
 
 import net.minecraft.item.ItemStack;
 import net.minecraft.recipe.Recipe;
diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/CatapultSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/CatapultSpell.java
index ec5cbf3e..ce440570 100644
--- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/CatapultSpell.java
+++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/CatapultSpell.java
@@ -86,7 +86,7 @@ public class CatapultSpell extends AbstractSpell implements ProjectileDelegate.B
         }
 
         BlockState state = world.getBlockState(bpos);
-        if (state.isIn(UTags.CATAPULT_IMMUNE)) {
+        if (state.isIn(UTags.Blocks.CATAPULT_IMMUNE)) {
             return;
         }
 
diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/TransformationSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/TransformationSpell.java
index e26152f0..4d507d1d 100644
--- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/TransformationSpell.java
+++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/TransformationSpell.java
@@ -66,7 +66,7 @@ public class TransformationSpell extends AbstractSpell implements ProjectileDele
 
     @SuppressWarnings("unchecked")
     private <T extends MobEntity> Optional<EntityType<T>> pickType(EntityType<?> except, World world) {
-        Set<EntityType<?>> options = RegistryUtils.valuesForTag(world, UTags.TRANSFORMABLE_ENTITIES).collect(Collectors.toSet());
+        Set<EntityType<?>> options = RegistryUtils.valuesForTag(world, UTags.Entities.TRANSFORMABLE).collect(Collectors.toSet());
         if (except.getSpawnGroup() == SpawnGroup.MONSTER) {
             options.removeIf(t -> t.getSpawnGroup() == SpawnGroup.MONSTER);
         } else {
diff --git a/src/main/java/com/minelittlepony/unicopia/block/EnchantedFruitBlock.java b/src/main/java/com/minelittlepony/unicopia/block/EnchantedFruitBlock.java
index c6af9166..fc72ef95 100644
--- a/src/main/java/com/minelittlepony/unicopia/block/EnchantedFruitBlock.java
+++ b/src/main/java/com/minelittlepony/unicopia/block/EnchantedFruitBlock.java
@@ -8,7 +8,7 @@ import net.minecraft.util.math.Direction;
 import net.minecraft.util.shape.VoxelShape;
 
 public class EnchantedFruitBlock extends FruitBlock {
-    static final BooleanProperty ENCHANTED = BooleanProperty.of("enchanted");
+    public static final BooleanProperty ENCHANTED = BooleanProperty.of("enchanted");
 
     public EnchantedFruitBlock(Settings settings, Direction attachmentFace, Block stem, VoxelShape shape) {
         super(settings, attachmentFace, stem, shape);
diff --git a/src/main/java/com/minelittlepony/unicopia/block/ItemJarBlock.java b/src/main/java/com/minelittlepony/unicopia/block/ItemJarBlock.java
index 68c9b9ba..ef84849d 100644
--- a/src/main/java/com/minelittlepony/unicopia/block/ItemJarBlock.java
+++ b/src/main/java/com/minelittlepony/unicopia/block/ItemJarBlock.java
@@ -1,9 +1,14 @@
 package com.minelittlepony.unicopia.block;
 
-import java.util.ArrayList;
-import java.util.List;
-import java.util.stream.IntStream;
+import org.jetbrains.annotations.Nullable;
 
+import com.minelittlepony.unicopia.block.jar.EntityJarContents;
+import com.minelittlepony.unicopia.block.jar.FluidOnlyJarContents;
+import com.minelittlepony.unicopia.block.jar.ItemsJarContents;
+import com.minelittlepony.unicopia.block.jar.FakeFluidJarContents;
+
+import net.fabricmc.fabric.api.transfer.v1.fluid.FluidConstants;
+import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant;
 import net.minecraft.block.BlockEntityProvider;
 import net.minecraft.block.BlockRenderType;
 import net.minecraft.block.BlockState;
@@ -12,11 +17,18 @@ import net.minecraft.block.entity.BlockEntity;
 import net.minecraft.entity.player.PlayerEntity;
 import net.minecraft.inventory.SidedInventory;
 import net.minecraft.item.ItemStack;
+import net.minecraft.item.ItemUsage;
+import net.minecraft.nbt.NbtCompound;
+import net.minecraft.nbt.NbtElement;
+import net.minecraft.network.listener.ClientPlayPacketListener;
+import net.minecraft.network.packet.Packet;
+import net.minecraft.network.packet.s2c.play.BlockEntityUpdateS2CPacket;
+import net.minecraft.server.world.ServerWorld;
 import net.minecraft.util.ActionResult;
 import net.minecraft.util.Hand;
+import net.minecraft.util.TypedActionResult;
 import net.minecraft.util.hit.BlockHitResult;
 import net.minecraft.util.math.BlockPos;
-import net.minecraft.util.math.Direction;
 import net.minecraft.world.World;
 import net.minecraft.world.WorldAccess;
 
@@ -36,14 +48,7 @@ public class ItemJarBlock extends JarBlock implements BlockEntityProvider, Inven
         if (hand == Hand.OFF_HAND) {
             return ActionResult.PASS;
         }
-        return world.getBlockEntity(pos, UBlockEntities.ITEM_JAR).map(data -> {
-            ItemStack stack = player.getStackInHand(hand);
-            if (stack.isEmpty()) {
-                return data.removeItem(world, pos);
-            }
-
-            return data.insertItem(world, pos, player.isCreative() ? stack.copyWithCount(1) : stack.split(1));
-        }).orElse(ActionResult.PASS);
+        return world.getBlockEntity(pos, UBlockEntities.ITEM_JAR).map(data -> data.interact(player, hand)).orElse(ActionResult.PASS);
     }
 
     @Deprecated
@@ -51,9 +56,7 @@ public class ItemJarBlock extends JarBlock implements BlockEntityProvider, Inven
     public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean moved) {
         if (!moved && !state.isOf(newState.getBlock())) {
             world.getBlockEntity(pos, UBlockEntities.ITEM_JAR).ifPresent(data -> {
-                data.getStacks().forEach(stack -> {
-                    dropStack(world, pos, stack);
-                });
+                data.getContents().onDestroyed();
             });
         }
         super.onStateReplaced(state, world, pos, newState, moved);
@@ -66,7 +69,10 @@ public class ItemJarBlock extends JarBlock implements BlockEntityProvider, Inven
 
     @Override
     public int getComparatorOutput(BlockState state, World world, BlockPos pos) {
-        return world.getBlockEntity(pos, UBlockEntities.ITEM_JAR).map(data -> Math.min(16, data.getStacks().size())).orElse(0);
+        return world.getBlockEntity(pos, UBlockEntities.ITEM_JAR)
+                .map(TileData::getItems)
+                .map(data -> Math.min(16, data.stacks().size()))
+                .orElse(0);
     }
 
     @Deprecated
@@ -82,135 +88,113 @@ public class ItemJarBlock extends JarBlock implements BlockEntityProvider, Inven
         return new TileData(pos, state);
     }
 
-
+    @Nullable
     @Override
     public SidedInventory getInventory(BlockState state, WorldAccess world, BlockPos pos) {
-        return world.getBlockEntity(pos, UBlockEntities.ITEM_JAR).orElse(null);
+        return world.getBlockEntity(pos, UBlockEntities.ITEM_JAR).map(TileData::getItems).orElse(null);
     }
 
-    public static class TileData extends BlockEntity implements SidedInventory {
-        private static final int[] SLOTS = IntStream.range(0, 16).toArray();
-        private final List<ItemStack> stacks = new ArrayList<>();
+    public static class TileData extends BlockEntity {
+
+        private JarContents contents = new ItemsJarContents(this);
 
         public TileData(BlockPos pos, BlockState state) {
             super(UBlockEntities.ITEM_JAR, pos, state);
         }
 
-        public ActionResult insertItem(World world, BlockPos pos, ItemStack stack) {
-            if (stacks.size() >= size()) {
-                return ActionResult.FAIL;
-            }
-            stacks.add(stack);
-            markDirty();
-
-            return ActionResult.SUCCESS;
+        public ActionResult interact(PlayerEntity player, Hand hand) {
+            TypedActionResult<JarContents> result = contents.interact(player, hand);
+            contents = result.getValue();
+            return result.getResult();
         }
 
-        public ActionResult removeItem(World world, BlockPos pos) {
-            if (stacks.isEmpty()) {
-                return ActionResult.FAIL;
-            }
-            dropStack(world, pos, stacks.remove(0));
-            markDirty();
-            return ActionResult.SUCCESS;
+        public JarContents getContents() {
+            return contents;
         }
 
-        public List<ItemStack> getStacks() {
-            return stacks;
+        @Nullable
+        public ItemsJarContents getItems() {
+            return getContents() instanceof ItemsJarContents c ? c : null;
+        }
+
+        @Nullable
+        public EntityJarContents getEntity() {
+            return getContents() instanceof EntityJarContents c ? c : null;
+        }
+
+        @Nullable
+        public FluidJarContents getFluid() {
+            return getContents() instanceof FluidJarContents c ? c : null;
+        }
+
+        @Nullable
+        public FakeFluidJarContents getFakeFluid() {
+            return getContents() instanceof FakeFluidJarContents c ? c : null;
         }
 
         @Override
-        public int size() {
-            return 15;
+        public Packet<ClientPlayPacketListener> toUpdatePacket() {
+            return BlockEntityUpdateS2CPacket.create(this);
         }
 
         @Override
-        public boolean isEmpty() {
-            return stacks.isEmpty();
+        public NbtCompound toInitialChunkDataNbt() {
+            return createNbt();
         }
 
         @Override
-        public ItemStack getStack(int slot) {
-            return slot < 0 || slot >= stacks.size() ? ItemStack.EMPTY : stacks.get(slot);
-        }
-
-        @Override
-        public ItemStack removeStack(int slot, int amount) {
-            if (slot < 0 || slot >= stacks.size()) {
-                try {
-                    ItemStack stack = stacks.get(slot);
-                    ItemStack removed = stack.split(1);
-                    if (stack.isEmpty()) {
-                        stacks.remove(slot);
-                    }
-                    return removed;
-                } finally {
-                    markDirty();
-                }
-            }
-            return ItemStack.EMPTY;
-        }
-
-        @Override
-        public ItemStack removeStack(int slot) {
-            if (slot < 0 || slot >= stacks.size()) {
-                try {
-                    return stacks.remove(slot);
-                } finally {
-                    markDirty();
-                }
-            }
-            return ItemStack.EMPTY;
-        }
-
-        @Override
-        public void setStack(int slot, ItemStack stack) {
-            if (slot >= stacks.size()) {
-                if (stacks.size() >= size()) {
-                    dropStack(getWorld(), getPos(), stack);
-                } else {
-                    stacks.add(stack);
-                }
-            } else {
-                ItemStack existing = stacks.get(slot);
-                if (!ItemStack.canCombine(existing, stack)) {
-                    dropStack(getWorld(), getPos(), stack);
-                } else {
-                    existing.setCount(existing.getCount() + stack.split(Math.max(0, existing.getMaxCount() - existing.getCount())).getCount());
-                    if (!stack.isEmpty()) {
-                        dropStack(getWorld(), getPos(), stack);
-                    }
-                }
+        public void markDirty() {
+            super.markDirty();
+            if (getWorld() instanceof ServerWorld sw) {
+                sw.getChunkManager().markForUpdate(getPos());
             }
         }
 
         @Override
-        public boolean canPlayerUse(PlayerEntity player) {
-            return false;
+        public void readNbt(NbtCompound nbt) {
+            if (nbt.contains("items", NbtElement.COMPOUND_TYPE)) {
+                contents = new ItemsJarContents(this, nbt.getCompound("items"));
+            } else if (nbt.contains("entity", NbtElement.COMPOUND_TYPE)) {
+                contents = new EntityJarContents(this, nbt.getCompound("entity"));
+            } else if (nbt.contains("fluid", NbtElement.COMPOUND_TYPE)) {
+                contents = new FluidOnlyJarContents(this, nbt.getCompound("fluid"));
+            } else if (nbt.contains("fakeFluid", NbtElement.COMPOUND_TYPE)) {
+                contents = new FakeFluidJarContents(this, nbt.getCompound("fakeFluid"));
+            }
         }
 
         @Override
-        public void clear() {
-            stacks.clear();
-            markDirty();
+        protected void writeNbt(NbtCompound nbt) {
+            var items = getItems();
+            if (items != null) {
+                nbt.put("items", items.toNBT(new NbtCompound()));
+            } else if (getEntity() != null) {
+                nbt.put("entity", getEntity().toNBT(new NbtCompound()));
+            } else if (getFluid() != null) {
+                nbt.put("fluid", getFluid().toNBT(new NbtCompound()));
+            } else if (getFakeFluid() != null) {
+                nbt.put("fakeFluid", getFakeFluid().toNBT(new NbtCompound()));
+            }
         }
+    }
 
-        @Override
-        public int[] getAvailableSlots(Direction side) {
-            return SLOTS;
+    public interface JarContents {
+        TypedActionResult<JarContents> interact(PlayerEntity player, Hand hand);
+
+        void onDestroyed();
+
+        NbtCompound toNBT(NbtCompound compound);
+
+        default void consumeAndSwap(PlayerEntity player, Hand hand, ItemStack output) {
+            player.setStackInHand(hand, ItemUsage.exchangeStack(player.getStackInHand(hand), player, output.copy()));
         }
+    }
 
-        @Override
-        public boolean canInsert(int slot, ItemStack stack, Direction dir) {
-            return (slot >= 0 && slot < size()) && (slot >= stacks.size() || (
-                    ItemStack.canCombine(stacks.get(slot), stack)
-                    && (stacks.get(slot).getCount() + stack.getCount()) <= Math.min(stacks.get(slot).getMaxCount(), stack.getMaxCount())
-            ));
-        }
+    public interface FluidJarContents extends JarContents {
+        FluidVariant fluid();
 
-        @Override
-        public boolean canExtract(int slot, ItemStack stack, Direction dir) {
-            return true;
+        default long amount() {
+            return FluidConstants.BUCKET;
         }
     }
 }
diff --git a/src/main/java/com/minelittlepony/unicopia/block/JarBlock.java b/src/main/java/com/minelittlepony/unicopia/block/JarBlock.java
index 80f24c7e..2bf5777b 100644
--- a/src/main/java/com/minelittlepony/unicopia/block/JarBlock.java
+++ b/src/main/java/com/minelittlepony/unicopia/block/JarBlock.java
@@ -11,10 +11,17 @@ import net.minecraft.block.AbstractGlassBlock;
 import net.minecraft.block.Block;
 import net.minecraft.block.BlockState;
 import net.minecraft.block.ShapeContext;
+import net.minecraft.block.Waterloggable;
 import net.minecraft.block.entity.BlockEntity;
 import net.minecraft.enchantment.EnchantmentHelper;
 import net.minecraft.entity.player.PlayerEntity;
+import net.minecraft.fluid.FluidState;
+import net.minecraft.fluid.Fluids;
+import net.minecraft.item.ItemPlacementContext;
 import net.minecraft.item.ItemStack;
+import net.minecraft.state.StateManager;
+import net.minecraft.state.property.BooleanProperty;
+import net.minecraft.state.property.Properties;
 import net.minecraft.util.math.BlockPos;
 import net.minecraft.util.math.Direction;
 import net.minecraft.util.math.random.Random;
@@ -22,17 +29,25 @@ import net.minecraft.util.shape.VoxelShape;
 import net.minecraft.util.shape.VoxelShapes;
 import net.minecraft.world.BlockView;
 import net.minecraft.world.World;
+import net.minecraft.world.WorldAccess;
 import net.minecraft.world.explosion.Explosion;
 
-public class JarBlock extends AbstractGlassBlock {
+public class JarBlock extends AbstractGlassBlock implements Waterloggable {
     private static final VoxelShape SHAPE = VoxelShapes.union(
             Block.createCuboidShape(4, 0, 4, 12, 12, 12),
             Block.createCuboidShape(6, 12, 6, 10, 16, 10),
             Block.createCuboidShape(5, 13, 5, 11, 14, 11)
     );
+    private static final BooleanProperty WATERLOGGED = Properties.WATERLOGGED;
 
     public JarBlock(Settings settings) {
         super(settings);
+        setDefaultState(getDefaultState().with(WATERLOGGED, false));
+    }
+
+    @Override
+    protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
+        builder.add(WATERLOGGED);
     }
 
     @Override
@@ -40,9 +55,26 @@ public class JarBlock extends AbstractGlassBlock {
         return SHAPE;
     }
 
+    @Deprecated
     @Override
-    public boolean isSideInvisible(BlockState state, BlockState stateFrom, Direction direction) {
-        return super.isSideInvisible(state, stateFrom, direction);
+    public BlockState getStateForNeighborUpdate(BlockState state, Direction direction, BlockState neighborState, WorldAccess world, BlockPos pos, BlockPos neighborPos) {
+        if (state.get(WATERLOGGED)) {
+            world.scheduleFluidTick(pos, Fluids.WATER, Fluids.WATER.getTickRate(world));
+        }
+
+        return super.getStateForNeighborUpdate(state, direction, neighborState, world, pos, neighborPos);
+    }
+
+    @Nullable
+    @Override
+    public BlockState getPlacementState(ItemPlacementContext ctx) {
+        return getDefaultState().with(WATERLOGGED, ctx.getWorld().getFluidState(ctx.getBlockPos()).getFluid() == Fluids.WATER);
+    }
+
+    @Deprecated
+    @Override
+    public FluidState getFluidState(BlockState state) {
+        return state.get(WATERLOGGED) ? Fluids.WATER.getStill(false) : super.getFluidState(state);
     }
 
     @Override
diff --git a/src/main/java/com/minelittlepony/unicopia/block/PieBlock.java b/src/main/java/com/minelittlepony/unicopia/block/PieBlock.java
index b7c2be5b..33c85df0 100644
--- a/src/main/java/com/minelittlepony/unicopia/block/PieBlock.java
+++ b/src/main/java/com/minelittlepony/unicopia/block/PieBlock.java
@@ -71,7 +71,7 @@ public class PieBlock extends Block implements Waterloggable {
 
         if (world.isClient) {
 
-            if (itemStack.isIn(UTags.CAN_CUT_PIE)) {
+            if (itemStack.isIn(UTags.Items.CAN_CUT_PIE)) {
                 return ActionResult.SUCCESS;
             }
 
@@ -84,7 +84,7 @@ public class PieBlock extends Block implements Waterloggable {
             }
         }
 
-        if (itemStack.isIn(UTags.CAN_CUT_PIE)) {
+        if (itemStack.isIn(UTags.Items.CAN_CUT_PIE)) {
             SoundEmitter.playSoundAt(player, USounds.BLOCK_PIE_SLICE, SoundCategory.NEUTRAL, 1, 1);
             removeSlice(world, pos, state, player);
             itemStack.damage(1, player, p -> p.sendToolBreakStatus(hand));
diff --git a/src/main/java/com/minelittlepony/unicopia/block/PineappleCropBlock.java b/src/main/java/com/minelittlepony/unicopia/block/PineappleCropBlock.java
index 2530a8d9..431597c5 100644
--- a/src/main/java/com/minelittlepony/unicopia/block/PineappleCropBlock.java
+++ b/src/main/java/com/minelittlepony/unicopia/block/PineappleCropBlock.java
@@ -41,7 +41,7 @@ public class PineappleCropBlock extends CropBlock {
     }
 
     @Override
-    protected boolean canPlantOnTop(BlockState floor, BlockView world, BlockPos pos) {
+    public boolean canPlantOnTop(BlockState floor, BlockView world, BlockPos pos) {
         return floor.isOf(this) || super.canPlantOnTop(floor, world, pos);
     }
 
diff --git a/src/main/java/com/minelittlepony/unicopia/block/SegmentedCropBlock.java b/src/main/java/com/minelittlepony/unicopia/block/SegmentedCropBlock.java
index 25f3539c..1f16f7c3 100644
--- a/src/main/java/com/minelittlepony/unicopia/block/SegmentedCropBlock.java
+++ b/src/main/java/com/minelittlepony/unicopia/block/SegmentedCropBlock.java
@@ -97,7 +97,7 @@ public class SegmentedCropBlock extends CropBlock implements SegmentedBlock {
     }
 
     @Override
-    protected boolean canPlantOnTop(BlockState state, BlockView view, BlockPos pos) {
+    public boolean canPlantOnTop(BlockState state, BlockView view, BlockPos pos) {
         return (state.getBlock() instanceof SegmentedCropBlock o && o.canSupportBlock(this, state, view, pos)) || super.canPlantOnTop(state, view, pos);
     }
 
@@ -204,4 +204,8 @@ public class SegmentedCropBlock extends CropBlock implements SegmentedBlock {
         return state.getBlock() == this || (nextSegmentSupplier != null && nextSegmentSupplier.get().isNext(state));
     }
 
+    @Nullable
+    public SegmentedCropBlock getNext() {
+        return nextSegmentSupplier == null ? null : nextSegmentSupplier.get();
+    }
 }
diff --git a/src/main/java/com/minelittlepony/unicopia/block/SlimePustuleBlock.java b/src/main/java/com/minelittlepony/unicopia/block/SlimePustuleBlock.java
index 4d7d58e8..72b1a814 100644
--- a/src/main/java/com/minelittlepony/unicopia/block/SlimePustuleBlock.java
+++ b/src/main/java/com/minelittlepony/unicopia/block/SlimePustuleBlock.java
@@ -199,7 +199,7 @@ public class SlimePustuleBlock extends Block {
     public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean moved) {
         super.onStateReplaced(state, world, pos, newState, moved);
         if (state.isOf(this) && newState.isOf(this) && state.get(POWERED) != newState.get(POWERED)) {
-            world.updateNeighbor(pos.up(), this, pos);
+            world.updateNeighborsAlways(pos.up(), this);
         }
     }
 
diff --git a/src/main/java/com/minelittlepony/unicopia/block/jar/EntityJarContents.java b/src/main/java/com/minelittlepony/unicopia/block/jar/EntityJarContents.java
new file mode 100644
index 00000000..967807c1
--- /dev/null
+++ b/src/main/java/com/minelittlepony/unicopia/block/jar/EntityJarContents.java
@@ -0,0 +1,80 @@
+package com.minelittlepony.unicopia.block.jar;
+
+import java.util.function.Supplier;
+
+import org.jetbrains.annotations.Nullable;
+
+import com.google.common.base.Suppliers;
+import com.minelittlepony.unicopia.block.ItemJarBlock.FluidJarContents;
+import com.minelittlepony.unicopia.block.ItemJarBlock.JarContents;
+import com.minelittlepony.unicopia.block.ItemJarBlock.TileData;
+
+import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant;
+import net.minecraft.block.Blocks;
+import net.minecraft.entity.Bucketable;
+import net.minecraft.entity.Entity;
+import net.minecraft.entity.EntityType;
+import net.minecraft.entity.player.PlayerEntity;
+import net.minecraft.fluid.Fluids;
+import net.minecraft.item.ItemStack;
+import net.minecraft.item.Items;
+import net.minecraft.nbt.NbtCompound;
+import net.minecraft.registry.Registries;
+import net.minecraft.util.Hand;
+import net.minecraft.util.Identifier;
+import net.minecraft.util.TypedActionResult;
+
+public record EntityJarContents (
+        TileData tile,
+        @Nullable EntityType<?> entityType,
+        Supplier<@Nullable Entity> entity
+) implements FluidJarContents {
+    public EntityJarContents(TileData tile, NbtCompound compound) {
+        this(tile, Registries.ENTITY_TYPE.getOrEmpty(Identifier.tryParse(compound.getString("entity"))).orElse(null));
+    }
+
+    public EntityJarContents(TileData tile) {
+        this(tile, (EntityType<?>)null);
+    }
+
+    public EntityJarContents(TileData tile, EntityType<?> entityType) {
+        this(tile, entityType, Suppliers.memoize(() -> {
+            return entityType == null ? null : entityType.create(tile.getWorld());
+        }));
+    }
+
+    @Override
+    public TypedActionResult<JarContents> interact(PlayerEntity player, Hand hand) {
+        ItemStack stack = player.getStackInHand(hand);
+        if (stack.isOf(Items.BUCKET)) {
+            if (entity().get() instanceof Bucketable bucketable) {
+                consumeAndSwap(player, hand, bucketable.getBucketItem());
+                player.playSound(bucketable.getBucketFillSound(), 1, 1);
+            }
+            tile.markDirty();
+            return TypedActionResult.success(new ItemsJarContents(tile));
+        }
+        return TypedActionResult.pass(this);
+    }
+
+    @Override
+    public void onDestroyed() {
+        tile.getWorld().setBlockState(tile.getPos(), Blocks.WATER.getDefaultState());
+        Entity entity = entity().get();
+        if (entity != null) {
+            entity.refreshPositionAfterTeleport(tile.getPos().toCenterPos());
+            tile.getWorld().spawnEntity(entity);
+        }
+    }
+
+    @Override
+    public NbtCompound toNBT(NbtCompound compound) {
+        compound.putString("entity", EntityType.getId(entityType).toString());
+        return compound;
+    }
+
+    @Override
+    public FluidVariant fluid() {
+        return FluidVariant.of(Fluids.WATER);
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/minelittlepony/unicopia/block/jar/FakeFluidJarContents.java b/src/main/java/com/minelittlepony/unicopia/block/jar/FakeFluidJarContents.java
new file mode 100644
index 00000000..e49d648c
--- /dev/null
+++ b/src/main/java/com/minelittlepony/unicopia/block/jar/FakeFluidJarContents.java
@@ -0,0 +1,79 @@
+package com.minelittlepony.unicopia.block.jar;
+
+import java.util.Optional;
+
+import com.minelittlepony.unicopia.USounds;
+import com.minelittlepony.unicopia.block.ItemJarBlock.JarContents;
+import com.minelittlepony.unicopia.block.ItemJarBlock.TileData;
+import com.minelittlepony.unicopia.util.FluidHelper;
+
+import net.fabricmc.fabric.api.transfer.v1.fluid.FluidConstants;
+import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant;
+import net.minecraft.entity.player.PlayerEntity;
+import net.minecraft.fluid.Fluid;
+import net.minecraft.item.Item;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NbtCompound;
+import net.minecraft.registry.Registries;
+import net.minecraft.util.Hand;
+import net.minecraft.util.Identifier;
+import net.minecraft.util.TypedActionResult;
+
+public record FakeFluidJarContents (
+        TileData tile,
+        String fluid,
+        int color,
+        Item empty,
+        Item filled
+) implements JarContents {
+    public FakeFluidJarContents(TileData tile, NbtCompound compound) {
+        this(tile, compound.getString("fluid"), compound.getInt("color"),
+                Registries.ITEM.get(new Identifier(compound.getString("empty"))),
+                Registries.ITEM.get(new Identifier(compound.getString("filled"))));
+    }
+
+    @Override
+    public TypedActionResult<JarContents> interact(PlayerEntity player, Hand hand) {
+        ItemStack stack = player.getStackInHand(hand);
+
+        tile.markDirty();
+        return getRealFluid().map(FluidVariant::of).<TypedActionResult<JarContents>>map(fluid -> {
+            long remainder = FluidHelper.deposit(stack, player, hand, fluid, FluidConstants.BUCKET);
+            fluid.getFluid().getBucketFillSound().ifPresent(sound -> player.playSound(sound, 1, 1));
+            if (remainder > 0) {
+                return TypedActionResult.success(new FluidOnlyJarContents(tile, remainder, fluid));
+            }
+            return TypedActionResult.success(new ItemsJarContents(tile));
+        }).orElseGet(() -> {
+            if (!stack.isOf(empty)) {
+                return TypedActionResult.pass(this);
+            }
+            consumeAndSwap(player, hand, filled.getDefaultStack());
+            player.playSound("powder_snow".equalsIgnoreCase(fluid) ? USounds.Vanilla.ITEM_BUCKET_FILL_POWDER_SNOW : USounds.Vanilla.ITEM_BUCKET_FILL, 1, 1);
+            return TypedActionResult.success(new ItemsJarContents(tile));
+        });
+    }
+
+    @Override
+    public void onDestroyed() {
+        getRealFluid().ifPresent(fluid -> {
+            tile.getWorld().setBlockState(tile.getPos(), FluidHelper.getFullFluidState(FluidVariant.of(fluid)).getBlockState());
+        });
+    }
+
+    @Override
+    public NbtCompound toNBT(NbtCompound compound) {
+        compound.putString("fluid", fluid);
+        compound.putInt("color", color);
+        compound.putString("empty", Registries.ITEM.getId(empty).toString());
+        compound.putString("filled", Registries.ITEM.getId(filled).toString());
+        return compound;
+    }
+
+    private Optional<Fluid> getRealFluid() {
+        return Registries.FLUID.getIds().stream()
+                .filter(id -> id.getPath().equalsIgnoreCase(fluid))
+                .findFirst()
+                .map(Registries.FLUID::get);
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/minelittlepony/unicopia/block/jar/FluidOnlyJarContents.java b/src/main/java/com/minelittlepony/unicopia/block/jar/FluidOnlyJarContents.java
new file mode 100644
index 00000000..0cdcab4b
--- /dev/null
+++ b/src/main/java/com/minelittlepony/unicopia/block/jar/FluidOnlyJarContents.java
@@ -0,0 +1,55 @@
+package com.minelittlepony.unicopia.block.jar;
+
+import com.minelittlepony.unicopia.block.ItemJarBlock.FluidJarContents;
+import com.minelittlepony.unicopia.block.ItemJarBlock.JarContents;
+import com.minelittlepony.unicopia.block.ItemJarBlock.TileData;
+import com.minelittlepony.unicopia.util.FluidHelper;
+
+import net.fabricmc.fabric.api.transfer.v1.fluid.FluidConstants;
+import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant;
+import net.minecraft.entity.player.PlayerEntity;
+import net.minecraft.item.ItemStack;
+import net.minecraft.item.Items;
+import net.minecraft.nbt.NbtCompound;
+import net.minecraft.util.Hand;
+import net.minecraft.util.TypedActionResult;
+
+public record FluidOnlyJarContents (
+        TileData tile,
+        long amount,
+        FluidVariant fluid
+) implements FluidJarContents {
+
+    public FluidOnlyJarContents(TileData tile, NbtCompound compound) {
+        this(tile, compound.getLong("amount"), FluidVariant.fromNbt(compound.getCompound("fluid")));
+    }
+
+    @Override
+    public TypedActionResult<JarContents> interact(PlayerEntity player, Hand hand) {
+        ItemStack stack = player.getStackInHand(hand);
+        if (stack.isOf(Items.BUCKET)) {
+            long remainder = FluidHelper.deposit(stack, player, hand, fluid, amount);
+            tile.markDirty();
+            fluid.getFluid().getBucketFillSound().ifPresent(sound -> player.playSound(sound, 1, 1));
+            if (remainder > 0) {
+                return TypedActionResult.success(new FluidOnlyJarContents(tile, remainder, fluid));
+            }
+            return TypedActionResult.success(new ItemsJarContents(tile));
+        }
+        return TypedActionResult.pass(this);
+    }
+
+    @Override
+    public void onDestroyed() {
+        if (amount >= FluidConstants.BUCKET) {
+            tile.getWorld().setBlockState(tile.getPos(), FluidHelper.getFullFluidState(fluid).getBlockState());
+        }
+    }
+
+    @Override
+    public NbtCompound toNBT(NbtCompound compound) {
+        compound.put("fluid", fluid.toNbt());
+        compound.putLong("amount", amount);
+        return compound;
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/minelittlepony/unicopia/block/jar/ItemsJarContents.java b/src/main/java/com/minelittlepony/unicopia/block/jar/ItemsJarContents.java
new file mode 100644
index 00000000..a406c3dd
--- /dev/null
+++ b/src/main/java/com/minelittlepony/unicopia/block/jar/ItemsJarContents.java
@@ -0,0 +1,208 @@
+package com.minelittlepony.unicopia.block.jar;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+import com.minelittlepony.unicopia.USounds;
+import com.minelittlepony.unicopia.block.ItemJarBlock.JarContents;
+import com.minelittlepony.unicopia.block.ItemJarBlock.TileData;
+import com.minelittlepony.unicopia.item.UItems;
+import com.minelittlepony.unicopia.mixin.MixinEntityBucketItem;
+import com.minelittlepony.unicopia.util.FluidHelper;
+import com.minelittlepony.unicopia.util.NbtSerialisable;
+
+import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant;
+import net.minecraft.block.Block;
+import net.minecraft.entity.player.PlayerEntity;
+import net.minecraft.inventory.SidedInventory;
+import net.minecraft.item.ItemStack;
+import net.minecraft.item.Items;
+import net.minecraft.nbt.NbtCompound;
+import net.minecraft.nbt.NbtElement;
+import net.minecraft.util.Hand;
+import net.minecraft.util.Pair;
+import net.minecraft.util.TypedActionResult;
+import net.minecraft.util.math.Direction;
+
+public record ItemsJarContents (
+        TileData tile,
+        List<ItemStack> stacks
+    ) implements JarContents, SidedInventory {
+    private static final int[] SLOTS = IntStream.range(0, 16).toArray();
+
+    public ItemsJarContents(TileData tile) {
+        this(tile, new ArrayList<>());
+    }
+
+    public ItemsJarContents(TileData tile, NbtCompound compound) {
+        this(tile, NbtSerialisable.ITEM_STACK.readAll(compound.getList("items", NbtElement.COMPOUND_TYPE))
+                .limit(15)
+                .collect(Collectors.toList()));
+    }
+
+    @Override
+    public TypedActionResult<JarContents> interact(PlayerEntity player, Hand hand) {
+        ItemStack handStack = player.getStackInHand(hand);
+
+        if (handStack.isEmpty()) {
+            if (stacks.isEmpty()) {
+                return TypedActionResult.fail(this);
+            }
+            Block.dropStack(tile.getWorld(), tile.getPos(), stacks.remove(0));
+            markDirty();
+            return TypedActionResult.success(this);
+        }
+
+        if (stacks.isEmpty()) {
+            if (handStack.getItem() instanceof MixinEntityBucketItem bucket) {
+                consumeAndSwap(player, hand, Items.BUCKET.getDefaultStack());
+                player.playSound(bucket.getEmptyingSound(), 1, 1);
+                markDirty();
+                return TypedActionResult.success(new EntityJarContents(tile, bucket.getEntityType()));
+            }
+
+            Pair<Long, FluidVariant> fluid = FluidHelper.extract(handStack, player, hand).orElse(null);
+            if (fluid != null) {
+                fluid.getRight().getFluid().getBucketFillSound().ifPresent(sound -> player.playSound(sound, 1, 1));
+                markDirty();
+                return TypedActionResult.success(new FluidOnlyJarContents(tile, fluid.getLeft(), fluid.getRight()));
+            }
+
+            if (handStack.isOf(Items.MILK_BUCKET)) {
+                consumeAndSwap(player, hand, handStack.getRecipeRemainder());
+                player.playSound(USounds.Vanilla.ITEM_BUCKET_EMPTY, 1, 1);
+                markDirty();
+                return TypedActionResult.success(new FakeFluidJarContents(tile, "milk", 0xFFFFFFFF, Items.BUCKET, Items.MILK_BUCKET));
+            }
+
+            if (handStack.isOf(Items.POWDER_SNOW_BUCKET)) {
+                consumeAndSwap(player, hand, Items.BUCKET.getDefaultStack());
+                player.playSound(USounds.Vanilla.ITEM_BUCKET_EMPTY_POWDER_SNOW, 1, 1);
+                markDirty();
+                return TypedActionResult.success(new FakeFluidJarContents(tile, "powder_snow", 0xFFFFFFFF, Items.BUCKET, Items.POWDER_SNOW_BUCKET));
+            }
+
+            if (handStack.isOf(UItems.LOVE_BUCKET)) {
+                consumeAndSwap(player, hand, handStack.getRecipeRemainder());
+                player.playSound(USounds.Vanilla.ITEM_BUCKET_EMPTY, 1, 1);
+                markDirty();
+                return TypedActionResult.success(new FakeFluidJarContents(tile, "love", 0xFF3030, Items.BUCKET, UItems.LOVE_BUCKET));
+            }
+
+            if (handStack.isOf(UItems.JUICE)) {
+                consumeAndSwap(player, hand, handStack.getRecipeRemainder());
+                player.playSound(USounds.Vanilla.ITEM_BUCKET_EMPTY, 1, 1);
+                markDirty();
+                return TypedActionResult.success(new FakeFluidJarContents(tile, "apple_juice", 0x30FF30, Items.GLASS_BOTTLE, UItems.JUICE));
+            }
+        }
+
+        if (stacks.size() >= size()) {
+            return TypedActionResult.fail(this);
+        }
+        stacks.add(player.isCreative() ? handStack.copyWithCount(1) : handStack.split(1));
+        markDirty();
+
+        return TypedActionResult.success(this);
+    }
+
+    @Override
+    public void onDestroyed() {
+        stacks.forEach(stack -> Block.dropStack(tile.getWorld(), tile.getPos(), stack));
+    }
+
+    @Override
+    public int size() {
+        return 15;
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return stacks.isEmpty();
+    }
+
+    @Override
+    public ItemStack getStack(int slot) {
+        return slot < 0 || slot >= stacks.size() ? ItemStack.EMPTY : stacks.get(slot);
+    }
+
+    @Override
+    public ItemStack removeStack(int slot, int amount) {
+        if (slot < 0 || slot >= stacks.size()) {
+            return ItemStack.EMPTY;
+        }
+
+        try {
+            ItemStack stack = stacks.get(slot);
+            ItemStack removed = stack.split(1);
+            if (stack.isEmpty()) {
+                stacks.remove(slot);
+            }
+            return removed;
+        } finally {
+            markDirty();
+        }
+    }
+
+    @Override
+    public ItemStack removeStack(int slot) {
+        if (slot < 0 || slot >= stacks.size()) {
+            return ItemStack.EMPTY;
+        }
+
+        try {
+            return stacks.remove(slot);
+        } finally {
+            markDirty();
+        }
+    }
+
+    @Override
+    public void setStack(int slot, ItemStack stack) {
+        if (slot >= stacks.size()) {
+            stacks.add(stack);
+        } else {
+            stacks.set(slot, stack);
+        }
+        markDirty();
+    }
+
+    @Override
+    public boolean canPlayerUse(PlayerEntity player) {
+        return false;
+    }
+
+    @Override
+    public void clear() {
+        stacks.clear();
+        markDirty();
+    }
+
+    @Override
+    public int[] getAvailableSlots(Direction side) {
+        return SLOTS;
+    }
+
+    @Override
+    public boolean canInsert(int slot, ItemStack stack, Direction dir) {
+        return slot >= 0 && slot < size() && slot >= stacks.size();
+    }
+
+    @Override
+    public boolean canExtract(int slot, ItemStack stack, Direction dir) {
+        return slot >= 0 && slot < size() && slot < stacks.size();
+    }
+
+    @Override
+    public NbtCompound toNBT(NbtCompound compound) {
+        compound.put("items", NbtSerialisable.ITEM_STACK.writeAll(stacks));
+        return compound;
+    }
+
+    @Override
+    public void markDirty() {
+        tile.markDirty();
+    }
+}
diff --git a/src/main/java/com/minelittlepony/unicopia/client/gui/spellbook/SpellbookCraftingPageContent.java b/src/main/java/com/minelittlepony/unicopia/client/gui/spellbook/SpellbookCraftingPageContent.java
index 6350bc98..a6fde947 100644
--- a/src/main/java/com/minelittlepony/unicopia/client/gui/spellbook/SpellbookCraftingPageContent.java
+++ b/src/main/java/com/minelittlepony/unicopia/client/gui/spellbook/SpellbookCraftingPageContent.java
@@ -7,7 +7,7 @@ import com.minelittlepony.unicopia.ability.magic.spell.crafting.SpellbookRecipe;
 import com.minelittlepony.unicopia.client.gui.DrawableUtil;
 import com.minelittlepony.unicopia.client.gui.MagicText;
 import com.minelittlepony.unicopia.container.SpellbookState;
-import com.minelittlepony.unicopia.item.URecipes;
+import com.minelittlepony.unicopia.recipe.URecipes;
 import com.mojang.blaze3d.systems.RenderSystem;
 
 import net.minecraft.client.gui.DrawContext;
diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/PlayerPoser.java b/src/main/java/com/minelittlepony/unicopia/client/render/PlayerPoser.java
index ec3b17bb..2402dfab 100644
--- a/src/main/java/com/minelittlepony/unicopia/client/render/PlayerPoser.java
+++ b/src/main/java/com/minelittlepony/unicopia/client/render/PlayerPoser.java
@@ -52,7 +52,7 @@ public class PlayerPoser {
             float pitchChange = -0.5F;
             float yawChange = 0.8F;
 
-            if (player.getStackInHand(rightHand).isIn(UTags.POLEARMS) && (!ponyRace.isEquine() || model.rightArm.pitch != 0)) {
+            if (player.getStackInHand(rightHand).isIn(UTags.Items.POLEARMS) && (!ponyRace.isEquine() || model.rightArm.pitch != 0)) {
                 model.rightArm.pitch += pitchChange;
                 model.rightArm.yaw += yawChange;
                 if (player.handSwingTicks > 0 && rightHand == Hand.MAIN_HAND) {
@@ -61,7 +61,7 @@ public class PlayerPoser {
                 }
             }
 
-            if (player.getStackInHand(leftHand).isIn(UTags.POLEARMS) && (!ponyRace.isEquine() || model.leftArm.pitch != 0)) {
+            if (player.getStackInHand(leftHand).isIn(UTags.Items.POLEARMS) && (!ponyRace.isEquine() || model.leftArm.pitch != 0)) {
                 model.leftArm.pitch += pitchChange;
                 model.leftArm.yaw -= yawChange;
                 if (player.handSwingTicks > 0 && leftHand == Hand.MAIN_HAND) {
diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/RenderUtil.java b/src/main/java/com/minelittlepony/unicopia/client/render/RenderUtil.java
index cb43a128..9b92256d 100644
--- a/src/main/java/com/minelittlepony/unicopia/client/render/RenderUtil.java
+++ b/src/main/java/com/minelittlepony/unicopia/client/render/RenderUtil.java
@@ -12,7 +12,8 @@ import net.minecraft.client.util.math.MatrixStack;
 
 public class RenderUtil {
     public static final Vector4f TEMP_VECTOR = new Vector4f();
-    private static final Vector4f TEMP_UV_VECTOR = new Vector4f();
+    public static final Vector4f TEMP_UV_VECTOR = new Vector4f();
+    public static final Vector3f TEMP_NORMAL_VECTOR = new Vector3f();
     public static final Vertex[] UNIT_FACE = new Vertex[] {
             new Vertex(0, 0, 0, 1, 1),
             new Vertex(0, 1, 0, 1, 0),
@@ -26,6 +27,9 @@ public class RenderUtil {
             new Vertex(0, 0, 0, 0, 1)
     };
 
+
+
+
     public static void renderFace(MatrixStack matrices, Tessellator te, BufferBuilder buffer, float r, float g, float b, float a, int light) {
         renderFace(matrices, te, buffer, r, g, b, a, light, 1, 1);
     }
diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/entity/ItemJarBlockEntityRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/entity/ItemJarBlockEntityRenderer.java
index 85bec08a..472a8335 100644
--- a/src/main/java/com/minelittlepony/unicopia/client/render/entity/ItemJarBlockEntityRenderer.java
+++ b/src/main/java/com/minelittlepony/unicopia/client/render/entity/ItemJarBlockEntityRenderer.java
@@ -1,29 +1,82 @@
 package com.minelittlepony.unicopia.client.render.entity;
 
-import java.util.List;
+import java.util.Arrays;
 
+import org.jetbrains.annotations.Nullable;
+
+import com.minelittlepony.common.util.Color;
 import com.minelittlepony.unicopia.block.ItemJarBlock;
+import com.minelittlepony.unicopia.block.ItemJarBlock.FluidJarContents;
+import com.minelittlepony.unicopia.block.jar.ItemsJarContents;
+import com.minelittlepony.unicopia.block.jar.FakeFluidJarContents;
+import com.minelittlepony.unicopia.block.jar.EntityJarContents;
+import com.minelittlepony.unicopia.client.render.model.CubeModel;
+import com.minelittlepony.unicopia.util.FluidHelper;
+import com.minelittlepony.unicopia.util.PosHelper;
 
+import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRenderHandler;
+import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRenderHandlerRegistry;
+import net.fabricmc.fabric.api.transfer.v1.fluid.FluidConstants;
 import net.minecraft.client.MinecraftClient;
+import net.minecraft.client.render.RenderLayer;
 import net.minecraft.client.render.VertexConsumerProvider;
 import net.minecraft.client.render.block.entity.BlockEntityRenderer;
 import net.minecraft.client.render.block.entity.BlockEntityRendererFactory;
+import net.minecraft.client.render.entity.EntityRenderDispatcher;
+import net.minecraft.client.render.item.ItemRenderer;
 import net.minecraft.client.render.model.json.ModelTransformationMode;
+import net.minecraft.client.texture.Sprite;
 import net.minecraft.client.util.math.MatrixStack;
+import net.minecraft.command.argument.EntityAnchorArgumentType.EntityAnchor;
+import net.minecraft.entity.Entity;
+import net.minecraft.entity.player.PlayerEntity;
+import net.minecraft.fluid.Fluid;
+import net.minecraft.fluid.FluidState;
+import net.minecraft.fluid.Fluids;
 import net.minecraft.item.ItemStack;
+import net.minecraft.util.math.BlockPos;
+import net.minecraft.util.math.Direction;
+import net.minecraft.util.math.MathHelper;
 import net.minecraft.util.math.RotationAxis;
+import net.minecraft.util.math.Vec3d;
 import net.minecraft.util.math.random.Random;
+import net.minecraft.world.World;
 
 public class ItemJarBlockEntityRenderer implements BlockEntityRenderer<ItemJarBlock.TileData> {
+    private static final Direction[] GLASS_SIDES = Arrays.stream(PosHelper.ALL).filter(i -> i != Direction.UP).toArray(Direction[]::new);
+    private final ItemRenderer itemRenderer;
+    private final EntityRenderDispatcher dispatcher;
 
     public ItemJarBlockEntityRenderer(BlockEntityRendererFactory.Context ctx) {
+        itemRenderer = ctx.getItemRenderer();
+        dispatcher = ctx.getEntityRenderDispatcher();
     }
 
     @Override
-    public void render(ItemJarBlock.TileData entity, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertices, int light, int overlay) {
+    public void render(ItemJarBlock.TileData data, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertices, int light, int overlay) {
 
-        List<ItemStack> stacks = entity.getStacks();
+        ItemsJarContents items = data.getItems();
+        if (items != null) {
+            renderItemStacks(data, items, tickDelta, matrices, vertices, light, overlay);
+        }
 
+        EntityJarContents entity = data.getEntity();
+        if (entity != null) {
+            renderEntity(data, entity, tickDelta, matrices, vertices, light, overlay);
+        }
+
+        FluidJarContents fluid = data.getFluid();
+        if (fluid != null) {
+            renderFluid(data, fluid, tickDelta, matrices, vertices, light, overlay);
+        }
+
+        FakeFluidJarContents milk = data.getFakeFluid();
+        if (milk != null) {
+            renderFluid(data, Fluids.WATER.getDefaultState(), milk.color(), FluidConstants.BUCKET, tickDelta, matrices, vertices, light, overlay);
+        }
+    }
+
+    private void renderItemStacks(ItemJarBlock.TileData data, ItemsJarContents items, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertices, int light, int overlay) {
         float itemScale = 0.35F;
 
         matrices.push();
@@ -31,19 +84,102 @@ public class ItemJarBlockEntityRenderer implements BlockEntityRenderer<ItemJarBl
         matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(90));
         matrices.scale(itemScale, itemScale, itemScale);
 
-        Random rng = Random.create(entity.getPos().asLong());
+        Random rng = Random.create(data.getPos().asLong());
 
         float y = 0;
-        for (ItemStack stack : stacks) {
+        for (ItemStack stack : items.stacks()) {
             matrices.push();
 
             matrices.translate((rng.nextFloat() - 0.5F) * 0.5F, (rng.nextFloat() - 0.5F) * 0.8F, -0.05 + y);
             matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees((rng.nextFloat() * 360) - 180));
             matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees((rng.nextFloat() * 360) - 180));
             y -= 0.1F;
-            MinecraftClient.getInstance().getItemRenderer().renderItem(stack, ModelTransformationMode.FIXED, light, overlay, matrices, vertices, entity.getWorld(), 0);
+            itemRenderer.renderItem(stack, ModelTransformationMode.FIXED, light, overlay, matrices, vertices, data.getWorld(), 0);
             matrices.pop();
         }
         matrices.pop();
     }
+
+    private void renderEntity(ItemJarBlock.TileData data, EntityJarContents entity, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertices, int light, int overlay) {
+        Entity e = entity.entity().get();
+        if (e != null) {
+
+            PlayerEntity player = MinecraftClient.getInstance().player;
+            int age = player == null ? 0 : player.age;
+
+            float fullTick = age + tickDelta;
+
+            float size = Math.max(e.getWidth(), e.getHeight());
+            float desiredSize = 0.25F;
+            float scale = desiredSize / size;
+            float eyePos = (e.getEyeHeight(e.getPose())) * scale;
+
+            float yaw = 0;
+            if (player != null) {
+                Vec3d center = data.getPos().toCenterPos();
+                Vec3d observerPos = MinecraftClient.getInstance().gameRenderer.getCamera().getPos();
+                e.setPosition(center);
+                e.lookAt(EntityAnchor.FEET, observerPos);
+            }
+
+            matrices.push();
+            matrices.translate(0.5, 0.48 + MathHelper.sin(fullTick / 19F) * 0.02F - eyePos, 0.5);
+            matrices.scale(scale, scale, scale);
+            matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(10 * MathHelper.sin(fullTick / 19F)));
+            dispatcher.render(e, 0, 0, 0, yaw * MathHelper.RADIANS_PER_DEGREE, tickDelta, matrices, vertices, light);
+            matrices.pop();
+        }
+    }
+
+    private void renderFluid(ItemJarBlock.TileData data, FluidJarContents fluid, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertices, int light, int overlay) {
+        FluidState state = FluidHelper.getFullFluidState(fluid.fluid());
+        int color = getFluidColor(data.getWorld(), data.getPos(), state);
+        renderFluid(data, state, color, fluid.amount(), tickDelta, matrices, vertices, light, overlay);
+    }
+
+    private void renderFluid(ItemJarBlock.TileData data, FluidState state, int color, long amount, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertices, int light, int overlay) {
+        Sprite[] sprite = getFluidSprite(data.getWorld(), data.getPos(), state);
+        matrices.push();
+        Sprite topSprite = sprite[0];
+        float height = 0.6F * (amount / (float)FluidConstants.BUCKET);
+        boolean opaque = Color.a(color) >= 1;
+        CubeModel.render(
+                matrices,
+                vertices.getBuffer(opaque ? RenderLayer.getEntitySolid(topSprite.getAtlasId()) : RenderLayer.getEntityTranslucent(topSprite.getAtlasId())),
+                topSprite.getMinU(), topSprite.getMinV(),
+                topSprite.getMaxU(), topSprite.getMaxV(),
+                0.28F, 0.01F, 0.28F,
+                0.73F, 0.01F + height, 0.73F,
+                color,
+                light, overlay, Direction.UP
+        );
+        Sprite sideSprite = sprite[sprite.length - 1];
+        CubeModel.render(
+                matrices,
+                vertices.getBuffer(opaque ? RenderLayer.getEntitySolid(sideSprite.getAtlasId()) : RenderLayer.getEntityTranslucent(sideSprite.getAtlasId())),
+                sideSprite.getMinU(), sideSprite.getMinV(),
+                sideSprite.getMaxU(), sideSprite.getMaxV(),
+                0.28F, 0.01F, 0.28F,
+                0.73F, 0.01F + height, 0.73F,
+                color,
+                light, overlay, GLASS_SIDES
+        );
+        matrices.pop();
+    }
+
+    private int getFluidColor(World world, BlockPos pos, FluidState state) {
+        return getFluidHandler(state.getFluid()).getFluidColor(world, pos, state);
+    }
+
+    private Sprite[] getFluidSprite(@Nullable World world, BlockPos pos, FluidState state) {
+        return getFluidHandler(state.getFluid()).getFluidSprites(world, pos, state);
+    }
+
+    private FluidRenderHandler getFluidHandler(Fluid fluid) {
+        FluidRenderHandler handler = FluidRenderHandlerRegistry.INSTANCE.get(fluid);
+        if (handler == null) {
+            return FluidRenderHandlerRegistry.INSTANCE.get(Fluids.WATER);
+        }
+        return handler;
+    }
 }
diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/model/CubeModel.java b/src/main/java/com/minelittlepony/unicopia/client/render/model/CubeModel.java
new file mode 100644
index 00000000..6aaadb33
--- /dev/null
+++ b/src/main/java/com/minelittlepony/unicopia/client/render/model/CubeModel.java
@@ -0,0 +1,77 @@
+package com.minelittlepony.unicopia.client.render.model;
+
+import org.joml.Matrix3f;
+import org.joml.Matrix4f;
+import org.joml.Vector2f;
+import org.joml.Vector3f;
+import org.joml.Vector4f;
+
+import com.minelittlepony.common.util.Color;
+import com.minelittlepony.unicopia.client.render.RenderUtil;
+import com.minelittlepony.unicopia.client.render.RenderUtil.Vertex;
+
+import net.minecraft.client.render.VertexConsumer;
+import net.minecraft.client.util.math.MatrixStack;
+import net.minecraft.util.math.Direction;
+
+public class CubeModel {
+    private static final Vector2f TEMP_UV_VECTOR = new Vector2f();
+    private static final Vertex[][] CUBE_VERTICES = {
+            new Vertex[] {
+                    new Vertex(0, 0, 0, 0, 0),
+                    new Vertex(1, 0, 0, 1, 0),
+                    new Vertex(1, 0, 1, 1, 1),
+                    new Vertex(0, 0, 1, 0, 1)
+            },
+            new Vertex[] {
+                    new Vertex(0, 1, 0, 0, 0),
+                    new Vertex(0, 1, 1, 0, 1),
+                    new Vertex(1, 1, 1, 1, 1),
+                    new Vertex(1, 1, 0, 1, 0)
+            },
+            new Vertex[] {
+                    new Vertex(0, 0, 0, 0, 0),
+                    new Vertex(0, 1, 0, 0, 1),
+                    new Vertex(1, 1, 0, 1, 1),
+                    new Vertex(1, 0, 0, 1, 0)
+            },
+            new Vertex[] {
+                    new Vertex(0, 0, 1, 0, 0),
+                    new Vertex(1, 0, 1, 1, 0),
+                    new Vertex(1, 1, 1, 1, 1),
+                    new Vertex(0, 1, 1, 0, 1)
+            },
+            new Vertex[] {
+                    new Vertex(0, 0, 0, 0, 0),
+                    new Vertex(0, 0, 1, 1, 0),
+                    new Vertex(0, 1, 1, 1, 1),
+                    new Vertex(0, 1, 0, 0, 1)
+            },
+            new Vertex[] {
+                    new Vertex(1, 0, 0, 0, 0),
+                    new Vertex(1, 1, 0, 1, 0),
+                    new Vertex(1, 1, 1, 1, 1),
+                    new Vertex(1, 0, 1, 0, 1)
+            }
+    };
+
+    public static void render(MatrixStack matrices, VertexConsumer buffer,
+            float u0, float v0, float u1, float v1,
+            float x0, float y0, float z0, float x1, float y1, float z1,
+            int color, int light, int overlay,
+            Direction... directions) {
+        float r = Color.r(color), g = Color.g(color), b = Color.b(color);
+        float du = u1 - u0, dv = v1 - v0;
+        float dx = x1 - x0, dy = y1 - y0, dz = z1 - z0;
+        Matrix4f position = matrices.peek().getPositionMatrix();
+        Matrix3f normal = matrices.peek().getNormalMatrix();
+        for (Direction direction : directions) {
+            for (Vertex vertex : CUBE_VERTICES[direction.ordinal()]) {
+                Vector4f pos = position.transform(RenderUtil.TEMP_VECTOR.set(vertex.position(), 1).mul(dx, dy, dz, 1).add(x0, y0, z0, 0));
+                Vector2f tex = TEMP_UV_VECTOR.set(vertex.texture().x, vertex.texture().y).mul(du, dv).add(u0, v0);
+                Vector3f norm = normal.transform(RenderUtil.TEMP_NORMAL_VECTOR.set(direction.getOffsetX(), direction.getOffsetY(), direction.getOffsetZ()));
+                buffer.vertex(pos.x, pos.y, pos.z, r, g, b, 1, tex.x, tex.y, overlay, light, norm.x, norm.y, norm.z);
+            }
+        }
+    }
+}
diff --git a/src/main/java/com/minelittlepony/unicopia/compat/emi/Main.java b/src/main/java/com/minelittlepony/unicopia/compat/emi/Main.java
index 9523cce2..4924981f 100644
--- a/src/main/java/com/minelittlepony/unicopia/compat/emi/Main.java
+++ b/src/main/java/com/minelittlepony/unicopia/compat/emi/Main.java
@@ -15,10 +15,10 @@ import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
 import com.minelittlepony.unicopia.block.UBlocks;
 import com.minelittlepony.unicopia.block.state.Schematic;
 import com.minelittlepony.unicopia.item.EnchantableItem;
-import com.minelittlepony.unicopia.item.TransformCropsRecipe;
 import com.minelittlepony.unicopia.item.UItems;
-import com.minelittlepony.unicopia.item.URecipes;
 import com.minelittlepony.unicopia.item.group.MultiItem;
+import com.minelittlepony.unicopia.recipe.TransformCropsRecipe;
+import com.minelittlepony.unicopia.recipe.URecipes;
 
 import dev.emi.emi.api.EmiPlugin;
 import dev.emi.emi.api.EmiRegistry;
diff --git a/src/main/java/com/minelittlepony/unicopia/container/ShapingBenchScreenHandler.java b/src/main/java/com/minelittlepony/unicopia/container/ShapingBenchScreenHandler.java
index 3ff1ac4a..2758a373 100644
--- a/src/main/java/com/minelittlepony/unicopia/container/ShapingBenchScreenHandler.java
+++ b/src/main/java/com/minelittlepony/unicopia/container/ShapingBenchScreenHandler.java
@@ -1,7 +1,7 @@
 package com.minelittlepony.unicopia.container;
 
 import com.minelittlepony.unicopia.block.UBlocks;
-import com.minelittlepony.unicopia.item.URecipes;
+import com.minelittlepony.unicopia.recipe.URecipes;
 
 import net.minecraft.entity.player.PlayerEntity;
 import net.minecraft.entity.player.PlayerInventory;
diff --git a/src/main/java/com/minelittlepony/unicopia/container/SpellbookScreenHandler.java b/src/main/java/com/minelittlepony/unicopia/container/SpellbookScreenHandler.java
index 5f675f85..47a088f1 100644
--- a/src/main/java/com/minelittlepony/unicopia/container/SpellbookScreenHandler.java
+++ b/src/main/java/com/minelittlepony/unicopia/container/SpellbookScreenHandler.java
@@ -10,7 +10,7 @@ import com.minelittlepony.unicopia.compat.trinkets.TrinketsDelegate;
 import com.minelittlepony.unicopia.container.inventory.*;
 import com.minelittlepony.unicopia.entity.player.Pony;
 import com.minelittlepony.unicopia.item.UItems;
-import com.minelittlepony.unicopia.item.URecipes;
+import com.minelittlepony.unicopia.recipe.URecipes;
 import com.mojang.datafixers.util.Pair;
 
 import net.minecraft.enchantment.EnchantmentHelper;
diff --git a/src/main/java/com/minelittlepony/unicopia/datagen/DataCollector.java b/src/main/java/com/minelittlepony/unicopia/datagen/DataCollector.java
index 46b27642..2dabd5cd 100644
--- a/src/main/java/com/minelittlepony/unicopia/datagen/DataCollector.java
+++ b/src/main/java/com/minelittlepony/unicopia/datagen/DataCollector.java
@@ -22,6 +22,10 @@ public class DataCollector {
         this.resolver = resolver;
     }
 
+    public boolean isDefined(Identifier id) {
+        return values.containsKey(id);
+    }
+
     public BiConsumer<Identifier, Supplier<JsonElement>> prime() {
         values.clear();
         return (Identifier id, Supplier<JsonElement> value) ->
diff --git a/src/main/java/com/minelittlepony/unicopia/datagen/Datagen.java b/src/main/java/com/minelittlepony/unicopia/datagen/Datagen.java
index 972699d1..517a21e4 100644
--- a/src/main/java/com/minelittlepony/unicopia/datagen/Datagen.java
+++ b/src/main/java/com/minelittlepony/unicopia/datagen/Datagen.java
@@ -3,39 +3,62 @@ package com.minelittlepony.unicopia.datagen;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 
+import com.minelittlepony.unicopia.block.EdibleBlock;
+import com.minelittlepony.unicopia.datagen.providers.DietsProvider;
 import com.minelittlepony.unicopia.datagen.providers.SeasonsGrowthRatesProvider;
 import com.minelittlepony.unicopia.datagen.providers.UAdvancementsProvider;
-import com.minelittlepony.unicopia.datagen.providers.UBlockTagProvider;
-import com.minelittlepony.unicopia.datagen.providers.UItemTagProvider;
 import com.minelittlepony.unicopia.datagen.providers.UModelProvider;
 import com.minelittlepony.unicopia.datagen.providers.loot.UBlockAdditionsLootTableProvider;
 import com.minelittlepony.unicopia.datagen.providers.loot.UBlockLootTableProvider;
 import com.minelittlepony.unicopia.datagen.providers.loot.UChestAdditionsLootTableProvider;
+import com.minelittlepony.unicopia.datagen.providers.loot.UChestLootTableProvider;
+import com.minelittlepony.unicopia.datagen.providers.loot.UEntityLootTableProvider;
 import com.minelittlepony.unicopia.datagen.providers.recipe.URecipeProvider;
+import com.minelittlepony.unicopia.datagen.providers.tag.UBlockTagProvider;
+import com.minelittlepony.unicopia.datagen.providers.tag.UDamageTypeProvider;
+import com.minelittlepony.unicopia.datagen.providers.tag.UItemTagProvider;
+import com.minelittlepony.unicopia.entity.damage.UDamageTypes;
 import com.minelittlepony.unicopia.server.world.UWorldGen;
 
 import net.fabricmc.fabric.api.datagen.v1.DataGeneratorEntrypoint;
 import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator;
+import net.minecraft.block.Block;
+import net.minecraft.item.Item;
+import net.minecraft.registry.Registries;
+import net.minecraft.registry.Registry;
 import net.minecraft.registry.RegistryBuilder;
-import net.minecraft.registry.RegistryEntryLookup;
 import net.minecraft.registry.RegistryKeys;
+import net.minecraft.util.Identifier;
 import net.minecraft.world.biome.OverworldBiomeCreator;
-import net.minecraft.world.gen.carver.ConfiguredCarver;
-import net.minecraft.world.gen.feature.PlacedFeature;
 
 public class Datagen implements DataGeneratorEntrypoint {
     public static final Logger LOGGER = LogManager.getLogger();
 
+    public static Block getOrCreateBaleBlock(Identifier id) {
+        return Registries.BLOCK.getOrEmpty(id).orElseGet(() -> {
+            return Registry.register(Registries.BLOCK, id, new EdibleBlock(id, id, false));
+        });
+    }
+
+    public static Item getOrCreateItem(Identifier id) {
+        return Registries.ITEM.getOrEmpty(id).orElseGet(() -> {
+            return Registry.register(Registries.ITEM, id, new Item(new Item.Settings()));
+        });
+    }
+
     @Override
     public void onInitializeDataGenerator(FabricDataGenerator fabricDataGenerator) {
-        final FabricDataGenerator.Pack pack = fabricDataGenerator.createPack();
-
-        UBlockTagProvider blockTags = pack.addProvider(UBlockTagProvider::new);
-        pack.addProvider((output, registries) -> new UItemTagProvider(output, registries, blockTags));
+        final var pack = fabricDataGenerator.createPack();
+        final var blockTags = pack.addProvider(UBlockTagProvider::new);
+        final var itemTags = pack.addProvider((output, registries) -> new UItemTagProvider(output, registries, blockTags));
+        pack.addProvider((output, registries) -> new DietsProvider(output, itemTags));
+        pack.addProvider(UDamageTypeProvider::new);
 
         pack.addProvider(UModelProvider::new);
         pack.addProvider(URecipeProvider::new);
         pack.addProvider(UBlockLootTableProvider::new);
+        pack.addProvider(UEntityLootTableProvider::new);
+        pack.addProvider(UChestLootTableProvider::new);
         pack.addProvider(UBlockAdditionsLootTableProvider::new);
         pack.addProvider(UChestAdditionsLootTableProvider::new);
         pack.addProvider(SeasonsGrowthRatesProvider::new);
@@ -45,9 +68,10 @@ public class Datagen implements DataGeneratorEntrypoint {
     @Override
     public void buildRegistry(RegistryBuilder builder) {
         builder.addRegistry(RegistryKeys.BIOME, registerable -> {
-            RegistryEntryLookup<PlacedFeature> placedFeatureLookup = registerable.getRegistryLookup(RegistryKeys.PLACED_FEATURE);
-            RegistryEntryLookup<ConfiguredCarver<?>> carverLookup = registerable.getRegistryLookup(RegistryKeys.CONFIGURED_CARVER);
+            final var placedFeatureLookup = registerable.getRegistryLookup(RegistryKeys.PLACED_FEATURE);
+            final var carverLookup = registerable.getRegistryLookup(RegistryKeys.CONFIGURED_CARVER);
             registerable.register(UWorldGen.SWEET_APPLE_ORCHARD, OverworldBiomeCreator.createNormalForest(placedFeatureLookup, carverLookup, false, false, false));
         });
+        builder.addRegistry(RegistryKeys.DAMAGE_TYPE, UDamageTypes.REGISTRY);
     }
 }
diff --git a/src/main/java/com/minelittlepony/unicopia/datagen/providers/DietProfileGenerator.java b/src/main/java/com/minelittlepony/unicopia/datagen/providers/DietProfileGenerator.java
new file mode 100644
index 00000000..4034021f
--- /dev/null
+++ b/src/main/java/com/minelittlepony/unicopia/datagen/providers/DietProfileGenerator.java
@@ -0,0 +1,275 @@
+package com.minelittlepony.unicopia.datagen.providers;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.function.BiConsumer;
+import com.minelittlepony.unicopia.Race;
+import com.minelittlepony.unicopia.Unicopia;
+import com.minelittlepony.unicopia.diet.DietProfile;
+import com.minelittlepony.unicopia.diet.DietProfile.Multiplier;
+import com.minelittlepony.unicopia.diet.FoodGroupEffects;
+import com.minelittlepony.unicopia.diet.affliction.ClearLoveSicknessAffliction;
+import com.minelittlepony.unicopia.diet.affliction.CompoundAffliction;
+import com.minelittlepony.unicopia.diet.affliction.HealingAffliction;
+import com.minelittlepony.unicopia.diet.affliction.LoseHungerAffliction;
+import com.minelittlepony.unicopia.diet.affliction.Range;
+import com.minelittlepony.unicopia.diet.affliction.StatusEffectAffliction;
+import com.minelittlepony.unicopia.entity.effect.UEffects;
+import com.minelittlepony.unicopia.item.UFoodComponents;
+
+import net.minecraft.entity.effect.StatusEffects;
+import net.minecraft.item.FoodComponents;
+
+public class DietProfileGenerator {
+
+    public void generate(BiConsumer<Race, DietProfile> exporter) {
+        // Pinecones are for everypony
+        var pineconeMultiplier = new Multiplier.Builder().tag(Unicopia.id("pinecone")).hunger(0.9F).saturation(0.9F).build();
+        var bakedGoodPreference = new Multiplier.Builder().tag(Unicopia.id("baked_goods")).build();
+        var bakedGoodExtremePreference = new Multiplier.Builder().tag(Unicopia.id("baked_goods")).hunger(1.2F).saturation(2).build();
+        var bakedGoodNonPreference = new Multiplier.Builder().tag(Unicopia.id("baked_goods")).hunger(0.4F).saturation(0.2F).build();
+        var properMeatStandards = new Multiplier.Builder().tag(Unicopia.id("love"))
+                .tag(Unicopia.id("meat/raw")).tag(Unicopia.id("insect/raw")).tag(Unicopia.id("fish/raw"))
+                .tag(Unicopia.id("meat/rotten")).tag(Unicopia.id("insect/rotten")).tag(Unicopia.id("fish/rotten"))
+                .hunger(0).saturation(0).build();
+        var avianMeatStandards = new Multiplier.Builder().tag(Unicopia.id("love"))
+                .tag(Unicopia.id("meat/raw")).tag(Unicopia.id("insect/raw"))
+                .tag(Unicopia.id("meat/rotten")).tag(Unicopia.id("insect/rotten"))
+                .hunger(0).saturation(0).build();
+        var loveSicknessEffects = CompoundAffliction.of(
+                new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(100), Range.of(2), 95),
+                new StatusEffectAffliction(StatusEffects.WEAKNESS, Range.of(200), Range.of(1), 0),
+                new LoseHungerAffliction(0.5F));
+        var seaFoodExclusions = new Multiplier.Builder()
+                .tag(Unicopia.id("sea_vegetable/raw")).tag(Unicopia.id("sea_vegetable/cooked"))
+                .tag(Unicopia.id("shells")).tag(Unicopia.id("special_shells"))
+                .hunger(0).saturation(0).build();
+
+        exporter.accept(Race.HUMAN, new DietProfile(1, 0, List.of(), List.of(
+                new FoodGroupEffects.Builder()
+                .tag(Unicopia.id("fish/cooked")).tag(Unicopia.id("fish/raw")).tag(Unicopia.id("fish/rotten"))
+                .tag(Unicopia.id("meat/cooked")).tag(Unicopia.id("meat/raw")).tag(Unicopia.id("meat/rotten"))
+                .tag(Unicopia.id("sea_vegetable/cooked")).tag(Unicopia.id("sea_vegetable/raw"))
+                .tag(Unicopia.id("pinecone"))
+                .build()
+        ), Optional.empty()));
+        // Alicorns are a mashup of unicorn, pegasus, and earth pony eating habits
+        exporter.accept(Race.ALICORN, new DietProfile(0.9F, 1, List.of(
+                // Pastries are their passion
+                bakedGoodExtremePreference, pineconeMultiplier, avianMeatStandards, seaFoodExclusions,
+                // They have a more of a sweet tooth than earth ponies
+                new Multiplier.Builder().tag(Unicopia.id("desserts")).hunger(2.5F).saturation(1.7F).build(),
+                new Multiplier.Builder().tag(Unicopia.id("candy")).tag(Unicopia.id("rocks")).hunger(1.5F).saturation(1.3F).build(),
+
+                // Cannot eat love, or raw/rotten meats and fish
+                // Can eat raw and rotten fish but still prefers if they are cooked
+                new Multiplier.Builder().tag(Unicopia.id("fish/cooked")).hunger(1.5F).saturation(1.5F).build(),
+                new Multiplier.Builder().tag(Unicopia.id("meat/cooked")).hunger(0.25F).saturation(0.16F).build(),
+                new Multiplier.Builder().tag(Unicopia.id("insect/cooked")).hunger(0.1F).saturation(0.7F).build(),
+
+                new Multiplier.Builder().tag(Unicopia.id("fish/raw")).hunger(0.5F).saturation(0.8F).build(),
+                new Multiplier.Builder().tag(Unicopia.id("fish/rotten")).hunger(0.25F).saturation(0.5F).build()
+        ), List.of(
+                // Can safely eat fresh and cooked fish with no ill effects
+                new FoodGroupEffects.Builder().tag(Unicopia.id("fish/cooked")).tag(Unicopia.id("fish/raw")).build(),
+                // Is less affected when eating rotten fish
+                new FoodGroupEffects.Builder().tag(Unicopia.id("fish/rotten")).ailment(new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(50), Range.of(2), 95)).build()
+        ), Optional.empty()));
+        // Unicorns have a general even preference of foods
+        exporter.accept(Race.UNICORN, new DietProfile(1.1F, 1, List.of(
+                bakedGoodPreference, pineconeMultiplier, seaFoodExclusions,
+                new Multiplier.Builder().tag(Unicopia.id("love")).hunger(0).saturation(0).build(),
+
+                // Improved benefits from cooking their food
+                new Multiplier.Builder().tag(Unicopia.id("fish/cooked")).hunger(0.3F).saturation(0.2F).build(),
+                new Multiplier.Builder().tag(Unicopia.id("meat/cooked")).hunger(0.4F).saturation(0.4F).build(),
+                new Multiplier.Builder().tag(Unicopia.id("insect/cooked")).hunger(0.1F).saturation(0.1F).build(),
+
+                new Multiplier.Builder().tag(Unicopia.id("fish/raw")).hunger(0.25F).saturation(0.1F).build(),
+                new Multiplier.Builder().tag(Unicopia.id("meat/raw")).hunger(0.3F).saturation(0.1F).build(),
+                new Multiplier.Builder().tag(Unicopia.id("insect/raw")).hunger(0.15F).saturation(0.1F).build(),
+
+                // Can still eat raw and rotten but at a reduced yield
+                new Multiplier.Builder().tag(Unicopia.id("fish/rotten")).hunger(0.1F).saturation(0.1F).build(),
+                new Multiplier.Builder().tag(Unicopia.id("meat/rotten")).hunger(0.1F).saturation(0.1F).build(),
+                new Multiplier.Builder().tag(Unicopia.id("insect/rotten")).hunger(0).saturation(0.1F).build()
+        ), List.of(), Optional.empty()));
+        // Bats prefer cooked foods over raw, and meat/insects over fish
+        exporter.accept(Race.BAT, new DietProfile(0.7F, 0.9F, List.of(
+                pineconeMultiplier, seaFoodExclusions,
+                // Doesn't like baked goods but really likes meats, fish, and insects
+                bakedGoodNonPreference,
+
+                new Multiplier.Builder().tag(Unicopia.id("fish/cooked")).hunger(0.75F).saturation(0.75F).build(),
+                new Multiplier.Builder().tag(Unicopia.id("meat/cooked")).hunger(1.15F).saturation(1.16F).build(),
+                new Multiplier.Builder().tag(Unicopia.id("insect/cooked")).hunger(1.75F).saturation(1.74F).build(),
+
+                new Multiplier.Builder().tag(Unicopia.id("fish/raw")).hunger(0.5F).saturation(0.6F).build(),
+                new Multiplier.Builder().tag(Unicopia.id("meat/raw")).hunger(0.25F).saturation(0.25F).build(),
+                new Multiplier.Builder().tag(Unicopia.id("insect/raw")).hunger(1).saturation(1).build(),
+
+                new Multiplier.Builder().tag(Unicopia.id("fish/rotten")).hunger(0.24F).saturation(0.25F).build(),
+                new Multiplier.Builder().tag(Unicopia.id("meat/rotten")).hunger(0.2F).saturation(0.2F).build(),
+                new Multiplier.Builder().tag(Unicopia.id("insect/rotten")).hunger(0.9F).saturation(0.9F).build()
+        ), List.of(
+                // Gets food poisoning from eating rotten and raw meat
+                new FoodGroupEffects.Builder().tag(Unicopia.id("fish/rotten")).tag(Unicopia.id("meat/raw")).tag(Unicopia.id("meat/rotten")).ailment(new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(100), Range.of(2), 5)).build(),
+                new FoodGroupEffects.Builder().tag(Unicopia.id("insect/rotten")).ailment(new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(50), Range.of(1), 15)).build(),
+                // Can eat cooked meat and insects without negative effects
+                new FoodGroupEffects.Builder().tag(Unicopia.id("insect/cooked")).tag(Unicopia.id("meat/cooked")).build(),
+                // Becomes hyper when eating mangoes
+                new FoodGroupEffects.Builder().tag(Unicopia.id("bat_ponys_delight")).ailment(CompoundAffliction.of(
+                        new StatusEffectAffliction(StatusEffects.HEALTH_BOOST, Range.of(30, 60), Range.of(2, 6), 0),
+                        new StatusEffectAffliction(StatusEffects.JUMP_BOOST, Range.of(30, 60), Range.of(1, 6), 0),
+                        new StatusEffectAffliction(StatusEffects.REGENERATION, Range.of(3, 30), Range.of(3, 6), 0)
+                )).build()
+        ), Optional.empty()));
+        // Much like Earth Ponies, Kirins must cook their meat before they eat it
+        exporter.accept(Race.KIRIN, new DietProfile(0.6F, 0.9F, List.of(
+                // Cannot eat love, or raw/rotten meats and fish
+                bakedGoodPreference, properMeatStandards, pineconeMultiplier, seaFoodExclusions,
+
+                new Multiplier.Builder().tag(Unicopia.id("fish/cooked")).hunger(0.75F).saturation(0.35F).build(),
+                new Multiplier.Builder().tag(Unicopia.id("meat/cooked")).hunger(1.5F).saturation(1.6F).build(),
+                new Multiplier.Builder().tag(Unicopia.id("insect/cooked")).hunger(0.25F).saturation(0.74F).build()
+        ), List.of(
+                // can eat these without negative effects
+                new FoodGroupEffects.Builder().tag(Unicopia.id("insect/cooked")).tag(Unicopia.id("meat/cooked")).food(FoodComponents.COOKED_BEEF).build(),
+                new FoodGroupEffects.Builder().tag(Unicopia.id("foraging/blinding")).food(4, 0.2F).build(),
+                new FoodGroupEffects.Builder().tag(Unicopia.id("foraging/prickly")).food(0, 1.5F).build(),
+                new FoodGroupEffects.Builder().tag(Unicopia.id("foraging/severely_prickly")).food(2, 0.9F).build(),
+                new FoodGroupEffects.Builder().tag(Unicopia.id("foraging/strengthening")).food(4, 0.2F).ailment(new StatusEffectAffliction(StatusEffects.STRENGTH, Range.of(1300), Range.of(0), 0)).build(),
+                new FoodGroupEffects.Builder().tag(Unicopia.id("foraging/glowing")).food(1, 1.6F).ailment(new StatusEffectAffliction(StatusEffects.GLOWING, Range.of(30), Range.of(0), 30)).build()
+        ), Optional.empty()));
+        // Earth Ponies are vegans. They get the most from foraging
+        exporter.accept(Race.EARTH, new DietProfile(0.7F, 1.2F, List.of(
+                // Pastries are their passion
+                // If they must eat meat, they have to cook it and not let it spoil.
+                bakedGoodExtremePreference, pineconeMultiplier, properMeatStandards, seaFoodExclusions,
+                // They have a sweet tooth
+                new Multiplier.Builder().tag(Unicopia.id("candy")).tag(Unicopia.id("desserts")).tag(Unicopia.id("rocks")).hunger(2.5F).saturation(1.7F).build(),
+                new Multiplier.Builder().tag(Unicopia.id("fish/cooked")).hunger(0.2F).saturation(0.3F).build(),
+                new Multiplier.Builder().tag(Unicopia.id("insect/cooked")).hunger(0.1F).saturation(0.1F).build(),
+                new Multiplier.Builder().tag(Unicopia.id("meat/cooked")).hunger(0.1F).saturation(0.1F).build()
+        ), List.of(
+                // Candy and rocks gives them a massive saturation boost. Maybe too much?
+                new FoodGroupEffects.Builder().tag(Unicopia.id("candy")).tag(Unicopia.id("rocks")).food(UFoodComponents.builder(5, 12).alwaysEdible()).build(),
+                new FoodGroupEffects.Builder().tag(Unicopia.id("desserts")).food(UFoodComponents.builder(12, 32).snack().alwaysEdible()).build()
+        ), Optional.empty()));
+        // Pegasi prefer fish over other food sources
+        exporter.accept(Race.PEGASUS, new DietProfile(0.9F, 1, List.of(
+                bakedGoodPreference, pineconeMultiplier, avianMeatStandards, seaFoodExclusions,
+                // Cannot eat love, or raw/rotten meat
+                // Can eat raw and rotten fish but still prefers if they are cooked
+                new Multiplier.Builder().tag(Unicopia.id("fish/cooked")).hunger(1.5F).saturation(1.5F).build(),
+                new Multiplier.Builder().tag(Unicopia.id("meat/cooked")).hunger(0.25F).saturation(0.16F).build(),
+                new Multiplier.Builder().tag(Unicopia.id("insect/cooked")).hunger(0.1F).saturation(0.7F).build(),
+
+                new Multiplier.Builder().tag(Unicopia.id("fish/raw")).hunger(0.5F).saturation(0.8F).build(),
+                new Multiplier.Builder().tag(Unicopia.id("fish/rotten")).hunger(0.25F).saturation(0.5F).build()
+        ), List.of(
+                // Can safely eat fresh and cooked fish with no ill effects
+                new FoodGroupEffects.Builder().tag(Unicopia.id("fish/cooked")).tag(Unicopia.id("fish/raw")).build(),
+                // Is less affected when eating rotten fish
+                new FoodGroupEffects.Builder().tag(Unicopia.id("fish/rotten")).ailment(new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(50), Range.of(2), 95)).build()
+        ), Optional.empty()));
+        // Changelings like meat and fish but really prefer feasting on ponies' love directly from the tap
+        exporter.accept(Race.CHANGELING, new DietProfile(0.15F, 0.1F, List.of(
+                // Doesn't like baked goods but really likes meats, fish, and insects
+                bakedGoodNonPreference, pineconeMultiplier, seaFoodExclusions,
+
+                new Multiplier.Builder().tag(Unicopia.id("fish/cooked")).hunger(0.5F).saturation(1.2F).build(),
+                new Multiplier.Builder().tag(Unicopia.id("meat/cooked")).hunger(0.9F).saturation(1.2F).build(),
+                new Multiplier.Builder().tag(Unicopia.id("insect/cooked")).hunger(1.2F).saturation(1.3F).build(),
+
+                new Multiplier.Builder().tag(Unicopia.id("fish/raw")).hunger(0.15F).saturation(0.25F).build(),
+                new Multiplier.Builder().tag(Unicopia.id("meat/raw")).hunger(1.25F).saturation(1.25F).build(),
+                new Multiplier.Builder().tag(Unicopia.id("insect/raw")).hunger(1).saturation(1).build(),
+
+                new Multiplier.Builder().tag(Unicopia.id("fish/rotten")).hunger(0.24F).saturation(0.25F).build(),
+                new Multiplier.Builder().tag(Unicopia.id("meat/rotten")).hunger(0.2F).saturation(0.2F).build(),
+                new Multiplier.Builder().tag(Unicopia.id("insect/rotten")).hunger(0.9F).saturation(0.9F).build(),
+
+                new Multiplier.Builder().tag(Unicopia.id("love")).hunger(1).saturation(1.5F).build()
+        ), List.of(
+                // Can eat fish, meat, insects, and love without negative effects
+                new FoodGroupEffects.Builder()
+                    .tag(Unicopia.id("fish/cooked")).tag(Unicopia.id("meat/cooked")).tag(Unicopia.id("insect/cooked"))
+                    .tag(Unicopia.id("fish/rotten")).tag(Unicopia.id("meat/rotten")).tag(Unicopia.id("insect/rotten"))
+                    .tag(Unicopia.id("fish/raw")).tag(Unicopia.id("meat/raw")).tag(Unicopia.id("insect/raw"))
+                    .tag(Unicopia.id("baked_goods")).tag(Unicopia.id("pinecone"))
+                    .tag(Unicopia.id("love")).ailment(ClearLoveSicknessAffliction.INSTANCE).build(),
+
+                new FoodGroupEffects.Builder()
+                    .tag(Unicopia.id("foraging/blinding")).tag(Unicopia.id("foraging/dangerous")).tag(Unicopia.id("foraging/edible_filling"))
+                    .tag(Unicopia.id("foraging/edible")).tag(Unicopia.id("foraging/leafy_greens")).tag(Unicopia.id("foraging/nauseating"))
+                    .tag(Unicopia.id("foraging/prickly")).tag(Unicopia.id("foraging/glowing")).tag(Unicopia.id("foraging/risky"))
+                    .tag(Unicopia.id("foraging/severely_nauseating")).tag(Unicopia.id("foraging/severely_prickly"))
+                    .tag(Unicopia.id("foraging/strengthening"))
+                    .ailment(loveSicknessEffects)
+                    .build()
+        ), Optional.empty()));
+        // Hippogriffs like fish, nuts, and seeds
+        exporter.accept(Race.HIPPOGRIFF, new DietProfile(0.5F, 0.8F, List.of(
+                bakedGoodPreference, pineconeMultiplier, seaFoodExclusions,
+
+                new Multiplier.Builder().tag(Unicopia.id("love"))
+                    .tag(Unicopia.id("insect/cooked")).tag(Unicopia.id("insect/raw")).tag(Unicopia.id("insect/rotten"))
+                    .hunger(0).saturation(0).build(),
+
+                new Multiplier.Builder().tag(Unicopia.id("fish/cooked")).hunger(1.5F).saturation(1.2F).build(),
+                new Multiplier.Builder().tag(Unicopia.id("meat/cooked")).hunger(1.9F).saturation(1.2F).build(),
+
+                new Multiplier.Builder().tag(Unicopia.id("fish/raw")).hunger(0.85F).saturation(0.95F).build(),
+                new Multiplier.Builder().tag(Unicopia.id("meat/raw")).hunger(0.75F).saturation(0.75F).build(),
+
+                new Multiplier.Builder().tag(Unicopia.id("fish/rotten")).hunger(0.24F).saturation(0.25F).build(),
+                new Multiplier.Builder().tag(Unicopia.id("meat/rotten")).hunger(0.3F).saturation(0.5F).build(),
+
+                new Multiplier.Builder().tag(Unicopia.id("nuts_and_seeds")).hunger(1.4F).saturation(1.4F).build()
+        ), List.of(
+                // Can eat fish and prickly foods without negative effect
+                new FoodGroupEffects.Builder()
+                    .tag(Unicopia.id("fish/cooked")).tag(Unicopia.id("fish/raw")).tag(Unicopia.id("fish/rotten"))
+                    .tag(Unicopia.id("foraging/prickly")).tag(Unicopia.id("foraging/severely_prickly"))
+                    .build(),
+                // Gains more health from pinecones
+                new FoodGroupEffects.Builder().tag(Unicopia.id("pinecone")).ailment(new HealingAffliction(3)).build()
+        ), Optional.empty()));
+        // Seaponies can eat seaweed, kelp, shells, and other undersea foods
+        exporter.accept(Race.SEAPONY, new DietProfile(0.5F, 0.8F, List.of(
+                new Multiplier.Builder().tag(Unicopia.id("fish/cooked")).hunger(1.5F).saturation(1.2F).build(),
+                new Multiplier.Builder().tag(Unicopia.id("fish/raw")).hunger(0.85F).saturation(0.95F).build(),
+                new Multiplier.Builder().tag(Unicopia.id("fish/rotten")).hunger(0.24F).saturation(0.25F).build(),
+                new Multiplier.Builder()
+                    .tag(Unicopia.id("sea_vegetable/raw"))
+                    .tag(Unicopia.id("sea_vegetable/cooked"))
+                    .tag(Unicopia.id("shells")).tag(Unicopia.id("special_shells"))
+                    .hunger(1).saturation(1).build()
+        ), List.of(
+                // Can eat fish without negative effect
+                new FoodGroupEffects.Builder()
+                    .tag(Unicopia.id("fish/cooked")).tag(Unicopia.id("fish/raw")).tag(Unicopia.id("fish/rotten"))
+                    .build(),
+                // Gains more health from pinecones
+                new FoodGroupEffects.Builder().tag(Unicopia.id("pinecone")).ailment(new HealingAffliction(3)).build()
+        ), Optional.empty()));
+    }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/java/com/minelittlepony/unicopia/datagen/providers/DietsProvider.java b/src/main/java/com/minelittlepony/unicopia/datagen/providers/DietsProvider.java
new file mode 100644
index 00000000..5b14e3dd
--- /dev/null
+++ b/src/main/java/com/minelittlepony/unicopia/datagen/providers/DietsProvider.java
@@ -0,0 +1,83 @@
+package com.minelittlepony.unicopia.datagen.providers;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.stream.Collectors;
+
+import com.google.gson.JsonObject;
+import com.minelittlepony.unicopia.Race;
+import com.minelittlepony.unicopia.datagen.DataCollector;
+import com.minelittlepony.unicopia.diet.DietProfile;
+import com.minelittlepony.unicopia.diet.FoodGroup;
+import com.mojang.serialization.JsonOps;
+
+import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
+import net.minecraft.data.DataOutput;
+import net.minecraft.data.DataProvider;
+import net.minecraft.data.DataWriter;
+import net.minecraft.data.server.tag.TagProvider;
+import net.minecraft.data.server.tag.TagProvider.TagLookup;
+import net.minecraft.item.Item;
+import net.minecraft.registry.RegistryKeys;
+import net.minecraft.registry.tag.TagKey;
+import net.minecraft.util.Identifier;
+
+public class DietsProvider implements DataProvider {
+    private final DataCollector dietsCollector;
+    private final DataCollector categoriesCollector;
+
+    private final CompletableFuture<TagLookup<Item>> itemTagLookup;
+
+    public DietsProvider(FabricDataOutput output, TagProvider<Item> tagProvider) {
+        this.dietsCollector = new DataCollector(output.getResolver(DataOutput.OutputType.DATA_PACK, "diet/races"));
+        this.categoriesCollector = new DataCollector(output.getResolver(DataOutput.OutputType.DATA_PACK, "diet/food_groups"));
+        itemTagLookup = tagProvider.getTagLookupFuture();
+    }
+
+    @Override
+    public String getName() {
+        return "Diets";
+    }
+
+    @Override
+    public CompletableFuture<?> run(DataWriter writer) {
+        return itemTagLookup.thenCompose(tagLookup -> {
+            var diets = categoriesCollector.prime();
+            Map<Identifier, Set<Identifier>> keyToGroupId = new HashMap<>();
+            new FoodGroupsGenerator().generate((id, builder) -> {
+                var attributes = builder.build();
+                attributes.tags().forEach(key -> {
+                    if (!tagLookup.contains(TagKey.of(RegistryKeys.ITEM, key.id()))) {
+                        throw new IllegalArgumentException("Food group " + id + " references unknown item tag " + key.id());
+                    }
+                    keyToGroupId.computeIfAbsent(key.id(), i -> new HashSet<>()).add(id);
+                });
+                diets.accept(id, () -> FoodGroup.CODEC.encode(attributes, JsonOps.INSTANCE, new JsonObject()).result().get());
+            });
+            var profiles = dietsCollector.prime();
+            new DietProfileGenerator().generate((race, profile) -> {
+                Identifier id = Race.REGISTRY.getId(race);
+                StringBuilder issues = new StringBuilder();
+                profile.validate(issue -> {
+                    issues.append(System.lineSeparator()).append(issue);
+                }, categoriesCollector::isDefined);
+                if (!issues.isEmpty()) {
+                    throw new IllegalArgumentException("Diet profile " + id + " failed validation: " + issues.toString());
+                }
+                profiles.accept(id, () -> DietProfile.CODEC.encode(profile, JsonOps.INSTANCE, new JsonObject()).result().get());
+            });
+            keyToGroupId.forEach((tag, groups) -> {
+               if (groups.size() > 1) {
+                   throw new IllegalArgumentException("Multiple groups referenced the same tag " + tag + " held by "
+                           + groups.stream().map(Identifier::toString).collect(Collectors.joining())
+                   );
+               }
+            });
+
+            return CompletableFuture.allOf(categoriesCollector.upload(writer), dietsCollector.upload(writer));
+        });
+    }
+}
diff --git a/src/main/java/com/minelittlepony/unicopia/datagen/providers/FoodGroupsGenerator.java b/src/main/java/com/minelittlepony/unicopia/datagen/providers/FoodGroupsGenerator.java
new file mode 100644
index 00000000..3959da20
--- /dev/null
+++ b/src/main/java/com/minelittlepony/unicopia/datagen/providers/FoodGroupsGenerator.java
@@ -0,0 +1,115 @@
+package com.minelittlepony.unicopia.datagen.providers;
+
+import java.util.List;
+import java.util.function.BiConsumer;
+import com.minelittlepony.unicopia.UConventionalTags;
+import com.minelittlepony.unicopia.UTags;
+import com.minelittlepony.unicopia.Unicopia;
+import com.minelittlepony.unicopia.diet.FoodGroupEffects;
+import com.minelittlepony.unicopia.diet.affliction.Affliction;
+import com.minelittlepony.unicopia.diet.affliction.CompoundAffliction;
+import com.minelittlepony.unicopia.diet.affliction.HealingAffliction;
+import com.minelittlepony.unicopia.diet.affliction.LoseHungerAffliction;
+import com.minelittlepony.unicopia.diet.affliction.Range;
+import com.minelittlepony.unicopia.diet.affliction.StatusEffectAffliction;
+import com.minelittlepony.unicopia.entity.effect.UEffects;
+import com.minelittlepony.unicopia.item.UFoodComponents;
+
+import net.minecraft.entity.effect.StatusEffects;
+import net.minecraft.item.FoodComponent;
+import net.minecraft.item.FoodComponents;
+import net.minecraft.item.Item;
+import net.minecraft.registry.tag.ItemTags;
+import net.minecraft.registry.tag.TagKey;
+import net.minecraft.util.Identifier;
+
+public class FoodGroupsGenerator {
+    public void generate(BiConsumer<Identifier, FoodGroupEffects.Builder> exporter) {
+        exporter.accept(Unicopia.id("baked_goods"), new FoodGroupEffects.Builder().tag(UTags.Items.BAKED_GOODS).food(FoodComponents.BREAD));
+        exporter.accept(Unicopia.id("bat_ponys_delight"), new FoodGroupEffects.Builder().tag(UConventionalTags.Items.MANGOES).food(UFoodComponents.MANGO));
+        exporter.accept(Unicopia.id("candy"), new FoodGroupEffects.Builder().tag(UConventionalTags.Items.CANDY).food(UFoodComponents.CANDY));
+        exporter.accept(Unicopia.id("desserts"), new FoodGroupEffects.Builder().tag(UConventionalTags.Items.DESSERTS).food(FoodComponents.COOKIE));
+        exporter.accept(Unicopia.id("fruit"), new FoodGroupEffects.Builder().tag(UConventionalTags.Items.FRUITS).food(UFoodComponents.BANANA));
+        exporter.accept(Unicopia.id("rocks"), new FoodGroupEffects.Builder().tag(UConventionalTags.Items.ROCKS).tag(UTags.Items.ROCK_STEWS).food(FoodComponents.MUSHROOM_STEW));
+        exporter.accept(Unicopia.id("shells"), new FoodGroupEffects.Builder().tag(UTags.Items.SHELLS).food(UFoodComponents.SHELL));
+        exporter.accept(Unicopia.id("special_shells"), new FoodGroupEffects.Builder().tag(UTags.Items.SPECIAL_SHELLS).food(UFoodComponents.SHELLY));
+        exporter.accept(Unicopia.id("love"), new FoodGroupEffects.Builder().tag(UTags.Items.CONTAINER_WITH_LOVE).food(UFoodComponents.LOVE_MUG).ailment(new CompoundAffliction(List.<Affliction>of(
+                new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(50), Range.of(2), 0),
+                new LoseHungerAffliction(0.5F)
+        ))));
+        exporter.accept(Unicopia.id("nuts_and_seeds"), new FoodGroupEffects.Builder()
+                .tag(UConventionalTags.Items.GRAIN).tag(UConventionalTags.Items.NUTS).tag(UConventionalTags.Items.SEEDS)
+                .food(UFoodComponents.BANANA)
+        );
+        exporter.accept(Unicopia.id("pinecone"), new FoodGroupEffects.Builder().tag(UConventionalTags.Items.PINECONES).food(UFoodComponents.PINECONE).ailment(new HealingAffliction(1)));
+
+        provideMeatCategory("fish",
+                UConventionalTags.Items.COOKED_FISH, UConventionalTags.Items.RAW_FISH, UConventionalTags.Items.ROTTEN_FISH,
+                FoodComponents.COOKED_COD, FoodComponents.COD, FoodComponents.ROTTEN_FLESH, exporter);
+        provideMeatCategory("meat",
+                UConventionalTags.Items.COOKED_MEAT, UConventionalTags.Items.RAW_MEAT, UConventionalTags.Items.ROTTEN_MEAT,
+                FoodComponents.COOKED_BEEF, FoodComponents.BEEF, FoodComponents.ROTTEN_FLESH, exporter);
+        provideMeatCategory("insect",
+                UConventionalTags.Items.COOKED_INSECT, UConventionalTags.Items.RAW_INSECT, UConventionalTags.Items.ROTTEN_INSECT,
+                FoodComponents.COOKED_BEEF, FoodComponents.BEEF, FoodComponents.ROTTEN_FLESH, exporter);
+        provideVegetableCategory("sea_vegetable",
+                UTags.Items.HIGH_QUALITY_SEA_VEGETABLES, UTags.Items.LOW_QUALITY_SEA_VEGETABLES,
+                FoodComponents.COOKED_BEEF, FoodComponents.BEEF, exporter);
+
+        exporter.accept(Unicopia.id("foraging/blinding"), new FoodGroupEffects.Builder().tag(UTags.Items.FORAGE_BLINDING).food(4, 0.2F).ailment(CompoundAffliction.of(
+                new StatusEffectAffliction(StatusEffects.BLINDNESS, Range.of(30), Range.of(0), 50),
+                new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(100), Range.of(2), 12)
+        )));
+        exporter.accept(Unicopia.id("foraging/dangerous"), new FoodGroupEffects.Builder().tag(UTags.Items.FORAGE_DANGEROUS).food(3, 0.3F).ailment(new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(250), Range.of(2), 4)));
+        exporter.accept(Unicopia.id("foraging/edible_filling"), new FoodGroupEffects.Builder().tag(UTags.Items.FORAGE_FILLING).food(17, 0.6F));
+        exporter.accept(Unicopia.id("foraging/edible"), new FoodGroupEffects.Builder().tag(UTags.Items.FORAGE_SAFE).food(2, 1));
+        exporter.accept(Unicopia.id("foraging/leafy_greens"), new FoodGroupEffects.Builder().tag(ItemTags.LEAVES).food(1, 1.4F));
+        exporter.accept(Unicopia.id("foraging/nauseating"), new FoodGroupEffects.Builder().tag(UTags.Items.FORAGE_NAUSEATING).food(5, 0.5F).ailment(CompoundAffliction.of(
+                new StatusEffectAffliction(StatusEffects.WEAKNESS, Range.of(200), Range.of(1), 30),
+                new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(200), Range.of(2), 0)
+        )));
+        exporter.accept(Unicopia.id("foraging/prickly"), new FoodGroupEffects.Builder().tag(UTags.Items.FORAGE_PRICKLY).food(0, 1.5F).ailment(CompoundAffliction.of(
+                new StatusEffectAffliction(StatusEffects.INSTANT_DAMAGE, Range.of(1), Range.of(0), 30)
+        )));
+        exporter.accept(Unicopia.id("foraging/glowing"), new FoodGroupEffects.Builder().tag(UTags.Items.FORAGE_GLOWING).food(1, 1.6F).ailment(CompoundAffliction.of(
+                new StatusEffectAffliction(StatusEffects.GLOWING, Range.of(30), Range.of(0), 30),
+                new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(100), Range.of(2), 0)
+        )));
+        exporter.accept(Unicopia.id("foraging/risky"), new FoodGroupEffects.Builder().tag(UTags.Items.FORAGE_RISKY).food(9, 1.1F).ailment(new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(100), Range.of(2), 80)));
+        exporter.accept(Unicopia.id("foraging/severely_nauseating"), new FoodGroupEffects.Builder().tag(UTags.Items.FORAGE_SEVERE_NAUSEATING).food(3, 0.9F).ailment(CompoundAffliction.of(
+                new StatusEffectAffliction(StatusEffects.WEAKNESS, Range.of(200), Range.of(1), 0),
+                new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(100), Range.of(2), 80)
+        )));
+        exporter.accept(Unicopia.id("foraging/severely_prickly"), new FoodGroupEffects.Builder().tag(UTags.Items.FORAGE_SEVERE_PRICKLY).food(2, 0.9F).ailment(CompoundAffliction.of(
+                new StatusEffectAffliction(StatusEffects.INSTANT_DAMAGE, Range.of(1), Range.of(0), 0),
+                new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(100), Range.of(2), 80)
+        )));
+        exporter.accept(Unicopia.id("foraging/strengthening"), new FoodGroupEffects.Builder().tag(UTags.Items.FORAGE_STRENGHENING).food(4, 0.2F).ailment(CompoundAffliction.of(
+                new StatusEffectAffliction(StatusEffects.STRENGTH, Range.of(1300), Range.of(0), 0),
+                new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(100), Range.of(2), 70)
+        )));
+    }
+
+    private void provideMeatCategory(String name,
+            TagKey<Item> cookedTag, TagKey<Item> rawTag, TagKey<Item> rottenTag,
+            FoodComponent cooked, FoodComponent raw, FoodComponent rotten,
+            BiConsumer<Identifier, FoodGroupEffects.Builder> exporter) {
+        exporter.accept(Unicopia.id(name + "/cooked"), new FoodGroupEffects.Builder().tag(cookedTag).food(cooked).ailment(new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(100), Range.of(2), 25)));
+        exporter.accept(Unicopia.id(name + "/raw"), new FoodGroupEffects.Builder().tag(rawTag).food(raw).ailment(CompoundAffliction.of(
+                new StatusEffectAffliction(StatusEffects.POISON, Range.of(45), Range.of(2), 80),
+                new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(100), Range.of(2), 65)
+        )));
+        exporter.accept(Unicopia.id(name + "/rotten"), new FoodGroupEffects.Builder().tag(rottenTag).food(rotten).ailment(CompoundAffliction.of(
+                new StatusEffectAffliction(StatusEffects.POISON, Range.of(45), Range.of(2), 80),
+                new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(100), Range.of(2), 95)
+        )));
+    }
+
+    private void provideVegetableCategory(String name,
+            TagKey<Item> cookedTag, TagKey<Item> rawTag,
+            FoodComponent cooked, FoodComponent raw,
+            BiConsumer<Identifier, FoodGroupEffects.Builder> exporter) {
+        exporter.accept(Unicopia.id(name + "/cooked"), new FoodGroupEffects.Builder().tag(cookedTag).food(cooked));
+        exporter.accept(Unicopia.id(name + "/raw"), new FoodGroupEffects.Builder().tag(rawTag).food(raw));
+    }
+}
diff --git a/src/main/java/com/minelittlepony/unicopia/datagen/providers/SeasonsGrowthRatesProvider.java b/src/main/java/com/minelittlepony/unicopia/datagen/providers/SeasonsGrowthRatesProvider.java
index 186c0685..d802bbc7 100644
--- a/src/main/java/com/minelittlepony/unicopia/datagen/providers/SeasonsGrowthRatesProvider.java
+++ b/src/main/java/com/minelittlepony/unicopia/datagen/providers/SeasonsGrowthRatesProvider.java
@@ -12,17 +12,16 @@ import com.minelittlepony.unicopia.server.world.UTreeGen;
 import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
 import net.minecraft.block.Block;
 import net.minecraft.data.DataOutput;
-import net.minecraft.data.DataOutput.PathResolver;
 import net.minecraft.registry.Registries;
 import net.minecraft.data.DataProvider;
 import net.minecraft.data.DataWriter;
 
 public class SeasonsGrowthRatesProvider implements DataProvider {
 
-    private final PathResolver pathResolver;
+    private final DataCollector collectedData;
 
     public SeasonsGrowthRatesProvider(FabricDataOutput output) {
-        this.pathResolver = output.getResolver(DataOutput.OutputType.DATA_PACK, "seasons/crop");
+        this.collectedData = new DataCollector(output.getResolver(DataOutput.OutputType.DATA_PACK, "seasons/crop"));
     }
 
     @Override
@@ -32,7 +31,6 @@ public class SeasonsGrowthRatesProvider implements DataProvider {
 
     @Override
     public CompletableFuture<?> run(DataWriter writer) {
-        DataCollector collectedData = new DataCollector(pathResolver);
         var exporter = collectedData.prime();
         generate((block, crop) -> {
             exporter.accept(Registries.BLOCK.getId(block), crop::toJson);
diff --git a/src/main/java/com/minelittlepony/unicopia/datagen/providers/UAdvancementsProvider.java b/src/main/java/com/minelittlepony/unicopia/datagen/providers/UAdvancementsProvider.java
index e0c2c349..de390bfb 100644
--- a/src/main/java/com/minelittlepony/unicopia/datagen/providers/UAdvancementsProvider.java
+++ b/src/main/java/com/minelittlepony/unicopia/datagen/providers/UAdvancementsProvider.java
@@ -73,27 +73,28 @@ public class UAdvancementsProvider extends FabricAdvancementProvider {
 
     private void generateEarthTribeAdvancementsTree(Consumer<Advancement> consumer, AdvancementDisplayBuilder.Parent parent) {
         parent.child(UItems.ROCK).criterion("has_rock", hasItems(UItems.ROCK)).build(consumer, "born_on_a_rock_farm").children(p -> {
-            p.child(UItems.PEBBLES).criterion("killed_entity_with_rock", killWithItems(UTags.FROM_ROCKS)).build(consumer, "sticks_and_stones");
+            p.child(UItems.PEBBLES).criterion("killed_entity_with_rock", killWithItems(UTags.DamageTypes.FROM_ROCKS)).build(consumer, "sticks_and_stones");
             p.child(UItems.WEIRD_ROCK).hidden().criterion("has_rock", hasItems(UItems.WEIRD_ROCK)).build(consumer, "thats_unusual");
         });
 
+        parent.child(UItems.FRIED_AXOLOTL).criterion("eaten_axolotl", ConsumeItemCriterion.Conditions.item(UItems.FRIED_AXOLOTL)).build(consumer, "tastes_like_chicken");
         parent.child(UItems.OATS).criterion("has_oats", hasItems(UItems.OATS)).build(consumer, "oats_so_easy");
         parent.child(Items.HAY_BLOCK).criterion("eat_hay", ConsumeItemCriterion.Conditions.item(Items.HAY_BLOCK)).build(consumer, "what_the_hay");
-        parent.child(UItems.COPPER_HORSE_SHOE).criterion("has_horseshoe", hasItems(UTags.HORSE_SHOES)).build(consumer, "blacksmith").children(p -> {
+        parent.child(UItems.COPPER_HORSE_SHOE).criterion("has_horseshoe", hasItems(UTags.Items.HORSE_SHOES)).build(consumer, "blacksmith").children(p -> {
             p.child(UItems.IRON_HORSE_SHOE).criterion("has_iron_horseshoe", hasItems(UItems.IRON_HORSE_SHOE)).build(consumer, "change_of_shoes")
              .child(UItems.GOLDEN_HORSE_SHOE).criterion("has_gold_horseshoe", hasItems(UItems.GOLDEN_HORSE_SHOE)).build(consumer, "fashionably_expensive")
              .child(UItems.NETHERITE_HORSE_SHOE).criterion("has_netherite_horseshoe", hasItems(UItems.NETHERITE_HORSE_SHOE)).build(consumer, "overkill");
-            p.child(UItems.IRON_HORSE_SHOE).hidden().frame(AdvancementFrame.CHALLENGE).criterion("killed_entity_with_horseshoe", killWithItems(UTags.FROM_HORSESHOES)).build(consumer, "dead_ringer");
+            p.child(UItems.IRON_HORSE_SHOE).hidden().frame(AdvancementFrame.CHALLENGE).criterion("killed_entity_with_horseshoe", killWithItems(UTags.DamageTypes.FROM_HORSESHOES)).build(consumer, "dead_ringer");
         });
         parent.child(UItems.PINECONE).frame(AdvancementFrame.CHALLENGE).criterion("eat_pinecone", ConsumeItemCriterion.Conditions.item(UItems.PINECONE)).build(consumer, "eat_pinecone");
-        parent.child(UItems.OAK_BASKET).doNotAnnounce().criterion("has_basket", hasItems(UTags.BASKETS)).build(consumer, "basket_case")
+        parent.child(UItems.OAK_BASKET).doNotAnnounce().criterion("has_basket", hasItems(UTags.Items.BASKETS)).build(consumer, "basket_case")
             .child(Items.LANTERN).criterion("construct_balloon", CustomEventCriterion.create("construct_balloon")).build(consumer, "aeronaut")
             .child(UItems.GIANT_BALLOON).announce().frame(AdvancementFrame.CHALLENGE).criterion("ride_balloon", CustomEventCriterion.create("ride_balloon")).build(consumer, "travelling_in_style");
         parent.child(UItems.MUFFIN).hidden().criterion("has_muffin", hasItems(UItems.MUFFIN)).build(consumer, "baked_bads");
         parent.child(UItems.HORSE_SHOE_FRIES).criterion("has_horse_shoe_fries", hasItems(UItems.HORSE_SHOE_FRIES)).build(consumer, "lucky");
         parent.child(UItems.TOAST).criterion("has_toast", hasItems(UItems.TOAST)).build(consumer, "toast")
             .child(UItems.BURNED_TOAST).hidden().criterion("has_burned_toast", hasItems(UItems.BURNED_TOAST)).build(consumer, "burn_toast");
-        parent.child(UItems.GREEN_APPLE).criterion("has_apple", hasItems(UTags.FRESH_APPLES)).build(consumer, "apple_route").children(p -> {
+        parent.child(UItems.GREEN_APPLE).criterion("has_apple", hasItems(UTags.Items.FRESH_APPLES)).build(consumer, "apple_route").children(p -> {
             p.child(UItems.SWEET_APPLE).criterion("has_all_apples", hasItems(Items.APPLE, UItems.GREEN_APPLE, UItems.SWEET_APPLE, UItems.SOUR_APPLE, UItems.ROTTEN_APPLE, UItems.ZAP_APPLE, UItems.COOKED_ZAP_APPLE, Items.GOLDEN_APPLE)).build(consumer, "sweet_apple_acres");
             p.child(UItems.ZAP_BULB).criterion("has_zap_apple", hasItems(UItems.ZAP_APPLE)).build(consumer, "trick_apple").children(pp -> {
                 pp.child(UItems.ZAP_APPLE).hidden().criterion("eat_trick_apple", CustomEventCriterion.createFlying("eat_trick_apple")).build(consumer, "eat_trick_apple");
@@ -110,7 +111,7 @@ public class UAdvancementsProvider extends FabricAdvancementProvider {
         parent.child(Items.GLASS_PANE).criterion("break_window", CustomEventCriterion.createFlying("break_window")).rewards(AdvancementRewards.Builder.experience(10)).build(consumer, "rainbow_crash");
         parent.child(UItems.PEGASUS_BADGE).criterion("fly_through_the_pain", CustomEventCriterion.createFlying("second_wind")).rewards(AdvancementRewards.Builder.experience(10)).build(consumer, "second_wind");
         parent.child(UItems.EMPTY_JAR).criterion("has_empty_jar", hasItems(UItems.EMPTY_JAR)).build(consumer, "jar")
-            .child(UItems.RAIN_CLOUD_JAR).criterion("has_cloud_jar", hasItems(UTags.CLOUD_JARS)).rewards(AdvancementRewards.Builder.experience(55)).build(consumer, "gotcha");
+            .child(UItems.RAIN_CLOUD_JAR).criterion("has_cloud_jar", hasItems(UTags.Items.CLOUD_JARS)).rewards(AdvancementRewards.Builder.experience(55)).build(consumer, "gotcha");
         parent.child(UItems.LIGHTNING_JAR).frame(AdvancementFrame.CHALLENGE).criterion("lightning_strike", CustomEventCriterion.createFlying("lightning_strike")).rewards(AdvancementRewards.Builder.experience(30)).build(consumer, "mid_flight_interruption").children(p -> {
             p.child(UItems.LIGHTNING_JAR).hidden().frame(AdvancementFrame.CHALLENGE).apply(d -> applyLightningBugCriterions(d, RacePredicate.of(Set.of(Race.CHANGELING), Set.of()), 10, 90)).build(consumer, "lightning_bug");
             p.child(UItems.LIGHTNING_JAR).hidden().frame(AdvancementFrame.CHALLENGE).apply(d -> applyLightningBugCriterions(d, RacePredicate.of(Set.of(), Set.of(Race.CHANGELING)), 10, 90)).build(consumer, "wonder_bolt");
@@ -145,6 +146,7 @@ public class UAdvancementsProvider extends FabricAdvancementProvider {
 
     private void generateUnicornTribeAdvancementsTree(Consumer<Advancement> consumer, AdvancementDisplayBuilder.Parent parent) {
         parent.child(UItems.SPELLBOOK).criterion("has_spellbook", hasItems(UItems.SPELLBOOK)).build(consumer, "books").children(p -> {
+            // TODO:
             //ItemPredicate bookPredicate = ItemPredicate.Builder.create().tag(ItemTags.BOOKSHELF_BOOKS).build();
             //p.child(Items.BOOK).hidden().frame(AdvancementFrame.CHALLENGE).criterion("has_books", InventoryChangedCriterion.Conditions.items(IntStream.range(0, 9 * 4).mapToObj(i -> bookPredicate).toArray(ItemPredicate[]::new))).build(consumer, "books_books_books");
             p.child(UItems.CRYSTAL_SHARD).criterion("has_shard", hasItems(UItems.CRYSTAL_SHARD)).build(consumer, "crystaline").children(pp -> {
@@ -255,7 +257,7 @@ public class UAdvancementsProvider extends FabricAdvancementProvider {
     static CriterionConditions dingCelestia(Set<Race> includeTribes, Set<Race> excludeTribes) {
         return new SendViaDragonBreathScrollCriterion.Conditions(
                 LootContextPredicate.EMPTY,
-                ItemPredicate.Builder.create().tag(UTags.IS_DELIVERED_AGGRESSIVELY).build(), false,
+                ItemPredicate.Builder.create().tag(UTags.Items.IS_DELIVERED_AGGRESSIVELY).build(), false,
                 Optional.of("princess celestia"),
                 TriState.FALSE,
                 Optional.of("dings_on_celestias_head"),
diff --git a/src/main/java/com/minelittlepony/unicopia/datagen/providers/UBlockStateModelGenerator.java b/src/main/java/com/minelittlepony/unicopia/datagen/providers/UBlockStateModelGenerator.java
index 048c3ad6..40fe766c 100644
--- a/src/main/java/com/minelittlepony/unicopia/datagen/providers/UBlockStateModelGenerator.java
+++ b/src/main/java/com/minelittlepony/unicopia/datagen/providers/UBlockStateModelGenerator.java
@@ -16,6 +16,7 @@ import com.minelittlepony.unicopia.block.ShellsBlock;
 import com.minelittlepony.unicopia.block.SlimePustuleBlock;
 import com.minelittlepony.unicopia.block.UBlocks;
 import com.minelittlepony.unicopia.block.zap.ZapAppleLeavesBlock;
+import com.minelittlepony.unicopia.datagen.Datagen;
 import com.minelittlepony.unicopia.datagen.UBlockFamilies;
 import com.minelittlepony.unicopia.server.world.Tree;
 
@@ -41,7 +42,6 @@ import net.minecraft.data.client.When;
 import net.minecraft.item.Item;
 import net.minecraft.item.Items;
 import net.minecraft.registry.Registries;
-import net.minecraft.registry.Registry;
 import net.minecraft.state.property.BooleanProperty;
 import net.minecraft.state.property.EnumProperty;
 import net.minecraft.state.property.Properties;
@@ -113,7 +113,7 @@ public class UBlockStateModelGenerator extends BlockStateModelGenerator {
         registerHiveBlock(UBlocks.HIVE);
         registerRotated(UBlocks.CHITIN_SPIKES, BlockModels.SPIKES);
         registerHull(UBlocks.CHISELLED_CHITIN_HULL, UBlocks.CHITIN, UBlocks.CHISELLED_CHITIN);
-        registerParentedItemModel(UBlocks.SLIME_PUSTULE, ModelIds.getBlockSubModelId(UBlocks.SLIME_PUSTULE, "_pod"));
+        registerItemModel(UBlocks.SLIME_PUSTULE.asItem());
         blockStateCollector.accept(VariantsBlockStateSupplier.create(UBlocks.SLIME_PUSTULE)
                 .coordinate(BlockStateVariantMap.create(SlimePustuleBlock.SHAPE)
                 .register(state -> BlockStateVariant.create().put(MODEL, ModelIds.getBlockSubModelId(UBlocks.SLIME_PUSTULE, "_" + state.asString())))));
@@ -176,7 +176,7 @@ public class UBlockStateModelGenerator extends BlockStateModelGenerator {
         registerWithStages(UBlocks.FROSTED_OBSIDIAN, Properties.AGE_3, BlockModels.CUBE_ALL, 0, 1, 2, 3);
         registerWithStagesBuiltinModels(UBlocks.ROCKS, Properties.AGE_7, 0, 1, 2, 3, 4, 5, 6, 7);
         registerWithStagesBuiltinModels(UBlocks.MYSTERIOUS_EGG, PileBlock.COUNT, 1, 2, 3);
-        excludeFromSimpleItemModelGeneration(UBlocks.MYSTERIOUS_EGG);
+        registerItemModel(UBlocks.MYSTERIOUS_EGG.asItem());
         FireModels.registerSoulFire(this, UBlocks.SPECTRAL_FIRE, Blocks.SOUL_FIRE);
 
         blockStateCollector.accept(createSingletonBlockState(UBlocks.JAR, BlockModels.TEMPLATE_JAR));
@@ -429,9 +429,7 @@ public class UBlockStateModelGenerator extends BlockStateModelGenerator {
         Identifier side = baseBlockId.withPath(p -> "block/" + p + "_side");
         TextureMap textures = new TextureMap().put(TOP, top).put(SIDE, side);
 
-        MultipartBlockStateSupplier supplier = MultipartBlockStateSupplier.create(Registries.BLOCK.getOrEmpty(blockId).orElseGet(() -> {
-            return Registry.register(Registries.BLOCK, blockId, new EdibleBlock(blockId, blockId, false));
-        }));
+        MultipartBlockStateSupplier supplier = MultipartBlockStateSupplier.create(Datagen.getOrCreateBaleBlock(blockId));
         Map<Integer, Identifier> uploadedModels = new HashMap<>();
 
         for (Direction.Axis axis : Direction.Axis.VALUES) {
diff --git a/src/main/java/com/minelittlepony/unicopia/datagen/providers/UItemTagProvider.java b/src/main/java/com/minelittlepony/unicopia/datagen/providers/UItemTagProvider.java
deleted file mode 100644
index 65c5d92a..00000000
--- a/src/main/java/com/minelittlepony/unicopia/datagen/providers/UItemTagProvider.java
+++ /dev/null
@@ -1,190 +0,0 @@
-package com.minelittlepony.unicopia.datagen.providers;
-
-import java.util.Objects;
-import java.util.concurrent.CompletableFuture;
-
-import com.minelittlepony.unicopia.Race;
-import com.minelittlepony.unicopia.UConventionalTags;
-import com.minelittlepony.unicopia.UTags;
-import com.minelittlepony.unicopia.block.UBlocks;
-import com.minelittlepony.unicopia.datagen.Datagen;
-import com.minelittlepony.unicopia.datagen.ItemFamilies;
-import com.minelittlepony.unicopia.item.BedsheetsItem;
-import com.minelittlepony.unicopia.item.UItems;
-
-import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
-import net.fabricmc.fabric.api.datagen.v1.provider.FabricTagProvider;
-import net.fabricmc.fabric.api.tag.convention.v1.ConventionalItemTags;
-import net.minecraft.block.Block;
-import net.minecraft.item.Item;
-import net.minecraft.item.Items;
-import net.minecraft.registry.Registries;
-import net.minecraft.registry.RegistryKeys;
-import net.minecraft.registry.RegistryWrapper;
-import net.minecraft.registry.RegistryWrapper.WrapperLookup;
-import net.minecraft.registry.tag.BlockTags;
-import net.minecraft.registry.tag.ItemTags;
-import net.minecraft.registry.tag.TagBuilder;
-import net.minecraft.registry.tag.TagKey;
-import net.minecraft.util.Identifier;
-
-public class UItemTagProvider extends FabricTagProvider.ItemTagProvider {
-
-
-    private final UBlockTagProvider blockTagProvider;
-
-    public UItemTagProvider(FabricDataOutput output, CompletableFuture<RegistryWrapper.WrapperLookup> registriesFuture, UBlockTagProvider blockTagProvider) {
-        super(output, registriesFuture, blockTagProvider);
-        this.blockTagProvider = blockTagProvider;
-    }
-
-    @Override
-    public void copy(TagKey<Block> blockTag, TagKey<Item> itemTag) {
-        TagBuilder blockTagBuilder = Objects.requireNonNull(blockTagProvider, "Pass Block tag provider via constructor to use copy").getTagBuilder(blockTag);
-        TagBuilder itemTagBuilder = getTagBuilder(itemTag);
-        blockTagBuilder.build().forEach(entry -> {
-            if (entry.canAdd(Registries.ITEM::containsId, tagId -> getTagBuilder(TagKey.of(RegistryKeys.ITEM, tagId)) != null)) {
-                itemTagBuilder.add(entry);
-            } else {
-                Datagen.LOGGER.warn("Cannot copy missing entry {} to item tag {}", entry, itemTag.id());
-            }
-        });
-    }
-
-    @Override
-    protected void configure(WrapperLookup arg) {
-        copyBlockTags();
-        exportConventionalTags();
-        getOrCreateTagBuilder(ItemTags.BOOKSHELF_BOOKS).add(UItems.SPELLBOOK);
-        getOrCreateTagBuilder(ItemTags.BEDS).add(UItems.CLOTH_BED, UItems.CLOUD_BED);
-
-        getOrCreateTagBuilder(ItemTags.CHEST_BOATS).add(UItems.PALM_CHEST_BOAT);
-        getOrCreateTagBuilder(ItemTags.BOATS).add(UItems.PALM_BOAT);
-        getOrCreateTagBuilder(ItemTags.MUSIC_DISCS).add(ItemFamilies.MUSIC_DISCS);
-        getOrCreateTagBuilder(ItemTags.CREEPER_DROP_MUSIC_DISCS).add(UItems.MUSIC_DISC_CRUSADE, UItems.MUSIC_DISC_FUNK, UItems.MUSIC_DISC_PET, UItems.MUSIC_DISC_POPULAR);
-
-        getOrCreateTagBuilder(ItemTags.SIGNS).add(UBlocks.PALM_SIGN.asItem());
-        getOrCreateTagBuilder(ItemTags.HANGING_SIGNS).add(UBlocks.PALM_HANGING_SIGN.asItem());
-
-        getOrCreateTagBuilder(UTags.HORSE_SHOES).add(ItemFamilies.HORSE_SHOES);
-        getOrCreateTagBuilder(UTags.POLEARMS).add(ItemFamilies.POLEARMS);
-
-        getOrCreateTagBuilder(ItemTags.TOOLS).addTag(UTags.HORSE_SHOES).addTag(UTags.POLEARMS);
-
-        getOrCreateTagBuilder(UTags.BASKETS).add(ItemFamilies.BASKETS);
-        getOrCreateTagBuilder(UTags.BADGES).add(Race.REGISTRY.stream()
-                .map(race -> race.getId().withPath(p -> p + "_badge"))
-                .flatMap(id -> Registries.ITEM.getOrEmpty(id).stream())
-                .toArray(Item[]::new));
-        getOrCreateTagBuilder(UTags.WOOL_BED_SHEETS).add(BedsheetsItem.ITEMS.values().stream().filter(sheet -> sheet != UItems.KELP_BED_SHEETS).toArray(Item[]::new));
-        getOrCreateTagBuilder(UTags.BED_SHEETS).forceAddTag(UTags.WOOL_BED_SHEETS).add(UItems.KELP_BED_SHEETS);
-        getOrCreateTagBuilder(UTags.APPLE_SEEDS).add(UItems.GREEN_APPLE_SEEDS, UItems.SWEET_APPLE_SEEDS, UItems.SOUR_APPLE_SEEDS);
-        getOrCreateTagBuilder(UTags.MAGIC_FEATHERS).add(UItems.PEGASUS_FEATHER, UItems.GRYPHON_FEATHER);
-        getOrCreateTagBuilder(UTags.FRESH_APPLES).add(Items.APPLE, UItems.GREEN_APPLE, UItems.SWEET_APPLE, UItems.SOUR_APPLE);
-        getOrCreateTagBuilder(UTags.CLOUD_JARS).add(UItems.RAIN_CLOUD_JAR, UItems.STORM_CLOUD_JAR);
-        getOrCreateTagBuilder(UTags.PIES).add(UItems.APPLE_PIE, UItems.APPLE_PIE_HOOF);
-
-        // technical tags
-        getOrCreateTagBuilder(ItemTags.VILLAGER_PLANTABLE_SEEDS).addTag(UTags.APPLE_SEEDS);
-        getOrCreateTagBuilder(UTags.CAN_CUT_PIE).forceAddTag(ConventionalItemTags.SHEARS).addOptionalTag(UConventionalTags.TOOL_KNIVES);
-        getOrCreateTagBuilder(UTags.COOLS_OFF_KIRINS).add(Items.MELON_SLICE, UItems.JUICE).forceAddTag(ConventionalItemTags.WATER_BUCKETS);
-        getOrCreateTagBuilder(UTags.FALLS_SLOWLY).add(Items.FEATHER, UItems.CLOUD_LUMP).forceAddTag(UTags.MAGIC_FEATHERS);
-        getOrCreateTagBuilder(UTags.IS_DELIVERED_AGGRESSIVELY).forceAddTag(ItemTags.ANVIL);
-        getOrCreateTagBuilder(UTags.SPOOKED_MOB_DROPS).add(Items.BRICK);
-        getOrCreateTagBuilder(UTags.SHADES).add(
-                Items.CARVED_PUMPKIN, Items.SKELETON_SKULL, Items.WITHER_SKELETON_SKULL, Items.PLAYER_HEAD,
-                Items.ZOMBIE_HEAD, Items.CREEPER_HEAD, Items.DRAGON_HEAD, Items.PIGLIN_HEAD,
-                UItems.SUNGLASSES
-        );
-        getOrCreateTagBuilder(UTags.FLOATS_ON_CLOUDS)
-            .forceAddTag(UTags.Items.CLOUD_BEDS)
-            .forceAddTag(UTags.Items.CLOUD_SLABS)
-            .forceAddTag(UTags.Items.CLOUD_STAIRS)
-            .forceAddTag(UTags.Items.CLOUD_BLOCKS)
-            .add(UItems.CLOUD_LUMP);
-        getOrCreateTagBuilder(UTags.HAS_NO_TRAITS).add(
-                Items.AIR, Items.SPAWNER, Items.STRUCTURE_VOID, Items.STRUCTURE_BLOCK,
-                Items.COMMAND_BLOCK, Items.CHAIN_COMMAND_BLOCK, Items.REPEATING_COMMAND_BLOCK,
-                Items.LIGHT, Items.JIGSAW, Items.BARRIER, Items.BEDROCK, Items.END_PORTAL_FRAME,
-                Items.DEBUG_STICK, Items.COMMAND_BLOCK_MINECART,
-                UItems.PLUNDER_VINE
-        ).forceAddTag(UTags.BADGES);
-        getOrCreateTagBuilder(UTags.LOOT_BUG_HIGH_VALUE_DROPS).add(
-                    Items.DIAMOND, Items.GOLDEN_APPLE, Items.GOLDEN_CARROT,
-                    Items.GOLDEN_HELMET, Items.GOLDEN_BOOTS, Items.GOLDEN_LEGGINGS, Items.GOLDEN_CHESTPLATE,
-                    Items.GOLDEN_HORSE_ARMOR,
-                    Items.GOLDEN_PICKAXE, Items.GOLDEN_SHOVEL, Items.GOLDEN_AXE, Items.GOLDEN_SWORD, Items.GOLDEN_HOE,
-                    UItems.GOLDEN_HORSE_SHOE, UItems.GOLDEN_POLEARM, UItems.GOLDEN_FEATHER, UItems.GOLDEN_WING,
-                    UItems.GOLDEN_OAK_SEEDS
-            ).forceAddTag(ConventionalItemTags.NUGGETS)
-            .forceAddTag(ConventionalItemTags.GOLD_INGOTS).forceAddTag(ConventionalItemTags.RAW_GOLD_ORES).forceAddTag(ConventionalItemTags.RAW_GOLD_BLOCKS)
-            .addOptionalTag(new Identifier("farmersdelight:golden_knife"));
-
-        exportFarmersDelightItems();
-    }
-
-    private void copyBlockTags() {
-        copy(BlockTags.LEAVES, ItemTags.LEAVES);
-        copy(BlockTags.LOGS_THAT_BURN, ItemTags.LOGS_THAT_BURN);
-        copy(BlockTags.LOGS, ItemTags.LOGS);
-        copy(BlockTags.PLANKS, ItemTags.PLANKS);
-        copy(BlockTags.WOODEN_BUTTONS, ItemTags.WOODEN_BUTTONS);
-        copy(BlockTags.WOODEN_DOORS, ItemTags.WOODEN_DOORS);
-        copy(BlockTags.FENCE_GATES, ItemTags.FENCE_GATES);
-        copy(BlockTags.WOODEN_FENCES, ItemTags.WOODEN_FENCES);
-        copy(BlockTags.WOODEN_PRESSURE_PLATES, ItemTags.WOODEN_PRESSURE_PLATES);
-        copy(BlockTags.SLABS, ItemTags.SLABS);
-        copy(BlockTags.WOODEN_SLABS, ItemTags.WOODEN_SLABS);
-        copy(BlockTags.STAIRS, ItemTags.STAIRS);
-        copy(BlockTags.WOODEN_STAIRS, ItemTags.WOODEN_STAIRS);
-        copy(BlockTags.TRAPDOORS, ItemTags.TRAPDOORS);
-        copy(BlockTags.WOODEN_TRAPDOORS, ItemTags.WOODEN_TRAPDOORS);
-        copy(BlockTags.SAPLINGS, ItemTags.SAPLINGS);
-
-        copy(UTags.Blocks.ZAP_LOGS, UTags.Items.ZAP_LOGS);
-        copy(UTags.Blocks.WAXED_ZAP_LOGS, UTags.Items.WAXED_ZAP_LOGS);
-        copy(UTags.Blocks.PALM_LOGS, UTags.Items.PALM_LOGS);
-        copy(UTags.Blocks.CLOUD_BEDS, UTags.Items.CLOUD_BEDS);
-        copy(UTags.Blocks.CLOUD_SLABS, UTags.Items.CLOUD_SLABS);
-        copy(UTags.Blocks.CLOUD_STAIRS, UTags.Items.CLOUD_STAIRS);
-        copy(UTags.Blocks.CLOUD_BLOCKS, UTags.Items.CLOUD_BLOCKS);
-        copy(UTags.Blocks.CHITIN_BLOCKS, UTags.Items.CHITIN_BLOCKS);
-    }
-
-    private void exportConventionalTags() {
-        getOrCreateTagBuilder(UConventionalTags.ACORNS).add(UItems.ACORN);
-        getOrCreateTagBuilder(UConventionalTags.APPLES)
-            .add(Items.APPLE, Items.GOLDEN_APPLE, Items.ENCHANTED_GOLDEN_APPLE, UItems.ROTTEN_APPLE)
-            .forceAddTag(UTags.FRESH_APPLES)
-            .addOptionalTag(new Identifier("c", "pyrite_apples")) // no idea which mod add pyrite apples
-        ;
-        getOrCreateTagBuilder(UConventionalTags.BANANAS).add(UItems.BANANA);
-        getOrCreateTagBuilder(UConventionalTags.COOKED_FISH).add(Items.COOKED_COD, Items.COOKED_SALMON);
-        getOrCreateTagBuilder(UConventionalTags.STICKS).add(Items.STICK);
-        getOrCreateTagBuilder(UConventionalTags.PINECONES).add(UItems.PINECONE);
-        getOrCreateTagBuilder(UConventionalTags.PINEAPPLES).add(UItems.PINEAPPLE);
-        getOrCreateTagBuilder(UConventionalTags.MANGOES).add(UItems.MANGO);
-        getOrCreateTagBuilder(UConventionalTags.MUSHROOMS).add(Items.RED_MUSHROOM, Items.BROWN_MUSHROOM);
-        getOrCreateTagBuilder(UConventionalTags.MUFFINS).add(UItems.MUFFIN);
-        getOrCreateTagBuilder(UConventionalTags.SEEDS).add(Items.BEETROOT_SEEDS, Items.MELON_SEEDS, Items.PUMPKIN_SEEDS, Items.TORCHFLOWER_SEEDS, Items.WHEAT_SEEDS)
-            .add(UItems.OAT_SEEDS)
-            .forceAddTag(UTags.APPLE_SEEDS);
-        getOrCreateTagBuilder(UConventionalTags.OATMEALS).add(UItems.OATMEAL);
-        getOrCreateTagBuilder(UConventionalTags.GRAIN).add(Items.WHEAT, UItems.OATS);
-        getOrCreateTagBuilder(UConventionalTags.NUTS).addOptionalTag(UConventionalTags.CROPS_PEANUTS);
-
-        getOrCreateTagBuilder(UConventionalTags.FRUITS)
-            .forceAddTag(UConventionalTags.MANGOES)
-            .forceAddTag(UConventionalTags.PINEAPPLES)
-            .forceAddTag(UConventionalTags.APPLES)
-            .forceAddTag(UConventionalTags.BANANAS);
-    }
-
-    private void exportFarmersDelightItems() {
-        getOrCreateTagBuilder(UTags.COOLS_OFF_KIRINS)
-            .addOptional(new Identifier("farmersdelight:melon_popsicle"))
-            .addOptional(new Identifier("farmersdelight:melon_juice"));
-        getOrCreateTagBuilder(TagKey.of(RegistryKeys.ITEM, new Identifier("farmersdelight:cabbage_roll_ingredients"))).add(UItems.OATS, UItems.ROCK, UItems.WHEAT_WORMS);
-        getOrCreateTagBuilder(TagKey.of(RegistryKeys.ITEM, new Identifier("farmersdelight:comfort_foods"))).add(UItems.OATMEAL, UItems.ROCK_STEW, UItems.MUFFIN);
-    }
-}
diff --git a/src/main/java/com/minelittlepony/unicopia/datagen/providers/UModelProvider.java b/src/main/java/com/minelittlepony/unicopia/datagen/providers/UModelProvider.java
index 8dd5d9c5..cc317eb5 100644
--- a/src/main/java/com/minelittlepony/unicopia/datagen/providers/UModelProvider.java
+++ b/src/main/java/com/minelittlepony/unicopia/datagen/providers/UModelProvider.java
@@ -59,12 +59,14 @@ public class UModelProvider extends FabricModelProvider {
         ItemModels.register(itemModelGenerator,
                 UItems.ACORN, UItems.APPLE_PIE_HOOF, UItems.APPLE_PIE_SLICE, UItems.APPLE_PIE,
                 UItems.BANANA, UItems.BOTCHED_GEM, UItems.BOWL_OF_NUTS, UItems.BROKEN_SUNGLASSES, UItems.BURNED_JUICE, UItems.BURNED_TOAST,
-                UItems.CARAPACE, UItems.CLAM_SHELL, UItems.COOKED_ZAP_APPLE, UItems.CHOCOLATE_OATMEAL_COOKIE, UItems.CLOUD_LUMP, UItems.CRISPY_HAY_FRIES, UItems.CRYSTAL_HEART, UItems.CRYSTAL_SHARD,
+                UItems.CARAPACE, UItems.CLAM_SHELL, UItems.COOKED_ZAP_APPLE, UItems.CHOCOLATE_OATMEAL_COOKIE,
+                    UItems.CLOUD_LUMP, UItems.CRISPY_HAY_FRIES, UItems.CRYSTAL_HEART, UItems.CRYSTAL_SHARD,
+                    UItems.COOKED_TROPICAL_FISH, UItems.COOKED_PUFFERFISH, UItems.FRIED_AXOLOTL,
                 UItems.DAFFODIL_DAISY_SANDWICH, UItems.DRAGON_BREATH_SCROLL,
                 UItems.EMPTY_JAR,
                 UItems.FRIENDSHIP_BRACELET,
                 UItems.GIANT_BALLOON, UItems.GOLDEN_FEATHER, UItems.GOLDEN_OAK_SEEDS, UItems.GOLDEN_WING, UItems.GREEN_APPLE_SEEDS, UItems.GREEN_APPLE, UItems.GROGARS_BELL,
-                    UItems.GRYPHON_FEATHER,
+                    UItems.GRYPHON_FEATHER, UItems.GREEN_FRIED_EGG,
                 UItems.HAY_BURGER, UItems.HAY_FRIES, UItems.HORSE_SHOE_FRIES,
                 UItems.IMPORTED_OATS,
                 UItems.JAM_TOAST, UItems.JUICE,
@@ -72,7 +74,8 @@ public class UModelProvider extends FabricModelProvider {
                 UItems.MANGO, UItems.MUFFIN,
                 UItems.OATMEAL, UItems.OATMEAL_COOKIE, UItems.SCONE,
                 UItems.PEBBLES, UItems.PEGASUS_FEATHER, UItems.PINECONE, UItems.PINECONE_COOKIE, UItems.PINEAPPLE_CROWN,
-                UItems.RAIN_CLOUD_JAR, UItems.ROCK_STEW, UItems.ROCK, UItems.ROTTEN_APPLE,
+                UItems.RAIN_CLOUD_JAR, UItems.ROCK_STEW, UItems.ROCK,
+                    UItems.ROTTEN_APPLE, UItems.ROTTEN_COD, UItems.ROTTEN_TROPICAL_FISH, UItems.ROTTEN_SALMON, UItems.ROTTEN_PUFFERFISH,
                 UItems.SALT_CUBE, UItems.SCALLOP_SHELL, UItems.SHELLY, UItems.SOUR_APPLE_SEEDS, UItems.SOUR_APPLE, UItems.SPELLBOOK, UItems.STORM_CLOUD_JAR,
                     UItems.SWEET_APPLE_SEEDS, UItems.SWEET_APPLE,
                 UItems.TOAST, UItems.TOM, UItems.TURRET_SHELL,
@@ -106,7 +109,10 @@ public class UModelProvider extends FabricModelProvider {
                 .put(TextureKey.LAYER1, ModelIds.getItemSubModelId(UItems.MAGIC_STAFF, "_magic")), itemModelGenerator.writer);
 
         // polearms
-        List.of(UItems.DIAMOND_POLEARM, UItems.GOLDEN_POLEARM, UItems.NETHERITE_POLEARM, UItems.STONE_POLEARM, UItems.WOODEN_POLEARM, UItems.IRON_POLEARM).forEach(item -> ItemModels.registerPolearm(itemModelGenerator, item));
+        List.of(
+                UItems.DIAMOND_POLEARM, UItems.GOLDEN_POLEARM, UItems.NETHERITE_POLEARM,
+                UItems.STONE_POLEARM, UItems.WOODEN_POLEARM, UItems.IRON_POLEARM
+        ).forEach(item -> ItemModels.registerPolearm(itemModelGenerator, item));
         // sheets
         ItemModels.register(itemModelGenerator, BedsheetsItem.ITEMS.values().stream().toArray(Item[]::new));
         // badges
diff --git a/src/main/java/com/minelittlepony/unicopia/datagen/providers/loot/UBlockAdditionsLootTableProvider.java b/src/main/java/com/minelittlepony/unicopia/datagen/providers/loot/UBlockAdditionsLootTableProvider.java
index 4663bd66..cf6ed6d5 100644
--- a/src/main/java/com/minelittlepony/unicopia/datagen/providers/loot/UBlockAdditionsLootTableProvider.java
+++ b/src/main/java/com/minelittlepony/unicopia/datagen/providers/loot/UBlockAdditionsLootTableProvider.java
@@ -2,6 +2,7 @@ package com.minelittlepony.unicopia.datagen.providers.loot;
 
 import java.util.function.Function;
 
+import com.minelittlepony.unicopia.UTags;
 import com.minelittlepony.unicopia.item.UItems;
 import com.minelittlepony.unicopia.item.enchantment.UEnchantments;
 
@@ -14,20 +15,24 @@ import net.minecraft.enchantment.Enchantments;
 import net.minecraft.item.ItemConvertible;
 import net.minecraft.loot.LootPool;
 import net.minecraft.loot.LootTable;
+import net.minecraft.loot.condition.LocationCheckLootCondition;
 import net.minecraft.loot.condition.LootCondition;
 import net.minecraft.loot.condition.MatchToolLootCondition;
 import net.minecraft.loot.condition.RandomChanceLootCondition;
 import net.minecraft.loot.condition.TableBonusLootCondition;
 import net.minecraft.loot.entry.ItemEntry;
 import net.minecraft.loot.entry.LootPoolEntry;
+import net.minecraft.loot.entry.TagEntry;
 import net.minecraft.loot.function.ApplyBonusLootFunction;
 import net.minecraft.loot.function.SetCountLootFunction;
 import net.minecraft.loot.provider.number.ConstantLootNumberProvider;
 import net.minecraft.loot.provider.number.UniformLootNumberProvider;
 import net.minecraft.predicate.NumberRange;
+import net.minecraft.predicate.entity.LocationPredicate;
 import net.minecraft.predicate.item.EnchantmentPredicate;
 import net.minecraft.predicate.item.ItemPredicate;
 import net.minecraft.util.Identifier;
+import net.minecraft.world.biome.BiomeKeys;
 
 public class UBlockAdditionsLootTableProvider extends FabricBlockLootTableProvider {
     public static final LootCondition.Builder WITH_GEM_FINDER = MatchToolLootCondition.builder(ItemPredicate.Builder.create().enchantment(new EnchantmentPredicate(UEnchantments.GEM_FINDER, NumberRange.IntRange.atLeast(1))));
@@ -35,6 +40,10 @@ public class UBlockAdditionsLootTableProvider extends FabricBlockLootTableProvid
     public static final LootCondition.Builder WITHOUT_SILK_TOUCH_AND_GEM_FINDER = WITHOUT_SILK_TOUCH.and(WITH_GEM_FINDER);
     public static final float[] GEMSTONES_FORTUNE_CHANCE = { 0.1F, 0.14285715F, 0.25F, 1F };
 
+    public static final LootCondition.Builder NEEDS_OCEAN_OR_BEACH_BIOME =
+            LocationCheckLootCondition.builder(LocationPredicate.Builder.create().biome(BiomeKeys.OCEAN))
+        .or(LocationCheckLootCondition.builder(LocationPredicate.Builder.create().biome(BiomeKeys.BEACH)));
+
     public UBlockAdditionsLootTableProvider(FabricDataOutput dataOutput) {
         super(dataOutput);
     }
@@ -57,12 +66,25 @@ public class UBlockAdditionsLootTableProvider extends FabricBlockLootTableProvid
         addVanillaDrop(Blocks.DEEPSLATE_DIAMOND_ORE, this::crystalShardDrops);
         addVanillaDrop(Blocks.OAK_LEAVES, block -> chanceDropWithShears(block, UItems.ACORN, GEMSTONES_FORTUNE_CHANCE));
         addVanillaDrop(Blocks.SPRUCE_LEAVES, block -> chanceDropWithShears(block, UItems.PINECONE, GEMSTONES_FORTUNE_CHANCE));
+        addVanillaDrop(Blocks.GRAVEL, this::shellDrops);
+        addVanillaDrop(Blocks.SUSPICIOUS_GRAVEL, this::shellDrops);
     }
 
     private void addVanillaDrop(Block block, Function<Block, LootTable.Builder> lootTableFunction) {
         lootTables.put(new Identifier("unicopiamc", block.getLootTableId().getPath()), lootTableFunction.apply(block));
     }
 
+    public LootTable.Builder shellDrops(Block block) {
+        return LootTable.builder().pool(LootPool.builder()
+                .rolls(ConstantLootNumberProvider.create(1))
+                .conditionally(WITHOUT_SILK_TOUCH.and(NEEDS_OCEAN_OR_BEACH_BIOME))
+                .with(applyExplosionDecay(block, TagEntry.builder(UTags.Items.SHELLS)
+                        .apply(SetCountLootFunction.builder(ConstantLootNumberProvider.create(1)))
+                    )
+                    .conditionally(TableBonusLootCondition.builder(Enchantments.FORTUNE, GEMSTONES_FORTUNE_CHANCE)))
+                );
+    }
+
     public LootTable.Builder chanceDropWithShears(Block block, ItemConvertible drop, float...chance) {
         return LootTable.builder()
                 .pool(LootPool.builder()
diff --git a/src/main/java/com/minelittlepony/unicopia/datagen/providers/loot/UBlockLootTableProvider.java b/src/main/java/com/minelittlepony/unicopia/datagen/providers/loot/UBlockLootTableProvider.java
index 77b0d94e..9c625a1d 100644
--- a/src/main/java/com/minelittlepony/unicopia/datagen/providers/loot/UBlockLootTableProvider.java
+++ b/src/main/java/com/minelittlepony/unicopia/datagen/providers/loot/UBlockLootTableProvider.java
@@ -1,7 +1,17 @@
 package com.minelittlepony.unicopia.datagen.providers.loot;
 
 import java.util.List;
+
+import com.minelittlepony.unicopia.Unicopia;
+import com.minelittlepony.unicopia.block.EdibleBlock;
+import com.minelittlepony.unicopia.block.EnchantedFruitBlock;
+import com.minelittlepony.unicopia.block.PieBlock;
+import com.minelittlepony.unicopia.block.PileBlock;
+import com.minelittlepony.unicopia.block.SegmentedCropBlock;
+import com.minelittlepony.unicopia.block.ShellsBlock;
+import com.minelittlepony.unicopia.block.SlimePustuleBlock;
 import com.minelittlepony.unicopia.block.UBlocks;
+import com.minelittlepony.unicopia.datagen.Datagen;
 import com.minelittlepony.unicopia.datagen.providers.UModelProvider;
 import com.minelittlepony.unicopia.item.UItems;
 import com.minelittlepony.unicopia.server.world.Tree;
@@ -9,22 +19,44 @@ import com.minelittlepony.unicopia.server.world.UTreeGen;
 
 import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
 import net.fabricmc.fabric.api.datagen.v1.provider.FabricBlockLootTableProvider;
+import net.fabricmc.fabric.api.resource.conditions.v1.DefaultResourceConditions;
 import net.minecraft.block.BedBlock;
 import net.minecraft.block.Block;
 import net.minecraft.block.Blocks;
+import net.minecraft.block.CarrotsBlock;
+import net.minecraft.block.SlabBlock;
 import net.minecraft.block.enums.BedPart;
+import net.minecraft.block.enums.BlockHalf;
+import net.minecraft.block.enums.SlabType;
 import net.minecraft.enchantment.Enchantments;
+import net.minecraft.item.Item;
+import net.minecraft.item.ItemConvertible;
 import net.minecraft.item.Items;
 import net.minecraft.loot.LootPool;
 import net.minecraft.loot.LootTable;
+import net.minecraft.loot.condition.BlockStatePropertyLootCondition;
+import net.minecraft.loot.condition.LootConditionConsumingBuilder;
+import net.minecraft.loot.condition.RandomChanceLootCondition;
 import net.minecraft.loot.condition.TableBonusLootCondition;
 import net.minecraft.loot.entry.ItemEntry;
+import net.minecraft.loot.function.ApplyBonusLootFunction;
+import net.minecraft.loot.function.ConditionalLootFunction;
 import net.minecraft.loot.function.SetCountLootFunction;
 import net.minecraft.loot.provider.number.ConstantLootNumberProvider;
+import net.minecraft.loot.provider.number.LootNumberProvider;
 import net.minecraft.loot.provider.number.UniformLootNumberProvider;
+import net.minecraft.predicate.StatePredicate;
+import net.minecraft.state.property.BooleanProperty;
+import net.minecraft.state.property.IntProperty;
+import net.minecraft.state.property.Properties;
+import net.minecraft.state.property.Property;
+import net.minecraft.util.Identifier;
+import net.minecraft.util.StringIdentifiable;
 
 public class UBlockLootTableProvider extends FabricBlockLootTableProvider {
 
+    private static final ConditionalLootFunction.Builder<?> FORTUNE_BONUS = ApplyBonusLootFunction.binomialWithBonusCount(Enchantments.FORTUNE, 0.5714286F, 3);
+
     public UBlockLootTableProvider(FabricDataOutput output) {
         super(output);
     }
@@ -63,13 +95,22 @@ public class UBlockLootTableProvider extends FabricBlockLootTableProvider {
                 UBlocks.CHISELLED_CHITIN_SLAB, UBlocks.CLOUD_BRICK_SLAB,
                 UBlocks.CLOUD_PLANK_SLAB, UBlocks.PALM_SLAB, UBlocks.ZAP_SLAB, UBlocks.WAXED_ZAP_SLAB
         ).forEach(slab -> addDrop(slab, this::slabDrops));
+        addDrop(UBlocks.CLOUD_SLAB, slab -> decomposingSlabDrops(slab, UItems.CLOUD_LUMP, 2));
+        addDrop(UBlocks.SOGGY_CLOUD_SLAB, slab -> decomposingSlabDrops(slab, UItems.CLOUD_LUMP, 2));
+        addDrop(UBlocks.DENSE_CLOUD_SLAB, slab -> decomposingSlabDrops(slab, UItems.CLOUD_LUMP, 4));
+        addDrop(UBlocks.ETCHED_CLOUD_SLAB, slab -> decomposingSlabDrops(slab, UItems.CLOUD_LUMP, 4));
 
         // fruit
         UModelProvider.FRUITS.forEach((block, drop) -> {
             if (block != UBlocks.GOLDEN_APPLE) {
-                addDrop(block, drop);
+                addDrop(block, fortuneBonusDrops(drop));
             }
         });
+        addDrop(UBlocks.GOLDEN_APPLE, LootTable.builder().pool(LootPool.builder()
+            .rolls(exactly(1))
+            .with(applyStateCondition(UBlocks.GOLDEN_APPLE, EnchantedFruitBlock.ENCHANTED, false, applyExplosionDecay(UBlocks.GOLDEN_APPLE, ItemEntry.builder(Items.GOLDEN_APPLE))).apply(FORTUNE_BONUS))
+            .with(applyStateCondition(UBlocks.GOLDEN_APPLE, EnchantedFruitBlock.ENCHANTED, true, applyExplosionDecay(UBlocks.GOLDEN_APPLE, ItemEntry.builder(Items.ENCHANTED_GOLDEN_APPLE))).apply(FORTUNE_BONUS))
+        ));
         List.of(UBlocks.GREEN_APPLE_LEAVES, UBlocks.SOUR_APPLE_LEAVES, UBlocks.SWEET_APPLE_LEAVES, UBlocks.GOLDEN_OAK_LEAVES).forEach(block -> addDrop(block, this::fruitLeavesDrops));
         addDrop(UBlocks.MANGO_LEAVES, block -> leavesDrops(block, UTreeGen.MANGO_TREE.sapling().get(), 0.025F, 0.027777778F, 0.03125F, 0.041666668F, 0.1F)); // same chance as jungle
         addDrop(UBlocks.ZAP_LEAVES, block -> leavesDrops(block, UTreeGen.ZAP_APPLE_TREE.sapling().get(), SAPLING_DROP_CHANCE));
@@ -97,43 +138,197 @@ public class UBlockLootTableProvider extends FabricBlockLootTableProvider {
             UBlocks.CLOUD_BED, UBlocks.CLOTH_BED
         ).forEach(bed -> addDrop(bed, b -> dropsWithProperty(b, BedBlock.PART, BedPart.HEAD)));
 
-        addDrop(UBlocks.CHITIN_SPIKES, drops(UBlocks.CHITIN_SPIKES, UItems.CARAPACE, ConstantLootNumberProvider.create(6)));
-        addDrop(UBlocks.CHITIN, drops(UBlocks.CHITIN, UItems.CARAPACE, ConstantLootNumberProvider.create(9)));
-        addDrop(UBlocks.SURFACE_CHITIN, drops(UBlocks.SURFACE_CHITIN, UItems.CARAPACE, ConstantLootNumberProvider.create(9)));
+        addDrop(UBlocks.CHITIN_SPIKES, drops(UBlocks.CHITIN_SPIKES, UItems.CARAPACE, exactly(6)));
+        addDrop(UBlocks.CHITIN, drops(UBlocks.CHITIN, UItems.CARAPACE, exactly(9)));
+        addDrop(UBlocks.SURFACE_CHITIN, drops(UBlocks.SURFACE_CHITIN, UItems.CARAPACE, exactly(9)));
+        addDrop(UBlocks.CHISELLED_CHITIN_HULL, hullDrops(UBlocks.CHISELLED_CHITIN_HULL, UBlocks.CHITIN, UBlocks.CHISELLED_CHITIN));
 
-        addDrop(UBlocks.CLOUD, drops(UBlocks.CLOUD, UItems.CLOUD_LUMP, ConstantLootNumberProvider.create(4)));
-        addDrop(UBlocks.CLOUD_STAIRS, drops(UBlocks.CLOUD_STAIRS, UItems.CLOUD_LUMP, ConstantLootNumberProvider.create(6)));
+        addDrop(UBlocks.SLIME_PUSTULE, LootTable.builder()
+                .pool(applyStateCondition(UBlocks.SLIME_PUSTULE, SlimePustuleBlock.SHAPE, SlimePustuleBlock.Shape.POD,
+                        addSurvivesExplosionCondition(UBlocks.SLIME_PUSTULE, LootPool.builder()
+                    .rolls(exactly(1))
+                    .with(ItemEntry.builder(UBlocks.SLIME_PUSTULE)).conditionally(WITH_SILK_TOUCH_OR_SHEARS))
+        )));
+        addDrop(UBlocks.MYSTERIOUS_EGG, LootTable.builder()
+            .pool(addSurvivesExplosionCondition(UBlocks.MYSTERIOUS_EGG, LootPool.builder()
+                .rolls(exactly(1))
+                .with(ItemEntry.builder(UBlocks.MYSTERIOUS_EGG))
+                    .apply(PileBlock.COUNT.getValues(), count -> applyStateCondition(UBlocks.MYSTERIOUS_EGG, PileBlock.COUNT, count, SetCountLootFunction.builder(exactly(count)))))));
 
-        addDrop(UBlocks.SOGGY_CLOUD, drops(UBlocks.CLOUD, UItems.CLOUD_LUMP, ConstantLootNumberProvider.create(4)));
-        addDrop(UBlocks.SOGGY_CLOUD_STAIRS, drops(UBlocks.CLOUD_STAIRS, UItems.CLOUD_LUMP, ConstantLootNumberProvider.create(6)));
+        addDrop(UBlocks.CLOUD, drops(UBlocks.CLOUD, UItems.CLOUD_LUMP, exactly(4)));
+        addDrop(UBlocks.CLOUD_STAIRS, drops(UBlocks.CLOUD_STAIRS, UItems.CLOUD_LUMP, exactly(6)));
 
-        addDrop(UBlocks.DENSE_CLOUD, drops(UBlocks.DENSE_CLOUD, UItems.CLOUD_LUMP, ConstantLootNumberProvider.create(9)));
-        addDrop(UBlocks.DENSE_CLOUD_STAIRS, drops(UBlocks.DENSE_CLOUD_STAIRS, UItems.CLOUD_LUMP, ConstantLootNumberProvider.create(13)));
-        addDrop(UBlocks.ETCHED_CLOUD, drops(UBlocks.ETCHED_CLOUD, UItems.CLOUD_LUMP, ConstantLootNumberProvider.create(9)));
-        addDrop(UBlocks.ETCHED_CLOUD_STAIRS, drops(UBlocks.ETCHED_CLOUD_STAIRS, UItems.CLOUD_LUMP, ConstantLootNumberProvider.create(13)));
+        addDrop(UBlocks.SOGGY_CLOUD, drops(UBlocks.CLOUD, UItems.CLOUD_LUMP, exactly(4)));
+        addDrop(UBlocks.SOGGY_CLOUD_STAIRS, drops(UBlocks.CLOUD_STAIRS, UItems.CLOUD_LUMP, exactly(6)));
+
+        addDrop(UBlocks.DENSE_CLOUD, drops(UBlocks.DENSE_CLOUD, UItems.CLOUD_LUMP, exactly(9)));
+        addDrop(UBlocks.DENSE_CLOUD_STAIRS, drops(UBlocks.DENSE_CLOUD_STAIRS, UItems.CLOUD_LUMP, exactly(13)));
+        addDrop(UBlocks.ETCHED_CLOUD, drops(UBlocks.ETCHED_CLOUD, UItems.CLOUD_LUMP, exactly(9)));
+        addDrop(UBlocks.ETCHED_CLOUD_STAIRS, drops(UBlocks.ETCHED_CLOUD_STAIRS, UItems.CLOUD_LUMP, exactly(13)));
 
         // recipe produces: 6 blocks -> 3 pillars means: 6/3 = 2
-        addDrop(UBlocks.CLOUD_PILLAR, drops(UBlocks.CLOUD_PILLAR, UBlocks.CLOUD, ConstantLootNumberProvider.create(2)));
+        addDrop(UBlocks.CLOUD_PILLAR, drops(UBlocks.CLOUD_PILLAR, UBlocks.CLOUD, exactly(2)));
 
         addDrop(UBlocks.FROSTED_OBSIDIAN, Blocks.OBSIDIAN);
+        addDrop(UBlocks.APPLE_PIE, pieDrops(UBlocks.APPLE_PIE, UItems.APPLE_PIE, UItems.APPLE_PIE_HOOF));
+
+        // crops
+        addTallCropDrops(UBlocks.OATS, UItems.OATS);
+        addDrop(UBlocks.BANANAS, LootTable.builder()
+            .pool(addSurvivesExplosionCondition(UBlocks.BANANAS, LootPool.builder()
+                .rolls(exactly(1))
+                .with(item(UItems.BANANA, between(6, 12F)).apply(FORTUNE_BONUS))
+            )));
+        addDrop(UBlocks.PINEAPPLE, LootTable.builder()
+            .pool(addSurvivesExplosionCondition(UBlocks.PINEAPPLE, LootPool.builder()
+                .rolls(exactly(1))
+                .with(item(UItems.PINEAPPLE, between(6, 12F))
+                    .apply(FORTUNE_BONUS)
+                    .conditionally(BlockStatePropertyLootCondition.builder(UBlocks.PINEAPPLE).properties(StatePredicate.Builder.create()
+                        .exactMatch(Properties.BLOCK_HALF, BlockHalf.TOP)
+                        .exactMatch(Properties.AGE_7, Properties.AGE_7_MAX))))
+            )));
+        addDrop(UBlocks.ROCKS, applyExplosionDecay(UBlocks.ROCKS, LootTable.builder()
+                .pool(applyStateCondition(UBlocks.ROCKS, Properties.AGE_7, Properties.AGE_7_MAX, LootPool.builder()
+                    .rolls(exactly(1))
+                    .with(ItemEntry.builder(UItems.WEIRD_ROCK).conditionally(RandomChanceLootCondition.builder(0.25F)).apply(FORTUNE_BONUS))
+                    .with(ItemEntry.builder(UItems.ROCK).apply(FORTUNE_BONUS))))
+                .pool(LootPool.builder()
+                    .rolls(exactly(1))
+                    .with(ItemEntry.builder(UItems.PEBBLES)))
+        ));
+        addDrop(UBlocks.GOLD_ROOT, applyExplosionDecay(UBlocks.GOLD_ROOT, LootTable.builder()
+            .pool(LootPool.builder().with(ItemEntry.builder(Items.GOLDEN_CARROT)))
+            .pool(applyStateCondition(UBlocks.GOLD_ROOT, CarrotsBlock.AGE, 7, LootPool.builder())
+                    .with(ItemEntry.builder(Items.GOLDEN_CARROT).apply(FORTUNE_BONUS)))));
+        addDrop(UBlocks.PLUNDER_VINE, applyExplosionDecay(UBlocks.PLUNDER_VINE, LootTable.builder()
+                .pool(LootPool.builder().rolls(exactly(4))
+                    .with(ItemEntry.builder(Items.STICK))
+                    .with(ItemEntry.builder(Items.DEAD_BUSH)))
+                .pool(LootPool.builder().rolls(exactly(1))
+                        .with(ItemEntry.builder(Items.STICK))
+                        .with(ItemEntry.builder(Items.DEAD_BUSH))
+                        .with(ItemEntry.builder(UItems.GRYPHON_FEATHER)))
+        ));
+
+        // hay
+        addDrop(UBlocks.HAY_BLOCK, b -> edibleBlockDrops(b, Items.WHEAT));
+
+        // shells
+        addDrop(UBlocks.CLAM_SHELL, shellDrops(UBlocks.CLAM_SHELL, UItems.CLAM_SHELL));
+        addDrop(UBlocks.SCALLOP_SHELL, shellDrops(UBlocks.SCALLOP_SHELL, UItems.SCALLOP_SHELL));
+        addDrop(UBlocks.TURRET_SHELL, shellDrops(UBlocks.TURRET_SHELL, UItems.TURRET_SHELL));
+
+        var farmersDelightGenerator = withConditions(DefaultResourceConditions.allModsLoaded("farmersdelight"));
+        farmersDelightGenerator.addDrop(Datagen.getOrCreateBaleBlock(Unicopia.id("rice_block")), b -> edibleBlockDrops(b, Datagen.getOrCreateItem(new Identifier("farmersdelight", "rice_panicle"))));
+        farmersDelightGenerator.addDrop(Datagen.getOrCreateBaleBlock(Unicopia.id("straw_block")), b -> edibleBlockDrops(b, Datagen.getOrCreateItem(new Identifier("farmersdelight", "straw"))));
+    }
+
+    private void addTallCropDrops(SegmentedCropBlock baseCrop, ItemConvertible crop) {
+        addDrop(baseCrop, applyExplosionDecay(baseCrop, LootTable.builder()
+            .pool(LootPool.builder()
+                .rolls(exactly(1))
+                .with(ItemEntry.builder(baseCrop.getSeedsItem()))))
+            .pool(applyStateCondition(baseCrop, baseCrop.getAgeProperty(), baseCrop.getMaxAge(), LootPool.builder()
+                .rolls(exactly(1))
+                .with(ItemEntry.builder(baseCrop.getSeedsItem()).apply(FORTUNE_BONUS)))));
+
+        SegmentedCropBlock stage = baseCrop;
+        while ((stage = stage.getNext()) != null) {
+            addDrop(stage, applyExplosionDecay(stage, LootTable.builder()
+                .pool(LootPool.builder()
+                    .rolls(exactly(1))
+                    .with(applyStateCondition(stage, stage.getAgeProperty(), stage.getMaxAge(), ItemEntry.builder(crop))))));
+        }
+    }
+
+    private LootTable.Builder decomposingSlabDrops(Block slab, ItemConvertible drop, int count) {
+        return LootTable.builder()
+            .pool(applyExplosionDecay(slab, LootPool.builder()
+                .rolls(exactly(1))
+                .with(item(drop, exactly(count))
+                        .apply(applyStateCondition(slab, SlabBlock.TYPE, SlabType.DOUBLE, SetCountLootFunction.builder(exactly(count * 2)))))));
     }
 
     private LootTable.Builder fruitLeavesDrops(Block leaves) {
         return LootTable.builder()
             .pool(LootPool.builder()
-                    .rolls(ConstantLootNumberProvider.create(1))
-                    .with(ItemEntry.builder(leaves).conditionally(WITH_SILK_TOUCH_OR_SHEARS))
-            )
-            .pool(LootPool.builder()
-                    .rolls(ConstantLootNumberProvider.create(1))
-                    .conditionally(WITHOUT_SILK_TOUCH_NOR_SHEARS)
-                    .with(
-                            applyExplosionDecay(leaves, ItemEntry.builder(Items.STICK)
-                                .apply(SetCountLootFunction.builder(UniformLootNumberProvider.create(1, 2)))
-                            )
-                            .conditionally(TableBonusLootCondition.builder(Enchantments.FORTUNE, LEAVES_STICK_DROP_CHANCE))
-                    )
-            );
+                .rolls(exactly(1))
+                .with(ItemEntry.builder(leaves).conditionally(WITH_SILK_TOUCH_OR_SHEARS)))
+            .pool(applyExplosionDecay(leaves, LootPool.builder()
+                .rolls(exactly(1))
+                .conditionally(WITHOUT_SILK_TOUCH_NOR_SHEARS)
+                .with(item(Items.STICK, between(1, 2)).conditionally(TableBonusLootCondition.builder(Enchantments.FORTUNE, LEAVES_STICK_DROP_CHANCE)))));
     }
 
+    private LootTable.Builder hullDrops(Block hull, ItemConvertible inner, ItemConvertible outer) {
+        return LootTable.builder()
+            .pool(addSurvivesExplosionCondition(hull, LootPool.builder()
+                .rolls(exactly(1))
+                .with(item(hull, exactly(2)).conditionally(WITHOUT_SILK_TOUCH))
+                .with(item(inner, exactly(2)).conditionally(WITHOUT_SILK_TOUCH))
+                .with(item(outer, exactly(2)).conditionally(WITH_SILK_TOUCH))));
+    }
+
+    private LootTable.Builder edibleBlockDrops(Block block, ItemConvertible drop) {
+        LootTable.Builder builder = LootTable.builder();
+        for (BooleanProperty segment : EdibleBlock.SEGMENTS) {
+            builder
+                .pool(addSurvivesExplosionCondition(block, LootPool.builder()
+                    .rolls(exactly(1))
+                        .with(applyStateCondition(block, segment, true, ItemEntry.builder(drop)))));
+        }
+        return builder;
+    }
+
+    private LootTable.Builder pieDrops(Block block, Item drop, Item stomped) {
+        return LootTable.builder()
+            .pool(applyExplosionDecay(block, LootPool.builder()
+                .rolls(exactly(1)).conditionally(WITH_SILK_TOUCH)
+                .with(applyStateCondition(block, PieBlock.STOMPED, false, ItemEntry.builder(drop)))
+                .with(applyStateCondition(block, PieBlock.STOMPED, true, ItemEntry.builder(stomped)))));
+    }
+
+    private LootTable.Builder shellDrops(Block block, Item shell) {
+        return LootTable.builder()
+            .pool(applyExplosionDecay(block, LootPool.builder()
+                .rolls(exactly(1))
+                .with(ItemEntry.builder(shell))
+                    .apply(ShellsBlock.COUNT.getValues(), count -> applyStateCondition(block, ShellsBlock.COUNT, count, SetCountLootFunction.builder(exactly(count))))
+                    .apply(FORTUNE_BONUS)));
+    }
+
+
+    public LootTable.Builder fortuneBonusDrops(ItemConvertible drop) {
+        return LootTable.builder().pool(addSurvivesExplosionCondition(drop, LootPool.builder()
+                .rolls(exactly(1))
+                .with(ItemEntry.builder(drop).apply(FORTUNE_BONUS))));
+    }
+
+    public static ConstantLootNumberProvider exactly(float n) {
+        return ConstantLootNumberProvider.create(n);
+    }
+
+    public static UniformLootNumberProvider between(float from, float to) {
+        return UniformLootNumberProvider.create(from, to);
+    }
+
+    public static ItemEntry.Builder<?> item(ItemConvertible item, LootNumberProvider count) {
+        return ItemEntry.builder(item).apply(SetCountLootFunction.builder(count));
+    }
+
+    public static <T extends LootConditionConsumingBuilder<T>, P extends Comparable<P> & StringIdentifiable> T applyStateCondition(Block block,
+            Property<P> property, P value, LootConditionConsumingBuilder<T> builder) {
+        return builder.conditionally(BlockStatePropertyLootCondition.builder(block).properties(StatePredicate.Builder.create().exactMatch(property, value)));
+    }
+
+    public static <T extends LootConditionConsumingBuilder<T>> T applyStateCondition(Block block,
+            BooleanProperty property, boolean value, LootConditionConsumingBuilder<T> builder) {
+        return builder.conditionally(BlockStatePropertyLootCondition.builder(block).properties(StatePredicate.Builder.create().exactMatch(property, value)));
+    }
+
+    public static <T extends LootConditionConsumingBuilder<T>> T applyStateCondition(Block block,
+            IntProperty property, int value, LootConditionConsumingBuilder<T> builder) {
+        return builder.conditionally(BlockStatePropertyLootCondition.builder(block).properties(StatePredicate.Builder.create().exactMatch(property, value)));
+    }
 }
diff --git a/src/main/java/com/minelittlepony/unicopia/datagen/providers/loot/UChestAdditionsLootTableProvider.java b/src/main/java/com/minelittlepony/unicopia/datagen/providers/loot/UChestAdditionsLootTableProvider.java
index 72ad8a91..0d6beac9 100644
--- a/src/main/java/com/minelittlepony/unicopia/datagen/providers/loot/UChestAdditionsLootTableProvider.java
+++ b/src/main/java/com/minelittlepony/unicopia/datagen/providers/loot/UChestAdditionsLootTableProvider.java
@@ -2,6 +2,7 @@ package com.minelittlepony.unicopia.datagen.providers.loot;
 
 import java.util.function.BiConsumer;
 
+import com.minelittlepony.unicopia.UConventionalTags;
 import com.minelittlepony.unicopia.UTags;
 import com.minelittlepony.unicopia.item.UItems;
 
@@ -24,6 +25,10 @@ public class UChestAdditionsLootTableProvider extends SimpleFabricLootTableProvi
         super(dataOutput, LootContextTypes.CHEST);
     }
 
+    @Override
+    public String getName() {
+        return super.getName() + " Additions";
+    }
 
     @Override
     public void accept(BiConsumer<Identifier, Builder> exporter) {
@@ -39,7 +44,7 @@ public class UChestAdditionsLootTableProvider extends SimpleFabricLootTableProvi
                 .rolls(UniformLootNumberProvider.create(2, 4))
                 .with(ItemEntry.builder(UItems.GRYPHON_FEATHER).weight(10).apply(SetCountLootFunction.builder(UniformLootNumberProvider.create(1, 7))))
                 .with(ItemEntry.builder(UItems.GOLDEN_WING).weight(1).apply(SetCountLootFunction.builder(UniformLootNumberProvider.create(1, 2))))
-                .with(TagEntry.expandBuilder(UTags.FRESH_APPLES).weight(1).apply(SetCountLootFunction.builder(UniformLootNumberProvider.create(2, 5))))
+                .with(TagEntry.expandBuilder(UTags.Items.FRESH_APPLES).weight(1).apply(SetCountLootFunction.builder(UniformLootNumberProvider.create(2, 5))))
         ));
         exporter.accept(LootTables.VILLAGE_FLETCHER_CHEST, LootTable.builder().pool(LootPool.builder()
                 .rolls(UniformLootNumberProvider.create(2, 4))
@@ -48,37 +53,42 @@ public class UChestAdditionsLootTableProvider extends SimpleFabricLootTableProvi
         ));
         exporter.accept(LootTables.VILLAGE_PLAINS_CHEST, LootTable.builder().pool(LootPool.builder()
                 .rolls(UniformLootNumberProvider.create(3, 4))
-                .with(TagEntry.expandBuilder(UTags.FRESH_APPLES).weight(1))
-                .with(TagEntry.expandBuilder(UTags.APPLE_SEEDS).weight(1))
+                .with(TagEntry.expandBuilder(UTags.Items.FRESH_APPLES).weight(1))
+                .with(TagEntry.expandBuilder(UTags.Items.APPLE_SEEDS).weight(1))
         ));
 
         exporter.accept(LootTables.ANCIENT_CITY_CHEST, LootTable.builder().pool(LootPool.builder()
                 .rolls(UniformLootNumberProvider.create(0, 1))
                 .with(ItemEntry.builder(UItems.GROGARS_BELL).weight(1))
         ));
+
         exporter.accept(LootTables.BURIED_TREASURE_CHEST, LootTable.builder().pool(LootPool.builder()
                 .rolls(UniformLootNumberProvider.create(1, 4))
                 .with(ItemEntry.builder(UItems.PEARL_NECKLACE).weight(1))
-                .with(TagEntry.expandBuilder(UTags.item("food_types/shells")).weight(3))
+                .with(TagEntry.expandBuilder(UTags.Items.SHELLS).weight(3))
         ));
         exporter.accept(LootTables.SHIPWRECK_SUPPLY_CHEST, LootTable.builder().pool(LootPool.builder()
                 .rolls(UniformLootNumberProvider.create(1, 6))
-                .with(TagEntry.expandBuilder(UTags.SHELLS).weight(3))
+                .with(TagEntry.expandBuilder(UTags.Items.SHELLS).weight(3))
+                .with(TagEntry.expandBuilder(UConventionalTags.Items.ROTTEN_FISH).weight(1))
         ));
         exporter.accept(LootTables.SHIPWRECK_TREASURE_CHEST, LootTable.builder().pool(LootPool.builder()
                 .rolls(UniformLootNumberProvider.create(1, 4))
                 .with(ItemEntry.builder(UItems.PEARL_NECKLACE).weight(1))
-                .with(TagEntry.expandBuilder(UTags.SHELLS).weight(3))
+                .with(TagEntry.expandBuilder(UTags.Items.SHELLS).weight(3))
+                .with(TagEntry.expandBuilder(UConventionalTags.Items.ROTTEN_FISH).weight(1))
         ));
         exporter.accept(LootTables.UNDERWATER_RUIN_BIG_CHEST, LootTable.builder().pool(LootPool.builder()
                 .rolls(UniformLootNumberProvider.create(1, 2))
                 .with(ItemEntry.builder(UItems.PEARL_NECKLACE).weight(1))
                 .with(ItemEntry.builder(UItems.SHELLY).weight(4))
-                .with(TagEntry.expandBuilder(UTags.SHELLS).weight(8))
+                .with(TagEntry.expandBuilder(UTags.Items.SHELLS).weight(8))
+                .with(TagEntry.expandBuilder(UConventionalTags.Items.ROTTEN_FISH).weight(1))
         ));
         exporter.accept(LootTables.UNDERWATER_RUIN_SMALL_CHEST, LootTable.builder().pool(LootPool.builder()
                 .rolls(UniformLootNumberProvider.create(1, 4))
-                .with(TagEntry.expandBuilder(UTags.SHELLS).weight(1))
+                .with(TagEntry.expandBuilder(UTags.Items.SHELLS).weight(1))
+                .with(TagEntry.expandBuilder(UConventionalTags.Items.ROTTEN_FISH).weight(1))
         ));
 
         exporter.accept(LootTables.DESERT_WELL_ARCHAEOLOGY, LootTable.builder().pool(LootPool.builder()
@@ -89,7 +99,7 @@ public class UChestAdditionsLootTableProvider extends SimpleFabricLootTableProvi
                 .with(ItemEntry.builder(UItems.ROCK_STEW).weight(1))
                 .with(ItemEntry.builder(UItems.PEBBLES).weight(1))
                 .with(ItemEntry.builder(UItems.SHELLY).weight(1))
-                .with(TagEntry.expandBuilder(UTags.SHELLS).weight(1))
+                .with(TagEntry.expandBuilder(UTags.Items.SHELLS).weight(1))
                 .with(ItemEntry.builder(UItems.PEARL_NECKLACE).weight(1))
         ));
         exporter.accept(LootTables.TRAIL_RUINS_COMMON_ARCHAEOLOGY, LootTable.builder().pool(LootPool.builder()
@@ -106,19 +116,22 @@ public class UChestAdditionsLootTableProvider extends SimpleFabricLootTableProvi
         ));
         exporter.accept(LootTables.OCEAN_RUIN_WARM_ARCHAEOLOGY, LootTable.builder().pool(LootPool.builder()
                 .rolls(UniformLootNumberProvider.create(1, 4))
-                .with(TagEntry.expandBuilder(UTags.SHELLS).weight(1))
+                .with(TagEntry.expandBuilder(UTags.Items.SHELLS).weight(1))
                 .with(ItemEntry.builder(UItems.PEARL_NECKLACE).weight(1))
+                .with(TagEntry.expandBuilder(UConventionalTags.Items.ROTTEN_FISH).weight(1))
         ));
 
         exporter.accept(LootTables.FISHING_GAMEPLAY, LootTable.builder().pool(LootPool.builder()
                 .rolls(UniformLootNumberProvider.create(1, 4))
-                .with(TagEntry.expandBuilder(UTags.SHELLS).weight(2))
+                .with(TagEntry.expandBuilder(UTags.Items.SHELLS).weight(2))
+                .with(TagEntry.expandBuilder(UConventionalTags.Items.ROTTEN_FISH).weight(1))
         ));
 
         exporter.accept(LootTables.FISHING_JUNK_GAMEPLAY, LootTable.builder().pool(LootPool.builder()
                 .rolls(UniformLootNumberProvider.create(1, 4))
                 .with(ItemEntry.builder(UItems.BROKEN_SUNGLASSES).weight(2))
                 .with(ItemEntry.builder(UItems.WHEAT_WORMS).weight(2))
+                .with(TagEntry.expandBuilder(UConventionalTags.Items.ROTTEN_FISH).weight(1))
                 .with(ItemEntry.builder(UItems.BOTCHED_GEM).weight(4))
         ));
 
diff --git a/src/main/java/com/minelittlepony/unicopia/datagen/providers/loot/UChestLootTableProvider.java b/src/main/java/com/minelittlepony/unicopia/datagen/providers/loot/UChestLootTableProvider.java
new file mode 100644
index 00000000..0ea207e9
--- /dev/null
+++ b/src/main/java/com/minelittlepony/unicopia/datagen/providers/loot/UChestLootTableProvider.java
@@ -0,0 +1,56 @@
+package com.minelittlepony.unicopia.datagen.providers.loot;
+
+import java.util.function.BiConsumer;
+
+import com.minelittlepony.unicopia.Unicopia;
+import com.minelittlepony.unicopia.entity.effect.UPotions;
+
+import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
+import net.fabricmc.fabric.api.datagen.v1.provider.SimpleFabricLootTableProvider;
+import net.minecraft.item.Items;
+import net.minecraft.loot.LootPool;
+import net.minecraft.loot.LootTable;
+import net.minecraft.loot.LootTable.Builder;
+import net.minecraft.loot.context.LootContextTypes;
+import net.minecraft.loot.entry.ItemEntry;
+import net.minecraft.loot.function.SetCountLootFunction;
+import net.minecraft.loot.function.SetPotionLootFunction;
+import net.minecraft.loot.provider.number.ConstantLootNumberProvider;
+import net.minecraft.loot.provider.number.UniformLootNumberProvider;
+import net.minecraft.potion.Potion;
+import net.minecraft.util.Identifier;
+
+public class UChestLootTableProvider extends SimpleFabricLootTableProvider {
+    public UChestLootTableProvider(FabricDataOutput output) {
+        super(output, LootContextTypes.CHEST);
+    }
+
+    @Override
+    public void accept(BiConsumer<Identifier, Builder> exporter) {
+        exporter.accept(Unicopia.id("chests/changeling_hive_trap"), LootTable.builder()
+                .pool(LootPool.builder()
+                .rolls(ConstantLootNumberProvider.create(6))
+
+                .with(createTippedArrowEntry(UPotions.MORPH_EARTH_PONY.shortEffect(), 3))
+                .with(createTippedArrowEntry(UPotions.MORPH_UNICORN.shortEffect(), 1))
+                .with(createTippedArrowEntry(UPotions.MORPH_PEGASUS.shortEffect(), 1))
+                .with(createTippedArrowEntry(UPotions.MORPH_BAT.shortEffect(), 1))
+                .with(createTippedArrowEntry(UPotions.MORPH_KIRIN.shortEffect(), 1))
+                .with(createTippedArrowEntry(UPotions.MORPH_HIPPOGRIFF.shortEffect(), 1))
+
+                .with(createTippedArrowEntry(UPotions.MORPH_EARTH_PONY.longEffect(), 5))
+                .with(createTippedArrowEntry(UPotions.MORPH_UNICORN.longEffect(), 2))
+                .with(createTippedArrowEntry(UPotions.MORPH_PEGASUS.longEffect(), 2))
+                .with(createTippedArrowEntry(UPotions.MORPH_BAT.longEffect(), 2))
+                .with(createTippedArrowEntry(UPotions.MORPH_KIRIN.longEffect(), 2))
+                .with(createTippedArrowEntry(UPotions.MORPH_HIPPOGRIFF.longEffect(), 2))
+        ));
+    }
+
+    private static ItemEntry.Builder<?> createTippedArrowEntry(Potion potion, int weight) {
+        return ItemEntry.builder(Items.TIPPED_ARROW)
+                .weight(weight)
+                .apply(SetPotionLootFunction.builder(potion))
+                .apply(SetCountLootFunction.builder(UniformLootNumberProvider.create(3, 9)));
+    }
+}
diff --git a/src/main/java/com/minelittlepony/unicopia/datagen/providers/loot/UEntityLootTableProvider.java b/src/main/java/com/minelittlepony/unicopia/datagen/providers/loot/UEntityLootTableProvider.java
new file mode 100644
index 00000000..bdcc6942
--- /dev/null
+++ b/src/main/java/com/minelittlepony/unicopia/datagen/providers/loot/UEntityLootTableProvider.java
@@ -0,0 +1,63 @@
+package com.minelittlepony.unicopia.datagen.providers.loot;
+
+import java.util.function.BiConsumer;
+
+import com.minelittlepony.unicopia.UTags;
+import com.minelittlepony.unicopia.entity.mob.UEntities;
+import com.minelittlepony.unicopia.item.UItems;
+
+import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
+import net.fabricmc.fabric.api.datagen.v1.provider.SimpleFabricLootTableProvider;
+import net.minecraft.entity.EntityType;
+import net.minecraft.loot.LootPool;
+import net.minecraft.loot.LootTable;
+import net.minecraft.loot.LootTable.Builder;
+import net.minecraft.loot.condition.RandomChanceLootCondition;
+import net.minecraft.loot.context.LootContextTypes;
+import net.minecraft.loot.entry.ItemEntry;
+import net.minecraft.loot.entry.TagEntry;
+import net.minecraft.loot.function.LootingEnchantLootFunction;
+import net.minecraft.loot.function.SetCountLootFunction;
+import net.minecraft.loot.provider.number.ConstantLootNumberProvider;
+import net.minecraft.loot.provider.number.UniformLootNumberProvider;
+import net.minecraft.util.Identifier;
+
+public class UEntityLootTableProvider extends SimpleFabricLootTableProvider {
+    public UEntityLootTableProvider(FabricDataOutput output) {
+        super(output, LootContextTypes.ENTITY);
+    }
+
+    @Override
+    public void accept(BiConsumer<Identifier, Builder> exporter) {
+        generate((type, builder) -> exporter.accept(EntityType.getId(type).withPrefixedPath("entities/"), builder));
+    }
+
+    protected void generate(BiConsumer<EntityType<?>, Builder> exporter) {
+        exporter.accept(UEntities.BUTTERFLY, LootTable.builder()
+                .pool(LootPool.builder()
+                .rolls(ConstantLootNumberProvider.create(1))
+                .with(ItemEntry.builder(UItems.BUTTERFLY)
+                    .apply(LootingEnchantLootFunction.builder(UniformLootNumberProvider.create(0, 1))))));
+        exporter.accept(UEntities.STORM_CLOUD, LootTable.builder()
+                .pool(LootPool.builder()
+                .rolls(ConstantLootNumberProvider.create(1))
+                .with(ItemEntry.builder(UItems.CLOUD_LUMP)
+                    .apply(SetCountLootFunction.builder(UniformLootNumberProvider.create(6, 12)))
+                    .apply(LootingEnchantLootFunction.builder(UniformLootNumberProvider.create(0, 1))))));
+        exporter.accept(UEntities.LOOT_BUG, LootTable.builder()
+                .pool(LootPool.builder()
+                .rolls(ConstantLootNumberProvider.create(1))
+                .with(TagEntry.builder(UTags.Items.LOOT_BUG_COMMON_DROPS)
+                        .apply(SetCountLootFunction.builder(UniformLootNumberProvider.create(6, 12)))
+                        .apply(LootingEnchantLootFunction.builder(UniformLootNumberProvider.create(0, 3))))
+                .with(TagEntry.builder(UTags.Items.LOOT_BUG_RARE_DROPS)
+                        .conditionally(RandomChanceLootCondition.builder(0.25F))
+                        .apply(SetCountLootFunction.builder(UniformLootNumberProvider.create(1, 3)))
+                        .apply(LootingEnchantLootFunction.builder(UniformLootNumberProvider.create(0, 6))))
+                .with(TagEntry.builder(UTags.Items.LOOT_BUG_EPIC_DROPS)
+                        .conditionally(RandomChanceLootCondition.builder(0.1F))
+                        .apply(SetCountLootFunction.builder(ConstantLootNumberProvider.create(1)))
+                        .apply(LootingEnchantLootFunction.builder(UniformLootNumberProvider.create(0, 2))))
+        ));
+    }
+}
diff --git a/src/main/java/com/minelittlepony/unicopia/datagen/providers/recipe/BedSheetPatternRecipeBuilder.java b/src/main/java/com/minelittlepony/unicopia/datagen/providers/recipe/BedSheetPatternRecipeBuilder.java
index 0cd69ce6..2e067830 100644
--- a/src/main/java/com/minelittlepony/unicopia/datagen/providers/recipe/BedSheetPatternRecipeBuilder.java
+++ b/src/main/java/com/minelittlepony/unicopia/datagen/providers/recipe/BedSheetPatternRecipeBuilder.java
@@ -73,7 +73,7 @@ public class BedSheetPatternRecipeBuilder {
 
     private static void offerBedSheetConversionRecipe(Consumer<RecipeJsonProvider> exporter, ItemConvertible output, Stream<ItemConvertible> wools) {
         var builder = ShapelessRecipeJsonBuilder.create(RecipeCategory.DECORATIONS, output)
-            .input(UTags.WOOL_BED_SHEETS).criterion("has_bed_sheet", RecipeProvider.conditionsFromTag(UTags.WOOL_BED_SHEETS));
+            .input(UTags.Items.WOOL_BED_SHEETS).criterion("has_bed_sheet", RecipeProvider.conditionsFromTag(UTags.Items.WOOL_BED_SHEETS));
         wools.forEach(builder::input);
         builder
             .group("bed_sheet")
diff --git a/src/main/java/com/minelittlepony/unicopia/datagen/providers/recipe/CraftingMaterialHelper.java b/src/main/java/com/minelittlepony/unicopia/datagen/providers/recipe/CraftingMaterialHelper.java
index 25118dd3..a32f4245 100644
--- a/src/main/java/com/minelittlepony/unicopia/datagen/providers/recipe/CraftingMaterialHelper.java
+++ b/src/main/java/com/minelittlepony/unicopia/datagen/providers/recipe/CraftingMaterialHelper.java
@@ -4,7 +4,7 @@ import java.util.Map;
 import java.util.NoSuchElementException;
 
 import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
-import com.minelittlepony.unicopia.item.URecipes;
+import com.minelittlepony.unicopia.recipe.URecipes;
 import com.mojang.datafixers.util.Either;
 
 import net.fabricmc.fabric.api.tag.convention.v1.ConventionalItemTags;
diff --git a/src/main/java/com/minelittlepony/unicopia/datagen/providers/recipe/GrowingRecipeJsonBuilder.java b/src/main/java/com/minelittlepony/unicopia/datagen/providers/recipe/GrowingRecipeJsonBuilder.java
index 1daab591..53d44888 100644
--- a/src/main/java/com/minelittlepony/unicopia/datagen/providers/recipe/GrowingRecipeJsonBuilder.java
+++ b/src/main/java/com/minelittlepony/unicopia/datagen/providers/recipe/GrowingRecipeJsonBuilder.java
@@ -7,7 +7,7 @@ import org.jetbrains.annotations.Nullable;
 import org.spongepowered.include.com.google.common.base.Preconditions;
 
 import com.google.gson.JsonObject;
-import com.minelittlepony.unicopia.item.URecipes;
+import com.minelittlepony.unicopia.recipe.URecipes;
 import com.mojang.serialization.JsonOps;
 
 import net.minecraft.advancement.Advancement;
diff --git a/src/main/java/com/minelittlepony/unicopia/datagen/providers/recipe/SpellcraftingRecipeJsonBuilder.java b/src/main/java/com/minelittlepony/unicopia/datagen/providers/recipe/SpellcraftingRecipeJsonBuilder.java
index ca8d7b58..c8ddf638 100644
--- a/src/main/java/com/minelittlepony/unicopia/datagen/providers/recipe/SpellcraftingRecipeJsonBuilder.java
+++ b/src/main/java/com/minelittlepony/unicopia/datagen/providers/recipe/SpellcraftingRecipeJsonBuilder.java
@@ -15,7 +15,8 @@ import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
 import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
 import com.minelittlepony.unicopia.advancement.TraitDiscoveredCriterion;
 import com.minelittlepony.unicopia.item.UItems;
-import com.minelittlepony.unicopia.item.URecipes;
+import com.minelittlepony.unicopia.recipe.URecipes;
+
 import net.minecraft.advancement.Advancement;
 import net.minecraft.advancement.AdvancementRewards;
 import net.minecraft.advancement.CriterionMerger;
diff --git a/src/main/java/com/minelittlepony/unicopia/datagen/providers/recipe/TrickCraftingRecipeJsonBuilder.java b/src/main/java/com/minelittlepony/unicopia/datagen/providers/recipe/TrickCraftingRecipeJsonBuilder.java
index 22868e0c..ccccdc12 100644
--- a/src/main/java/com/minelittlepony/unicopia/datagen/providers/recipe/TrickCraftingRecipeJsonBuilder.java
+++ b/src/main/java/com/minelittlepony/unicopia/datagen/providers/recipe/TrickCraftingRecipeJsonBuilder.java
@@ -8,7 +8,7 @@ import org.spongepowered.include.com.google.common.base.Preconditions;
 
 import com.google.gson.JsonArray;
 import com.google.gson.JsonObject;
-import com.minelittlepony.unicopia.item.URecipes;
+import com.minelittlepony.unicopia.recipe.URecipes;
 
 import net.minecraft.advancement.Advancement;
 import net.minecraft.advancement.AdvancementRewards;
diff --git a/src/main/java/com/minelittlepony/unicopia/datagen/providers/recipe/URecipeProvider.java b/src/main/java/com/minelittlepony/unicopia/datagen/providers/recipe/URecipeProvider.java
index 3a95e32e..0597b525 100644
--- a/src/main/java/com/minelittlepony/unicopia/datagen/providers/recipe/URecipeProvider.java
+++ b/src/main/java/com/minelittlepony/unicopia/datagen/providers/recipe/URecipeProvider.java
@@ -17,7 +17,7 @@ import com.minelittlepony.unicopia.datagen.ItemFamilies;
 import com.minelittlepony.unicopia.datagen.UBlockFamilies;
 import com.minelittlepony.unicopia.datagen.providers.recipe.BedSheetPatternRecipeBuilder.PatternTemplate;
 import com.minelittlepony.unicopia.item.UItems;
-import com.minelittlepony.unicopia.item.URecipes;
+import com.minelittlepony.unicopia.recipe.URecipes;
 import com.minelittlepony.unicopia.server.world.UTreeGen;
 import com.mojang.datafixers.util.Either;
 
@@ -80,8 +80,19 @@ public class URecipeProvider extends FabricRecipeProvider {
     }
 
     private void generateVanillaRecipeExtensions(Consumer<RecipeJsonProvider> exporter) {
-        ShapelessRecipeJsonBuilder.create(RecipeCategory.MISC, Items.WRITABLE_BOOK).input(Items.BOOK).input(Items.INK_SAC).input(UTags.MAGIC_FEATHERS).criterion("has_book", conditionsFromItem(Items.BOOK)).offerTo(exporter);
-        ShapedRecipeJsonBuilder.create(RecipeCategory.COMBAT, Items.ARROW, 4).input('#', UConventionalTags.STICKS).input('X', Items.FLINT).input('Y', UTags.MAGIC_FEATHERS).pattern("X").pattern("#").pattern("Y").criterion("has_feather", conditionsFromTag(UTags.MAGIC_FEATHERS)).criterion("has_flint", conditionsFromItem(Items.FLINT)).offerTo(exporter);
+        ShapelessRecipeJsonBuilder.create(RecipeCategory.MISC, Items.WRITABLE_BOOK)
+            .input(Items.BOOK).criterion("has_book", conditionsFromItem(Items.BOOK))
+            .input(Items.INK_SAC)
+            .input(UTags.Items.MAGIC_FEATHERS)
+            .offerTo(exporter);
+        ShapedRecipeJsonBuilder.create(RecipeCategory.COMBAT, Items.ARROW, 4)
+            .input('#', UConventionalTags.Items.STICKS)
+            .input('X', Items.FLINT).criterion("has_flint", conditionsFromItem(Items.FLINT))
+            .input('Y', UTags.Items.MAGIC_FEATHERS).criterion("has_feather", conditionsFromTag(UTags.Items.MAGIC_FEATHERS))
+            .pattern("X")
+            .pattern("#")
+            .pattern("Y")
+            .offerTo(exporter);
     }
 
     private void offerJarRecipes(Consumer<RecipeJsonProvider> exporter) {
@@ -97,7 +108,7 @@ public class URecipeProvider extends FabricRecipeProvider {
     }
 
     private void offerCloudRecipes(Consumer<RecipeJsonProvider> exporter) {
-        offerShapelessRecipe(exporter, UItems.CLOUD_LUMP, UTags.CLOUD_JARS, "cloud", 4);
+        offerShapelessRecipe(exporter, UItems.CLOUD_LUMP, UTags.Items.CLOUD_JARS, "cloud", 4);
         generateFamily(exporter, UBlockFamilies.CLOUD);
         offer2x3Recipe(exporter, UBlocks.CLOUD_PILLAR, UBlocks.CLOUD, "pillar");
         offer2x2CompactingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, UBlocks.CLOUD, UItems.CLOUD_LUMP);
@@ -200,7 +211,7 @@ public class URecipeProvider extends FabricRecipeProvider {
         // magic staff
         ShapedRecipeJsonBuilder.create(RecipeCategory.TOOLS, UItems.MAGIC_STAFF)
             .input('*', UItems.GEMSTONE).criterion("has_gemstone", conditionsFromItem(UItems.GEMSTONE))
-            .input('#', UConventionalTags.STICKS).criterion("has_stick", conditionsFromTag(UConventionalTags.STICKS))
+            .input('#', UConventionalTags.Items.STICKS).criterion("has_stick", conditionsFromTag(UConventionalTags.Items.STICKS))
             .pattern("  *")
             .pattern(" # ")
             .pattern("#  ")
@@ -217,7 +228,7 @@ public class URecipeProvider extends FabricRecipeProvider {
         // pegasus amulet
         ShapedRecipeJsonBuilder.create(RecipeCategory.MISC, UItems.GOLDEN_FEATHER)
             .input('*', Items.GOLD_NUGGET).criterion("has_nugget", conditionsFromItem(Items.GOLD_NUGGET))
-            .input('#', UTags.MAGIC_FEATHERS).criterion("has_feather", conditionsFromTag(UTags.MAGIC_FEATHERS))
+            .input('#', UTags.Items.MAGIC_FEATHERS).criterion("has_feather", conditionsFromTag(UTags.Items.MAGIC_FEATHERS))
             .pattern("***")
             .pattern("*#*")
             .pattern("***")
@@ -232,7 +243,7 @@ public class URecipeProvider extends FabricRecipeProvider {
         // friendship bracelet
         ShapedRecipeJsonBuilder.create(RecipeCategory.TOOLS, UItems.FRIENDSHIP_BRACELET)
             .input('*', Items.STRING)
-            .input('#', Items.LEATHER).criterion(hasItem(Items.LEATHER), conditionsFromTag(UTags.MAGIC_FEATHERS))
+            .input('#', Items.LEATHER).criterion(hasItem(Items.LEATHER), conditionsFromItem(Items.LEATHER))
             .pattern("*#*")
             .pattern("# #")
             .pattern("*#*")
@@ -242,7 +253,7 @@ public class URecipeProvider extends FabricRecipeProvider {
         // meadowbrook's staff
         ShapedRecipeJsonBuilder.create(RecipeCategory.TOOLS, UItems.MEADOWBROOKS_STAFF)
             .input('*', UItems.GEMSTONE).criterion(hasItem(UItems.GEMSTONE), conditionsFromItem(UItems.GEMSTONE))
-            .input('/', UConventionalTags.STICKS).criterion(hasItem(Items.STICK), conditionsFromTag(UConventionalTags.STICKS))
+            .input('/', UConventionalTags.Items.STICKS).criterion(hasItem(Items.STICK), conditionsFromTag(UConventionalTags.Items.STICKS))
             .pattern("  *")
             .pattern(" / ")
             .pattern("/  ")
@@ -310,7 +321,7 @@ public class URecipeProvider extends FabricRecipeProvider {
         offerShapelessRecipe(exporter, UItems.SOUR_APPLE_SEEDS, UItems.SOUR_APPLE, "seeds", 3);
         offerShapelessRecipe(exporter, UItems.GREEN_APPLE_SEEDS, UItems.GREEN_APPLE, "seeds", 3);
         offerShapelessRecipe(exporter, UItems.GOLDEN_OAK_SEEDS, Items.GOLDEN_APPLE, "seeds", 1);
-        offerPieRecipe(exporter, UItems.APPLE_PIE, UItems.APPLE_PIE_SLICE, Items.WHEAT, UTags.FRESH_APPLES);
+        offerPieRecipe(exporter, UItems.APPLE_PIE, UItems.APPLE_PIE_SLICE, Items.WHEAT, UTags.Items.FRESH_APPLES);
 
         ShapelessRecipeJsonBuilder.create(RecipeCategory.FOOD, UItems.ROCK_STEW)
             .input(UItems.ROCK, 3).criterion(hasItem(UItems.ROCK), conditionsFromItem(UItems.ROCK))
@@ -344,20 +355,20 @@ public class URecipeProvider extends FabricRecipeProvider {
             .pattern("###")
             .offerTo(exporter, convertBetween(UItems.OATS, Items.WHEAT));
         ShapelessRecipeJsonBuilder.create(RecipeCategory.FOOD, UItems.JUICE)
-            .input(Ingredient.fromTag(UTags.FRESH_APPLES), 6).criterion(hasItem(Items.APPLE), conditionsFromTag(UTags.FRESH_APPLES))
+            .input(Ingredient.fromTag(UTags.Items.FRESH_APPLES), 6).criterion(hasItem(Items.APPLE), conditionsFromTag(UTags.Items.FRESH_APPLES))
             .input(Items.GLASS_BOTTLE)
             .group("juice")
             .offerTo(exporter);
         appendIngredients(ShapelessRecipeJsonBuilder.create(RecipeCategory.FOOD, UItems.MUFFIN), Items.SUGAR, Items.EGG, Items.POTATO, UItems.JUICE, UItems.WHEAT_WORMS).offerTo(exporter);
         ShapedRecipeJsonBuilder.create(RecipeCategory.MISC, UItems.MUG)
             .input('*', Items.IRON_NUGGET).criterion(hasItem(Items.IRON_NUGGET), conditionsFromItem(Items.IRON_NUGGET))
-            .input('#', UConventionalTags.STICKS).criterion(hasItem(Items.STICK), conditionsFromTag(UConventionalTags.STICKS))
+            .input('#', UConventionalTags.Items.STICKS).criterion(hasItem(Items.STICK), conditionsFromTag(UConventionalTags.Items.STICKS))
             .pattern("# #")
             .pattern("* *")
             .pattern(" # ")
             .offerTo(exporter);
         appendIngredients(ShapelessRecipeJsonBuilder.create(RecipeCategory.FOOD, UItems.CIDER), UItems.BURNED_JUICE, UItems.MUG)
-            .input(Ingredient.fromTag(UTags.FRESH_APPLES)).criterion(hasItem(Items.APPLE), conditionsFromTag(UTags.FRESH_APPLES))
+            .input(Ingredient.fromTag(UTags.Items.FRESH_APPLES)).criterion(hasItem(Items.APPLE), conditionsFromTag(UTags.Items.FRESH_APPLES))
             .offerTo(exporter);
 
         ShapedRecipeJsonBuilder.create(RecipeCategory.FOOD, UItems.HAY_FRIES)
@@ -400,6 +411,10 @@ public class URecipeProvider extends FabricRecipeProvider {
         offerSmelting(exporter, List.of(UItems.BURNED_JUICE, UItems.BURNED_TOAST), RecipeCategory.FOOD, Items.CHARCOAL, 1, 20, "coal");
         offerSmelting(exporter, List.of(UItems.HAY_FRIES), RecipeCategory.FOOD, UItems.CRISPY_HAY_FRIES, 1F, 25, "hay_fries");
         offerSmelting(exporter, List.of(UItems.ZAP_APPLE), RecipeCategory.FOOD, UItems.COOKED_ZAP_APPLE, 1.2F, 430, "zap_apple");
+        offerSmelting(exporter, List.of(Items.TROPICAL_FISH), RecipeCategory.FOOD, UItems.COOKED_TROPICAL_FISH, 1.2F, 230, "fish");
+        offerSmelting(exporter, List.of(Items.PUFFERFISH), RecipeCategory.FOOD, UItems.COOKED_PUFFERFISH, 1.2F, 230, "fish");
+        offerSmelting(exporter, List.of(Items.AXOLOTL_BUCKET), RecipeCategory.FOOD, UItems.FRIED_AXOLOTL, 2.2F, 230, "fried_axolotl");
+        offerSmelting(exporter, List.of(UBlocks.MYSTERIOUS_EGG.asItem()), RecipeCategory.FOOD, UItems.GREEN_FRIED_EGG, 3.8F, 630, "fried_egg");
 
         ShapelessRecipeJsonBuilder.create(RecipeCategory.FOOD, UItems.ZAP_APPLE_JAM_JAR)
             .input(UItems.COOKED_ZAP_APPLE, 6).criterion(hasItem(UItems.COOKED_ZAP_APPLE), conditionsFromItem(UItems.COOKED_ZAP_APPLE))
@@ -410,8 +425,8 @@ public class URecipeProvider extends FabricRecipeProvider {
             .input(UItems.TOAST, 8)
             .offerTo(exporter);
         ShapelessRecipeJsonBuilder.create(RecipeCategory.FOOD, UItems.CANDIED_APPLE)
-            .input(UConventionalTags.STICKS)
-            .input(UTags.FRESH_APPLES).criterion(hasItem(UItems.ZAP_APPLE_JAM_JAR), conditionsFromItem(UItems.ZAP_APPLE_JAM_JAR))
+            .input(UConventionalTags.Items.STICKS)
+            .input(UTags.Items.FRESH_APPLES).criterion(hasItem(Items.APPLE), conditionsFromTag(UTags.Items.FRESH_APPLES))
             .input(Items.SUGAR, 4)
             .offerTo(exporter);
 
@@ -445,7 +460,7 @@ public class URecipeProvider extends FabricRecipeProvider {
             .pattern(" C ")
             .offerTo(exporter);
         ShapedRecipeJsonBuilder.create(RecipeCategory.COMBAT, UItems.PEARL_NECKLACE)
-            .input('#', UTags.SHELLS).criterion("has_shell", conditionsFromTag(UTags.SHELLS))
+            .input('#', UTags.Items.SHELLS).criterion("has_shell", conditionsFromTag(UTags.Items.SHELLS))
             .input('~', Items.STRING)
             .pattern("# #")
             .pattern("# #")
@@ -492,7 +507,7 @@ public class URecipeProvider extends FabricRecipeProvider {
             .pattern("#*")
             .offerTo(exporter, convertBetween(Items.DIRT, UItems.WHEAT_WORMS));
 
-        offerShapelessRecipe(exporter, Items.BONE_MEAL, UTags.SHELLS, "bonemeal", 3);
+        offerShapelessRecipe(exporter, Items.BONE_MEAL, UTags.Items.SHELLS, "bonemeal", 3);
 
         // pegasus feathers for non pegasi
         ShapedRecipeJsonBuilder.create(RecipeCategory.MISC, UItems.PEGASUS_FEATHER)
@@ -578,7 +593,7 @@ public class URecipeProvider extends FabricRecipeProvider {
     public static void offerPolearmRecipe(Consumer<RecipeJsonProvider> exporter, ItemConvertible output, Either<ItemConvertible, TagKey<Item>> input) {
         CraftingMaterialHelper
             .input(ShapedRecipeJsonBuilder.create(RecipeCategory.TOOLS, output), 'o', input).criterion(CraftingMaterialHelper.hasEither(input), CraftingMaterialHelper.conditionsFromEither(input))
-            .input('#', UConventionalTags.STICKS)
+            .input('#', UConventionalTags.Items.STICKS)
             .pattern("  o")
             .pattern(" # ")
             .pattern("#  ")
diff --git a/src/main/java/com/minelittlepony/unicopia/datagen/providers/UBlockTagProvider.java b/src/main/java/com/minelittlepony/unicopia/datagen/providers/tag/UBlockTagProvider.java
similarity index 81%
rename from src/main/java/com/minelittlepony/unicopia/datagen/providers/UBlockTagProvider.java
rename to src/main/java/com/minelittlepony/unicopia/datagen/providers/tag/UBlockTagProvider.java
index 50a752c3..a576582d 100644
--- a/src/main/java/com/minelittlepony/unicopia/datagen/providers/UBlockTagProvider.java
+++ b/src/main/java/com/minelittlepony/unicopia/datagen/providers/tag/UBlockTagProvider.java
@@ -1,7 +1,9 @@
-package com.minelittlepony.unicopia.datagen.providers;
+package com.minelittlepony.unicopia.datagen.providers.tag;
 
+import java.util.Arrays;
 import java.util.concurrent.CompletableFuture;
 
+import com.minelittlepony.unicopia.UConventionalTags;
 import com.minelittlepony.unicopia.UTags;
 import com.minelittlepony.unicopia.Unicopia;
 import com.minelittlepony.unicopia.block.UBlocks;
@@ -12,12 +14,14 @@ import net.fabricmc.fabric.api.datagen.v1.provider.FabricTagProvider;
 import net.fabricmc.fabric.api.tag.convention.v1.ConventionalBlockTags;
 import net.minecraft.block.Block;
 import net.minecraft.block.Blocks;
+import net.minecraft.registry.Registries;
 import net.minecraft.registry.RegistryKeys;
 import net.minecraft.registry.RegistryWrapper;
 import net.minecraft.registry.RegistryWrapper.WrapperLookup;
 import net.minecraft.registry.tag.BlockTags;
 import net.minecraft.registry.tag.TagBuilder;
 import net.minecraft.registry.tag.TagKey;
+import net.minecraft.util.DyeColor;
 import net.minecraft.util.Identifier;
 
 public class UBlockTagProvider extends FabricTagProvider.BlockTagProvider {
@@ -32,6 +36,7 @@ public class UBlockTagProvider extends FabricTagProvider.BlockTagProvider {
 
     @Override
     protected void configure(WrapperLookup registries) {
+        populateConventionalTags();
         Block[] crops = {
                 UBlocks.OATS, UBlocks.OATS_STEM, UBlocks.OATS_CROWN,
                 UBlocks.ROCKS, UBlocks.PINEAPPLE,
@@ -39,13 +44,14 @@ public class UBlockTagProvider extends FabricTagProvider.BlockTagProvider {
                 UBlocks.GOLDEN_OAK_SPROUT
         };
 
-        getOrCreateTagBuilder(UTags.CATAPULT_IMMUNE).add(Blocks.BEDROCK).forceAddTag(BlockTags.DOORS).forceAddTag(BlockTags.TRAPDOORS);
-        getOrCreateTagBuilder(UTags.JARS).add(UBlocks.JAR, UBlocks.CLOUD_JAR, UBlocks.STORM_JAR, UBlocks.LIGHTNING_JAR, UBlocks.ZAP_JAR);
+        getOrCreateTagBuilder(UTags.Blocks.CATAPULT_IMMUNE).add(Blocks.BEDROCK).forceAddTag(BlockTags.DOORS).forceAddTag(BlockTags.TRAPDOORS);
+        getOrCreateTagBuilder(UTags.Blocks.BUTTERFLIES_SPAWNABLE_ON).forceAddTag(BlockTags.ANIMALS_SPAWNABLE_ON).forceAddTag(BlockTags.LEAVES).forceAddTag(BlockTags.FLOWERS).forceAddTag(BlockTags.FLOWER_POTS);
+        getOrCreateTagBuilder(UTags.Blocks.JARS).add(UBlocks.JAR, UBlocks.CLOUD_JAR, UBlocks.STORM_JAR, UBlocks.LIGHTNING_JAR, UBlocks.ZAP_JAR);
         getOrCreateTagBuilder(BlockTags.CROPS).add(crops);
         getOrCreateTagBuilder(BlockTags.BEE_GROWABLES).add(crops);
         getOrCreateTagBuilder(BlockTags.MAINTAINS_FARMLAND).add(crops);
         getOrCreateTagBuilder(BlockTags.NEEDS_DIAMOND_TOOL).add(UBlocks.FROSTED_OBSIDIAN);
-        getOrCreateTagBuilder(BlockTags.PICKAXE_MINEABLE).add(UBlocks.ROCKS, UBlocks.FROSTED_OBSIDIAN, UBlocks.WEATHER_VANE).forceAddTag(UTags.JARS);
+        getOrCreateTagBuilder(BlockTags.PICKAXE_MINEABLE).add(UBlocks.ROCKS, UBlocks.FROSTED_OBSIDIAN, UBlocks.WEATHER_VANE).forceAddTag(UTags.Blocks.JARS);
         getOrCreateTagBuilder(BlockTags.DRAGON_IMMUNE).add(UBlocks.FROSTED_OBSIDIAN, UBlocks.GOLDEN_OAK_LOG, UBlocks.GOLDEN_OAK_LEAVES);
         getOrCreateTagBuilder(BlockTags.FIRE).add(UBlocks.SPECTRAL_FIRE);
         getOrCreateTagBuilder(BlockTags.HOE_MINEABLE).add(UBlocks.HAY_BLOCK).addOptional(Unicopia.id("rice_block")).addOptional(Unicopia.id("straw_block"));
@@ -57,31 +63,31 @@ public class UBlockTagProvider extends FabricTagProvider.BlockTagProvider {
         addChitinBlocksets();
         addFruitTrees();
 
-        getOrCreateTagBuilder(UTags.CRYSTAL_HEART_BASE).add(
+        getOrCreateTagBuilder(UTags.Blocks.CRYSTAL_HEART_BASE).add(
                 Blocks.DIAMOND_BLOCK,
                 Blocks.QUARTZ_BLOCK, Blocks.QUARTZ_BRICKS, Blocks.QUARTZ_SLAB, Blocks.QUARTZ_STAIRS, Blocks.QUARTZ_PILLAR,
                 Blocks.SMOOTH_QUARTZ, Blocks.SMOOTH_QUARTZ_SLAB, Blocks.SMOOTH_QUARTZ_STAIRS, Blocks.CHISELED_QUARTZ_BLOCK,
                 Blocks.AMETHYST_BLOCK, Blocks.NETHERITE_BLOCK, Blocks.EMERALD_BLOCK
         );
-        getOrCreateTagBuilder(UTags.CRYSTAL_HEART_ORNAMENT).add(Blocks.END_ROD);
+        getOrCreateTagBuilder(UTags.Blocks.CRYSTAL_HEART_ORNAMENT).add(Blocks.END_ROD);
 
-        getOrCreateTagBuilder(UTags.FRAGILE)
+        getOrCreateTagBuilder(UTags.Blocks.FRAGILE)
             .forceAddTag(ConventionalBlockTags.GLASS_BLOCKS)
             .forceAddTag(ConventionalBlockTags.GLASS_PANES)
-            .forceAddTag(UTags.JARS)
+            .forceAddTag(UTags.Blocks.JARS)
             .add(Blocks.VINE, Blocks.LILY_PAD);
 
-        getOrCreateTagBuilder(UTags.INTERESTING).add(
+        getOrCreateTagBuilder(UTags.Blocks.INTERESTING).add(
                 Blocks.SEA_LANTERN, Blocks.ENDER_CHEST, Blocks.END_PORTAL_FRAME,
                 Blocks.JUKEBOX, Blocks.SPAWNER
         ).forceAddTag(ConventionalBlockTags.ORES);
 
-        getOrCreateTagBuilder(UTags.KICKS_UP_DUST).forceAddTag(BlockTags.SAND).add(
+        getOrCreateTagBuilder(UTags.Blocks.KICKS_UP_DUST).forceAddTag(BlockTags.SAND).add(
                 Blocks.SUSPICIOUS_SAND,
                 Blocks.GRAVEL, Blocks.SUSPICIOUS_GRAVEL
         ).forceAddTag(TagKey.of(RegistryKeys.BLOCK, new Identifier("c", "concrete_powders")));
 
-        getOrCreateTagBuilder(UTags.UNAFFECTED_BY_GROW_ABILITY).add(Blocks.GRASS_BLOCK);
+        getOrCreateTagBuilder(UTags.Blocks.UNAFFECTED_BY_GROW_ABILITY).add(Blocks.GRASS_BLOCK);
     }
 
     private void addFruitTrees() {
@@ -106,7 +112,7 @@ public class UBlockTagProvider extends FabricTagProvider.BlockTagProvider {
 
     private void addZapWoodset() {
         getOrCreateTagBuilder(BlockTags.LEAVES).add(UBlocks.ZAP_LEAVES, UBlocks.FLOWERING_ZAP_LEAVES);
-        getOrCreateTagBuilder(UTags.POLEARM_MINEABLE).add(
+        getOrCreateTagBuilder(UTags.Blocks.POLEARM_MINEABLE).add(
                 UBlocks.ZAP_LEAVES, UBlocks.FLOWERING_ZAP_LEAVES,
                 UBlocks.ZAP_PLANKS,
                 UBlocks.ZAP_LOG, UBlocks.ZAP_WOOD, UBlocks.STRIPPED_ZAP_LOG, UBlocks.STRIPPED_ZAP_WOOD,
@@ -204,4 +210,13 @@ public class UBlockTagProvider extends FabricTagProvider.BlockTagProvider {
         getOrCreateTagBuilder(BlockTags.CEILING_HANGING_SIGNS).add(hanging);
         getOrCreateTagBuilder(BlockTags.WALL_HANGING_SIGNS).add(wallHanging);
     }
+
+    private void populateConventionalTags() {
+        getOrCreateTagBuilder(UConventionalTags.Blocks.CONCRETES).add(Arrays.stream(DyeColor.values()).map(i -> Registries.BLOCK.get(new Identifier(i.getName() + "_concrete"))).toArray(Block[]::new));
+        getOrCreateTagBuilder(UConventionalTags.Blocks.CONCRETE_POWDERS).add(Arrays.stream(DyeColor.values()).map(i -> Registries.BLOCK.get(new Identifier(i.getName() + "_concrete_powder"))).toArray(Block[]::new));
+        getOrCreateTagBuilder(UConventionalTags.Blocks.GLAZED_TERRACOTTAS).add(Arrays.stream(DyeColor.values()).map(i -> Registries.BLOCK.get(new Identifier(i.getName() + "_glazed_terracotta"))).toArray(Block[]::new));
+        getOrCreateTagBuilder(UConventionalTags.Blocks.CORAL_BLOCKS).add(Blocks.TUBE_CORAL_BLOCK, Blocks.BRAIN_CORAL_BLOCK, Blocks.BUBBLE_CORAL_BLOCK, Blocks.FIRE_CORAL_BLOCK, Blocks.HORN_CORAL_BLOCK);
+        getOrCreateTagBuilder(UConventionalTags.Blocks.CORAL_FANS).add(Blocks.TUBE_CORAL_FAN, Blocks.BRAIN_CORAL_FAN, Blocks.BUBBLE_CORAL_FAN, Blocks.FIRE_CORAL_FAN, Blocks.HORN_CORAL_FAN);
+        getOrCreateTagBuilder(UConventionalTags.Blocks.CORALS).add(Blocks.TUBE_CORAL, Blocks.BRAIN_CORAL, Blocks.BUBBLE_CORAL, Blocks.FIRE_CORAL, Blocks.HORN_CORAL);
+    }
 }
diff --git a/src/main/java/com/minelittlepony/unicopia/datagen/providers/tag/UDamageTypeProvider.java b/src/main/java/com/minelittlepony/unicopia/datagen/providers/tag/UDamageTypeProvider.java
new file mode 100644
index 00000000..d0b265b1
--- /dev/null
+++ b/src/main/java/com/minelittlepony/unicopia/datagen/providers/tag/UDamageTypeProvider.java
@@ -0,0 +1,30 @@
+package com.minelittlepony.unicopia.datagen.providers.tag;
+
+import java.util.concurrent.CompletableFuture;
+
+import com.minelittlepony.unicopia.UTags;
+import com.minelittlepony.unicopia.entity.damage.UDamageTypes;
+
+import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
+import net.fabricmc.fabric.api.datagen.v1.provider.FabricTagProvider;
+import net.minecraft.entity.damage.DamageType;
+import net.minecraft.registry.RegistryKeys;
+import net.minecraft.registry.RegistryWrapper.WrapperLookup;
+import net.minecraft.registry.tag.DamageTypeTags;
+
+public class UDamageTypeProvider extends FabricTagProvider<DamageType> {
+    public UDamageTypeProvider(FabricDataOutput output, CompletableFuture<WrapperLookup> registriesFuture) {
+        super(output, RegistryKeys.DAMAGE_TYPE, registriesFuture);
+    }
+
+    @Override
+    protected void configure(WrapperLookup lookup) {
+        getOrCreateTagBuilder(UTags.DamageTypes.SPELLBOOK_IMMUNE_TO).add(
+                UDamageTypes.ZAP_APPLE, UDamageTypes.LOVE_DRAINING, UDamageTypes.LIFE_DRAINING,
+                UDamageTypes.RAINBOOM, UDamageTypes.SUN, UDamageTypes.SUNLIGHT, UDamageTypes.SMASH
+        ).forceAddTag(DamageTypeTags.IS_FALL).forceAddTag(DamageTypeTags.IS_FREEZING).forceAddTag(DamageTypeTags.IS_LIGHTNING).forceAddTag(DamageTypeTags.IS_PROJECTILE);
+        getOrCreateTagBuilder(UTags.DamageTypes.FROM_ROCKS).add(UDamageTypes.ROCK);
+        getOrCreateTagBuilder(UTags.DamageTypes.FROM_HORSESHOES).add(UDamageTypes.HORSESHOE);
+        getOrCreateTagBuilder(UTags.DamageTypes.BREAKS_SUNGLASSES).add(UDamageTypes.BAT_SCREECH, UDamageTypes.RAINBOOM);
+    }
+}
diff --git a/src/main/java/com/minelittlepony/unicopia/datagen/providers/tag/UItemTagProvider.java b/src/main/java/com/minelittlepony/unicopia/datagen/providers/tag/UItemTagProvider.java
new file mode 100644
index 00000000..42365d56
--- /dev/null
+++ b/src/main/java/com/minelittlepony/unicopia/datagen/providers/tag/UItemTagProvider.java
@@ -0,0 +1,348 @@
+package com.minelittlepony.unicopia.datagen.providers.tag;
+
+import java.util.Objects;
+import java.util.concurrent.CompletableFuture;
+
+import com.minelittlepony.unicopia.Race;
+import com.minelittlepony.unicopia.UConventionalTags;
+import com.minelittlepony.unicopia.UTags;
+import com.minelittlepony.unicopia.block.UBlocks;
+import com.minelittlepony.unicopia.datagen.Datagen;
+import com.minelittlepony.unicopia.datagen.ItemFamilies;
+import com.minelittlepony.unicopia.item.BedsheetsItem;
+import com.minelittlepony.unicopia.item.UItems;
+
+import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
+import net.fabricmc.fabric.api.datagen.v1.provider.FabricTagProvider;
+import net.fabricmc.fabric.api.tag.convention.v1.ConventionalItemTags;
+import net.minecraft.block.Block;
+import net.minecraft.item.Item;
+import net.minecraft.item.Items;
+import net.minecraft.registry.Registries;
+import net.minecraft.registry.RegistryKeys;
+import net.minecraft.registry.RegistryWrapper;
+import net.minecraft.registry.RegistryWrapper.WrapperLookup;
+import net.minecraft.registry.tag.BlockTags;
+import net.minecraft.registry.tag.ItemTags;
+import net.minecraft.registry.tag.TagBuilder;
+import net.minecraft.registry.tag.TagKey;
+import net.minecraft.util.Identifier;
+
+public class UItemTagProvider extends FabricTagProvider.ItemTagProvider {
+
+
+    private final UBlockTagProvider blockTagProvider;
+
+    public UItemTagProvider(FabricDataOutput output, CompletableFuture<RegistryWrapper.WrapperLookup> registriesFuture, UBlockTagProvider blockTagProvider) {
+        super(output, registriesFuture, blockTagProvider);
+        this.blockTagProvider = blockTagProvider;
+    }
+
+    @Override
+    public void copy(TagKey<Block> blockTag, TagKey<Item> itemTag) {
+        TagBuilder blockTagBuilder = Objects.requireNonNull(blockTagProvider, "Pass Block tag provider via constructor to use copy").getTagBuilder(blockTag);
+        TagBuilder itemTagBuilder = getTagBuilder(itemTag);
+        blockTagBuilder.build().forEach(entry -> {
+            if (entry.canAdd(Registries.ITEM::containsId, tagId -> getTagBuilder(TagKey.of(RegistryKeys.ITEM, tagId)) != null)) {
+                itemTagBuilder.add(entry);
+            } else {
+                Datagen.LOGGER.warn("Cannot copy missing entry {} to item tag {}", entry, itemTag.id());
+            }
+        });
+    }
+
+    @Override
+    protected void configure(WrapperLookup arg) {
+        copyBlockTags();
+        exportConventionalTags();
+        getOrCreateTagBuilder(ItemTags.BOOKSHELF_BOOKS).add(UItems.SPELLBOOK);
+        getOrCreateTagBuilder(ItemTags.BEDS).add(UItems.CLOTH_BED, UItems.CLOUD_BED);
+
+        getOrCreateTagBuilder(ItemTags.CHEST_BOATS).add(UItems.PALM_CHEST_BOAT);
+        getOrCreateTagBuilder(ItemTags.BOATS).add(UItems.PALM_BOAT);
+        getOrCreateTagBuilder(ItemTags.MUSIC_DISCS).add(ItemFamilies.MUSIC_DISCS);
+        getOrCreateTagBuilder(ItemTags.CREEPER_DROP_MUSIC_DISCS).add(UItems.MUSIC_DISC_CRUSADE, UItems.MUSIC_DISC_FUNK, UItems.MUSIC_DISC_PET, UItems.MUSIC_DISC_POPULAR);
+
+        getOrCreateTagBuilder(ItemTags.SIGNS).add(UBlocks.PALM_SIGN.asItem());
+        getOrCreateTagBuilder(ItemTags.HANGING_SIGNS).add(UBlocks.PALM_HANGING_SIGN.asItem());
+
+        getOrCreateTagBuilder(UTags.Items.HORSE_SHOES).add(ItemFamilies.HORSE_SHOES);
+        getOrCreateTagBuilder(UTags.Items.POLEARMS).add(ItemFamilies.POLEARMS);
+
+        getOrCreateTagBuilder(ItemTags.TOOLS).addTag(UTags.Items.HORSE_SHOES).addTag(UTags.Items.POLEARMS);
+
+        getOrCreateTagBuilder(UTags.Items.BASKETS).add(ItemFamilies.BASKETS);
+        getOrCreateTagBuilder(UTags.Items.BADGES).add(Race.REGISTRY.stream()
+                .map(race -> race.getId().withPath(p -> p + "_badge"))
+                .flatMap(id -> Registries.ITEM.getOrEmpty(id).stream())
+                .toArray(Item[]::new));
+        getOrCreateTagBuilder(UTags.Items.WOOL_BED_SHEETS).add(BedsheetsItem.ITEMS.values().stream().filter(sheet -> sheet != UItems.KELP_BED_SHEETS).toArray(Item[]::new));
+        getOrCreateTagBuilder(UTags.Items.BED_SHEETS).forceAddTag(UTags.Items.WOOL_BED_SHEETS).add(UItems.KELP_BED_SHEETS);
+        getOrCreateTagBuilder(UTags.Items.APPLE_SEEDS).add(UItems.GREEN_APPLE_SEEDS, UItems.SWEET_APPLE_SEEDS, UItems.SOUR_APPLE_SEEDS);
+        getOrCreateTagBuilder(UTags.Items.MAGIC_FEATHERS).add(UItems.PEGASUS_FEATHER, UItems.GRYPHON_FEATHER);
+        getOrCreateTagBuilder(UTags.Items.FRESH_APPLES).add(Items.APPLE, UItems.GREEN_APPLE, UItems.SWEET_APPLE, UItems.SOUR_APPLE);
+        getOrCreateTagBuilder(UTags.Items.CLOUD_JARS).add(UItems.RAIN_CLOUD_JAR, UItems.STORM_CLOUD_JAR);
+        getOrCreateTagBuilder(UTags.Items.PIES).add(UItems.APPLE_PIE, UItems.APPLE_PIE_HOOF);
+
+        // technical tags
+        getOrCreateTagBuilder(ItemTags.VILLAGER_PLANTABLE_SEEDS).addTag(UTags.Items.APPLE_SEEDS);
+        getOrCreateTagBuilder(UTags.Items.CAN_CUT_PIE).forceAddTag(ConventionalItemTags.SHEARS).addOptionalTag(UConventionalTags.Items.TOOL_KNIVES);
+        getOrCreateTagBuilder(UTags.Items.COOLS_OFF_KIRINS).add(Items.MELON_SLICE, UItems.JUICE).forceAddTag(ConventionalItemTags.WATER_BUCKETS);
+        getOrCreateTagBuilder(UTags.Items.FALLS_SLOWLY).add(Items.FEATHER, UItems.CLOUD_LUMP).forceAddTag(UTags.Items.MAGIC_FEATHERS);
+        getOrCreateTagBuilder(UTags.Items.IS_DELIVERED_AGGRESSIVELY).forceAddTag(ItemTags.ANVIL);
+        getOrCreateTagBuilder(UTags.Items.SPOOKED_MOB_DROPS).add(Items.BRICK);
+        getOrCreateTagBuilder(UTags.Items.SHADES).add(
+                Items.CARVED_PUMPKIN, Items.SKELETON_SKULL, Items.WITHER_SKELETON_SKULL, Items.PLAYER_HEAD,
+                Items.ZOMBIE_HEAD, Items.CREEPER_HEAD, Items.DRAGON_HEAD, Items.PIGLIN_HEAD,
+                UItems.SUNGLASSES
+        );
+        getOrCreateTagBuilder(UTags.Items.FLOATS_ON_CLOUDS)
+            .forceAddTag(UTags.Items.CLOUD_BEDS)
+            .forceAddTag(UTags.Items.CLOUD_SLABS)
+            .forceAddTag(UTags.Items.CLOUD_STAIRS)
+            .forceAddTag(UTags.Items.CLOUD_BLOCKS)
+            .add(UItems.CLOUD_LUMP);
+        getOrCreateTagBuilder(UTags.Items.CONTAINER_WITH_LOVE).add(UItems.LOVE_BOTTLE, UItems.LOVE_BUCKET, UItems.LOVE_MUG);
+        getOrCreateTagBuilder(UTags.Items.HAS_NO_TRAITS).add(
+                Items.AIR, Items.SPAWNER, Items.STRUCTURE_VOID, Items.STRUCTURE_BLOCK,
+                Items.COMMAND_BLOCK, Items.CHAIN_COMMAND_BLOCK, Items.REPEATING_COMMAND_BLOCK,
+                Items.LIGHT, Items.JIGSAW, Items.BARRIER, Items.BEDROCK, Items.END_PORTAL_FRAME,
+                Items.DEBUG_STICK, Items.COMMAND_BLOCK_MINECART,
+                UItems.PLUNDER_VINE
+        ).forceAddTag(UTags.Items.BADGES);
+        getOrCreateTagBuilder(UTags.Items.LOOT_BUG_COMMON_DROPS).forceAddTag(ConventionalItemTags.NUGGETS);
+        getOrCreateTagBuilder(UTags.Items.LOOT_BUG_RARE_DROPS).add(
+                    Items.DIAMOND, Items.GOLDEN_APPLE, Items.GOLDEN_CARROT,
+                    Items.GOLDEN_HELMET, Items.GOLDEN_BOOTS, Items.GOLDEN_LEGGINGS, Items.GOLDEN_CHESTPLATE,
+                    Items.GOLDEN_HORSE_ARMOR,
+                    Items.GOLDEN_PICKAXE, Items.GOLDEN_SHOVEL, Items.GOLDEN_AXE, Items.GOLDEN_SWORD, Items.GOLDEN_HOE,
+                    UItems.GOLDEN_HORSE_SHOE, UItems.GOLDEN_POLEARM, UItems.GOLDEN_FEATHER, UItems.GOLDEN_WING,
+                    UItems.GOLDEN_OAK_SEEDS
+            ).forceAddTag(ConventionalItemTags.GOLD_INGOTS).forceAddTag(ConventionalItemTags.RAW_GOLD_ORES).forceAddTag(ConventionalItemTags.RAW_GOLD_BLOCKS)
+            .addOptionalTag(new Identifier("farmersdelight:golden_knife"));
+        getOrCreateTagBuilder(UTags.Items.LOOT_BUG_EPIC_DROPS).add(
+                Items.DIAMOND_BLOCK,
+                Items.DIAMOND_HELMET, Items.DIAMOND_BOOTS, Items.DIAMOND_LEGGINGS, Items.DIAMOND_CHESTPLATE,
+                Items.DIAMOND_HORSE_ARMOR,
+                Items.DIAMOND_PICKAXE, Items.DIAMOND_SHOVEL, Items.DIAMOND_AXE, Items.DIAMOND_SWORD, Items.DIAMOND_HOE,
+                UItems.DIAMOND_POLEARM
+        ).forceAddTag(UTags.Items.BADGES).forceAddTag(ConventionalItemTags.GOLD_INGOTS);
+        getOrCreateTagBuilder(UTags.Items.SHELLS).add(Items.NAUTILUS_SHELL, UItems.CLAM_SHELL, UItems.SCALLOP_SHELL, UItems.TURRET_SHELL);
+        getOrCreateTagBuilder(UTags.Items.SPECIAL_SHELLS).add(UItems.SHELLY);
+        getOrCreateTagBuilder(UTags.Items.ROCK_STEWS).add(UItems.ROCK_STEW);
+        getOrCreateTagBuilder(UTags.Items.HIGH_QUALITY_SEA_VEGETABLES)
+            .add(Items.DRIED_KELP_BLOCK, Items.GLOW_LICHEN)
+            .forceAddTag(UConventionalTags.Items.CORAL_BLOCKS);
+        getOrCreateTagBuilder(UTags.Items.LOW_QUALITY_SEA_VEGETABLES)
+            .add(Items.KELP, Items.DRIED_KELP, Items.SEAGRASS, Items.SEA_PICKLE)
+            .forceAddTag(UConventionalTags.Items.CORALS).forceAddTag(UConventionalTags.Items.CORAL_FANS);
+
+        exportForagingTags();
+        exportFarmersDelightItems();
+    }
+
+    private void copyBlockTags() {
+        copy(BlockTags.LEAVES, ItemTags.LEAVES);
+        copy(BlockTags.LOGS_THAT_BURN, ItemTags.LOGS_THAT_BURN);
+        copy(BlockTags.LOGS, ItemTags.LOGS);
+        copy(BlockTags.PLANKS, ItemTags.PLANKS);
+        copy(BlockTags.WOODEN_BUTTONS, ItemTags.WOODEN_BUTTONS);
+        copy(BlockTags.WOODEN_DOORS, ItemTags.WOODEN_DOORS);
+        copy(BlockTags.FENCE_GATES, ItemTags.FENCE_GATES);
+        copy(BlockTags.WOODEN_FENCES, ItemTags.WOODEN_FENCES);
+        copy(BlockTags.WOODEN_PRESSURE_PLATES, ItemTags.WOODEN_PRESSURE_PLATES);
+        copy(BlockTags.SLABS, ItemTags.SLABS);
+        copy(BlockTags.WOODEN_SLABS, ItemTags.WOODEN_SLABS);
+        copy(BlockTags.STAIRS, ItemTags.STAIRS);
+        copy(BlockTags.WOODEN_STAIRS, ItemTags.WOODEN_STAIRS);
+        copy(BlockTags.TRAPDOORS, ItemTags.TRAPDOORS);
+        copy(BlockTags.WOODEN_TRAPDOORS, ItemTags.WOODEN_TRAPDOORS);
+        copy(BlockTags.SAPLINGS, ItemTags.SAPLINGS);
+
+        copy(UTags.Blocks.ZAP_LOGS, UTags.Items.ZAP_LOGS);
+        copy(UTags.Blocks.WAXED_ZAP_LOGS, UTags.Items.WAXED_ZAP_LOGS);
+        copy(UTags.Blocks.PALM_LOGS, UTags.Items.PALM_LOGS);
+        copy(UTags.Blocks.CLOUD_BEDS, UTags.Items.CLOUD_BEDS);
+        copy(UTags.Blocks.CLOUD_SLABS, UTags.Items.CLOUD_SLABS);
+        copy(UTags.Blocks.CLOUD_STAIRS, UTags.Items.CLOUD_STAIRS);
+        copy(UTags.Blocks.CLOUD_BLOCKS, UTags.Items.CLOUD_BLOCKS);
+        copy(UTags.Blocks.CHITIN_BLOCKS, UTags.Items.CHITIN_BLOCKS);
+    }
+
+    private void exportForagingTags() {
+        getOrCreateTagBuilder(UTags.Items.FORAGE_BLINDING).add(Items.OXEYE_DAISY);
+        getOrCreateTagBuilder(UTags.Items.FORAGE_DANGEROUS).add(Items.POPPY, Items.LILY_OF_THE_VALLEY);
+        getOrCreateTagBuilder(UTags.Items.FORAGE_FILLING).add(Items.HAY_BLOCK);
+        getOrCreateTagBuilder(UTags.Items.FORAGE_SAFE).add(Items.BLUE_ORCHID, Items.RED_TULIP, Items.ORANGE_TULIP,
+                Items.PINK_TULIP, Items.CORNFLOWER, Items.PEONY, Items.SUNFLOWER, Items.DANDELION, Items.LILAC, Items.TALL_GRASS,
+                Items.DEAD_BUSH, Items.PINK_PETALS
+        ).forceAddTag(UConventionalTags.Items.MUSHROOMS).forceAddTag(ItemTags.SAPLINGS);
+        getOrCreateTagBuilder(UTags.Items.FORAGE_NAUSEATING).add(Items.GRASS, UItems.CIDER);
+        getOrCreateTagBuilder(UTags.Items.FORAGE_PRICKLY).add(Items.ROSE_BUSH).forceAddTag(ItemTags.SAPLINGS);
+        getOrCreateTagBuilder(UTags.Items.FORAGE_GLOWING).add(Items.AZURE_BLUET, Items.TORCHFLOWER);
+        getOrCreateTagBuilder(UTags.Items.FORAGE_RISKY).add(Items.ALLIUM, Items.WHITE_TULIP, UItems.BURNED_JUICE);
+        getOrCreateTagBuilder(UTags.Items.FORAGE_STRENGHENING).add(Items.FERN);
+        getOrCreateTagBuilder(UTags.Items.FORAGE_SEVERE_NAUSEATING).add(Items.PITCHER_PLANT);
+        getOrCreateTagBuilder(UTags.Items.FORAGE_SEVERE_PRICKLY).add(Items.LARGE_FERN);
+    }
+
+    private void exportConventionalTags() {
+        copy(UConventionalTags.Blocks.CONCRETES, UConventionalTags.Items.CONCRETES);
+        copy(UConventionalTags.Blocks.CONCRETE_POWDERS, UConventionalTags.Items.CONCRETE_POWDERS);
+        copy(UConventionalTags.Blocks.GLAZED_TERRACOTTAS, UConventionalTags.Items.GLAZED_TERRACOTTAS);
+        copy(UConventionalTags.Blocks.CORAL_BLOCKS, UConventionalTags.Items.CORAL_BLOCKS);
+        copy(UConventionalTags.Blocks.CORAL_FANS, UConventionalTags.Items.CORAL_FANS);
+        copy(UConventionalTags.Blocks.CORALS, UConventionalTags.Items.CORALS);
+        getOrCreateTagBuilder(UConventionalTags.Items.ACORNS).add(UItems.ACORN);
+        getOrCreateTagBuilder(UConventionalTags.Items.APPLES)
+            .add(Items.APPLE, Items.GOLDEN_APPLE, Items.ENCHANTED_GOLDEN_APPLE, UItems.ROTTEN_APPLE)
+            .forceAddTag(UTags.Items.FRESH_APPLES)
+            .addOptionalTag(new Identifier("c", "pyrite_apples")) // no idea which mod add pyrite apples
+        ;
+        getOrCreateTagBuilder(UConventionalTags.Items.BANANAS).add(UItems.BANANA);
+        getOrCreateTagBuilder(UConventionalTags.Items.RAW_FISH).add(Items.COD, Items.SALMON, Items.PUFFERFISH, Items.TROPICAL_FISH).addOptionalTag(new Identifier("c", "mollusks"));
+        getOrCreateTagBuilder(UConventionalTags.Items.COOKED_FISH).add(Items.COOKED_COD, Items.COOKED_SALMON, UItems.COOKED_TROPICAL_FISH, UItems.COOKED_PUFFERFISH, UItems.FRIED_AXOLOTL);
+        getOrCreateTagBuilder(UConventionalTags.Items.ROTTEN_FISH).add(UItems.ROTTEN_COD, UItems.ROTTEN_TROPICAL_FISH, UItems.ROTTEN_SALMON, UItems.ROTTEN_PUFFERFISH);
+        getOrCreateTagBuilder(ItemTags.FISHES).add(
+                UItems.COOKED_TROPICAL_FISH, UItems.COOKED_PUFFERFISH, UItems.FRIED_AXOLOTL,
+                UItems.ROTTEN_COD, UItems.ROTTEN_TROPICAL_FISH, UItems.ROTTEN_SALMON, UItems.ROTTEN_PUFFERFISH
+        );
+        getOrCreateTagBuilder(UConventionalTags.Items.COOKED_MEAT)
+            .add(Items.COOKED_PORKCHOP, Items.COOKED_BEEF, Items.COOKED_MUTTON, Items.COOKED_RABBIT, Items.COOKED_CHICKEN, Items.RABBIT_STEW)
+            .addOptionalTag(new Identifier("c", "cooked_bacon"))
+            .addOptionalTag(new Identifier("c", "cooked_beef"))
+            .addOptionalTag(new Identifier("c", "cooked_chicken"))
+            .addOptionalTag(new Identifier("c", "cooked_mutton"))
+            .addOptionalTag(new Identifier("c", "cooked_pork"))
+            .addOptionalTag(new Identifier("c", "fried_chickens"))
+            .addOptionalTag(new Identifier("c", "hamburgers"))
+            .addOptionalTag(new Identifier("c", "pork_and_beans"))
+            .addOptionalTag(new Identifier("c", "pork_jerkies"))
+            .addOptionalTag(new Identifier("c", "protien"));
+        getOrCreateTagBuilder(UConventionalTags.Items.RAW_MEAT)
+            .add(Items.PORKCHOP, Items.BEEF, Items.MUTTON, Items.RABBIT, Items.CHICKEN)
+            .addOptionalTag(new Identifier("c", "raw_bacon"))
+            .addOptionalTag(new Identifier("c", "raw_beef"))
+            .addOptionalTag(new Identifier("c", "raw_chicken"))
+            .addOptionalTag(new Identifier("c", "raw_mutton"))
+            .addOptionalTag(new Identifier("c", "raw_pork"))
+            .addOptionalTag(new Identifier("c", "lemon_chickens"));
+        getOrCreateTagBuilder(UConventionalTags.Items.ROTTEN_MEAT).add(Items.ROTTEN_FLESH);
+        getOrCreateTagBuilder(UConventionalTags.Items.ROTTEN_INSECT).add(Items.FERMENTED_SPIDER_EYE);
+        getOrCreateTagBuilder(UConventionalTags.Items.COOKED_INSECT);//.add(Items.FERMENTED_SPIDER_EYE); TODO
+        getOrCreateTagBuilder(UConventionalTags.Items.RAW_INSECT).add(Items.SPIDER_EYE, UItems.BUTTERFLY, UItems.WHEAT_WORMS, UBlocks.WORM_BLOCK.asItem());
+        getOrCreateTagBuilder(UConventionalTags.Items.WORMS).add(UItems.WHEAT_WORMS);
+        getOrCreateTagBuilder(UConventionalTags.Items.STICKS).add(Items.STICK);
+        getOrCreateTagBuilder(UConventionalTags.Items.ROCKS).add(UItems.ROCK);
+        getOrCreateTagBuilder(UConventionalTags.Items.PINECONES).add(UItems.PINECONE);
+        getOrCreateTagBuilder(UConventionalTags.Items.PINEAPPLES).add(UItems.PINEAPPLE);
+        getOrCreateTagBuilder(UConventionalTags.Items.MANGOES).add(UItems.MANGO);
+        getOrCreateTagBuilder(UConventionalTags.Items.MUSHROOMS).add(Items.RED_MUSHROOM, Items.BROWN_MUSHROOM);
+        getOrCreateTagBuilder(UConventionalTags.Items.MUFFINS).add(UItems.MUFFIN);
+        getOrCreateTagBuilder(UConventionalTags.Items.SEEDS).add(Items.BEETROOT_SEEDS, Items.MELON_SEEDS, Items.PUMPKIN_SEEDS, Items.TORCHFLOWER_SEEDS, Items.WHEAT_SEEDS)
+            .add(UItems.OAT_SEEDS)
+            .forceAddTag(UTags.Items.APPLE_SEEDS);
+        getOrCreateTagBuilder(UConventionalTags.Items.COOKIES).add(Items.COOKIE, UItems.OATMEAL_COOKIE, UItems.CHOCOLATE_OATMEAL_COOKIE, UItems.PINECONE_COOKIE);
+        getOrCreateTagBuilder(UConventionalTags.Items.OATMEALS).add(UItems.OATMEAL);
+        getOrCreateTagBuilder(UConventionalTags.Items.GRAIN).add(Items.WHEAT, UItems.OATS);
+        getOrCreateTagBuilder(UConventionalTags.Items.NUTS).add(UItems.BOWL_OF_NUTS)
+            .addOptionalTag(UConventionalTags.Items.CROPS_PEANUTS)
+            .forceAddTag(UConventionalTags.Items.ACORNS)
+            .addOptional(new Identifier("garnished", "nuts"))
+            .addOptional(new Identifier("garnished", "nut_mix"))
+            .addOptional(new Identifier("garnished", "neverable_delecacies"));
+        getOrCreateTagBuilder(UConventionalTags.Items.FRUITS)
+            .add(Items.MELON_SLICE, Items.SWEET_BERRIES, Items.GLOW_BERRIES, Items.CHORUS_FRUIT)
+            .add(UItems.JUICE, UItems.ZAP_APPLE, UItems.ZAP_BULB)
+            .forceAddTag(UConventionalTags.Items.MANGOES)
+            .forceAddTag(UConventionalTags.Items.PINEAPPLES)
+            .forceAddTag(UConventionalTags.Items.APPLES)
+            .forceAddTag(UConventionalTags.Items.BANANAS)
+            .addOptionalTag(new Identifier("garnished", "berries"));
+        getOrCreateTagBuilder(UConventionalTags.Items.DESSERTS).add(Items.CAKE, UItems.APPLE_PIE_SLICE).forceAddTag(UTags.Items.PIES);
+        getOrCreateTagBuilder(UConventionalTags.Items.CANDY).add(Items.SUGAR, UItems.ROCK_CANDY, UItems.CANDIED_APPLE);
+        getOrCreateTagBuilder(UTags.Items.BAKED_GOODS).add(
+                Items.BREAD, Items.COOKIE, Items.PUMPKIN_PIE,
+                UItems.MUFFIN, UItems.SCONE, UItems.COOKED_ZAP_APPLE, UItems.TOAST, UItems.BURNED_TOAST, UItems.JAM_TOAST, UItems.IMPORTED_OATS,
+                UItems.HAY_FRIES, UItems.CRISPY_HAY_FRIES, UItems.HORSE_SHOE_FRIES)
+            .forceAddTag(UConventionalTags.Items.OATMEALS)
+            .forceAddTag(UConventionalTags.Items.COOKIES);
+    }
+
+    private void exportFarmersDelightItems() {
+        getOrCreateTagBuilder(UTags.Items.COOLS_OFF_KIRINS)
+            .addOptional(new Identifier("farmersdelight", "melon_popsicle"))
+            .addOptional(new Identifier("farmersdelight", "melon_juice"));
+        getOrCreateTagBuilder(TagKey.of(RegistryKeys.ITEM, new Identifier("farmersdelight", "cabbage_roll_ingredients"))).add(UItems.OATS, UItems.ROCK, UItems.WHEAT_WORMS);
+        getOrCreateTagBuilder(TagKey.of(RegistryKeys.ITEM, new Identifier("farmersdelight", "comfort_foods"))).add(UItems.OATMEAL, UItems.ROCK_STEW, UItems.MUFFIN);
+        getOrCreateTagBuilder(UConventionalTags.Items.RAW_FISH)
+            .addOptional(new Identifier("farmersdelight", "cod_roll"))
+            .addOptional(new Identifier("farmersdelight", "salmon_roll"))
+            .addOptional(new Identifier("farmersdelight", "cod_slice"))
+            .addOptional(new Identifier("farmersdelight", "salmon_slice"));
+        getOrCreateTagBuilder(UConventionalTags.Items.COOKED_FISH)
+            .addOptional(new Identifier("farmersdelight", "fish_stew"))
+            .addOptional(new Identifier("farmersdelight", "baked_cod_stew"))
+            .addOptional(new Identifier("farmersdelight", "grilled_salmon"));
+        getOrCreateTagBuilder(UConventionalTags.Items.RAW_MEAT)
+            .addOptional(new Identifier("farmersdelight", "ham"));
+        getOrCreateTagBuilder(UConventionalTags.Items.COOKED_MEAT)
+            .addOptional(new Identifier("farmersdelight", "chicken_soup"))
+            .addOptional(new Identifier("farmersdelight", "bacon_and_eggs"))
+            .addOptional(new Identifier("farmersdelight", "pasta_with_meatballs"))
+            .addOptional(new Identifier("farmersdelight", "beef_stew"))
+            .addOptional(new Identifier("farmersdelight", "bone_broth"))
+            .addOptional(new Identifier("farmersdelight", "mutton_wrap"))
+            .addOptional(new Identifier("farmersdelight", "bacon_sandwich"))
+            .addOptional(new Identifier("farmersdelight", "hamburger"))
+            .addOptional(new Identifier("farmersdelight", "chicken_sandwich"))
+            .addOptional(new Identifier("farmersdelight", "barbecue_stick"))
+            .addOptional(new Identifier("farmersdelight", "smoked_ham"))
+            .addOptional(new Identifier("farmersdelight", "honey_glazed_ham"))
+            .addOptional(new Identifier("farmersdelight", "honey_glazed_ham_block"))
+            .addOptional(new Identifier("farmersdelight", "roast_chicken"))
+            .addOptional(new Identifier("farmersdelight", "roast_chicken_block"))
+            .addOptional(new Identifier("farmersdelight", "steak_and_potatoes"))
+            .addOptional(new Identifier("farmersdelight", "roasted_mutton_chops"))
+            .addOptional(new Identifier("farmersdelight", "pasta_with_mutton_chop"));
+        getOrCreateTagBuilder(UConventionalTags.Items.FRUITS)
+            .addOptional(new Identifier("farmersdelight", "pumpkin_slice"))
+            .addOptional(new Identifier("farmersdelight", "tomato"))
+            .addOptional(new Identifier("farmersdelight", "melon_juice"))
+            .addOptional(new Identifier("farmersdelight", "fruit_salad"));
+        getOrCreateTagBuilder(UConventionalTags.Items.DESSERTS)
+            .addOptional(new Identifier("farmersdelight", "sweet_berry_cheesecake"))
+            .addOptional(new Identifier("farmersdelight", "sweet_berry_cheesecake_slice"))
+            .addOptional(new Identifier("farmersdelight", "chocolate_pie_slice"))
+            .addOptional(new Identifier("farmersdelight", "cake_slice"))
+            .addOptional(new Identifier("farmersdelight", "apple_pie_slice"))
+            .addOptional(new Identifier("farmersdelight", "glow_berry_custard"));
+        getOrCreateTagBuilder(UConventionalTags.Items.COOKIES)
+            .addOptional(new Identifier("farmersdelight", "sweet_berry_cookie"))
+            .addOptional(new Identifier("farmersdelight", "honey_cookie"));
+        getOrCreateTagBuilder(UTags.Items.BAKED_GOODS)
+            .addOptional(new Identifier("farmersdelight", "wheat_dough"))
+            .addOptional(new Identifier("farmersdelight", "raw_pasta"))
+            .addOptional(new Identifier("farmersdelight", "pie_crust"))
+            .addOptional(new Identifier("farmersdelight", "egg_sandwich"));
+        getOrCreateTagBuilder(UTags.Items.HIGH_QUALITY_SEA_VEGETABLES)
+            .addOptional(new Identifier("farmersdelight", "kelp_roll"));
+        getOrCreateTagBuilder(UTags.Items.LOW_QUALITY_SEA_VEGETABLES)
+            .addOptional(new Identifier("farmersdelight", "kelp_roll_slice"));
+        getOrCreateTagBuilder(UTags.Items.FORAGE_FILLING)
+            .addOptional(new Identifier("farmersdelight", "horse_feed"))
+            .addOptional(new Identifier("farmersdelight", "rice_bale"))
+            .addOptional(new Identifier("farmersdelight", "straw_bale"));
+        getOrCreateTagBuilder(UTags.Items.FORAGE_SAFE)
+            .addOptional(new Identifier("farmersdelight", "sandy_shrub"))
+            .addOptional(new Identifier("farmersdelight", "wild_cabbages"))
+            .addOptional(new Identifier("farmersdelight", "wild_onions"))
+            .addOptional(new Identifier("farmersdelight", "wild_carrots"))
+            .addOptional(new Identifier("farmersdelight", "wild_beetroots"))
+            .addOptional(new Identifier("farmersdelight", "wild_rice"));
+        getOrCreateTagBuilder(UTags.Items.FORAGE_RISKY)
+            .addOptional(new Identifier("farmersdelight", "wild_tomatoes"))
+            .addOptional(new Identifier("farmersdelight", "wild_potatoes"))
+            .addOptionalTag(new Identifier("c", "meads"));
+    }
+}
diff --git a/src/main/java/com/minelittlepony/unicopia/diet/DietProfile.java b/src/main/java/com/minelittlepony/unicopia/diet/DietProfile.java
index a71c8499..b10a8143 100644
--- a/src/main/java/com/minelittlepony/unicopia/diet/DietProfile.java
+++ b/src/main/java/com/minelittlepony/unicopia/diet/DietProfile.java
@@ -5,11 +5,11 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Optional;
 import java.util.Set;
+import java.util.function.Consumer;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
 
 import org.jetbrains.annotations.Nullable;
-
 import com.minelittlepony.unicopia.entity.player.Pony;
 import com.minelittlepony.unicopia.item.ItemDuck;
 import com.mojang.datafixers.util.Pair;
@@ -19,33 +19,53 @@ import com.mojang.serialization.codecs.RecordCodecBuilder;
 import net.minecraft.client.item.TooltipContext;
 import net.minecraft.entity.player.PlayerEntity;
 import net.minecraft.item.FoodComponent;
-import net.minecraft.item.Item;
 import net.minecraft.item.ItemStack;
 import net.minecraft.network.PacketByteBuf;
-import net.minecraft.registry.RegistryKeys;
-import net.minecraft.registry.tag.TagKey;
 import net.minecraft.text.Text;
 import net.minecraft.util.Formatting;
+import net.minecraft.util.Identifier;
 import net.minecraft.util.UseAction;
 
 public record DietProfile(
         float defaultMultiplier,
         float foragingMultiplier,
         List<Multiplier> multipliers,
-        List<Effect> effects,
-        Optional<Effect> defaultEffect
+        List<FoodGroupEffects> effects,
+        Optional<FoodGroupEffects> defaultEffect
     ) {
     public static final DietProfile EMPTY = new DietProfile(1, 1, List.of(), List.of(), Optional.empty());
     public static final Codec<DietProfile> CODEC = RecordCodecBuilder.create(instance -> instance.group(
                 Codec.FLOAT.fieldOf("default_multiplier").forGetter(DietProfile::defaultMultiplier),
                 Codec.FLOAT.fieldOf("foraging_multiplier").forGetter(DietProfile::foragingMultiplier),
                 Codec.list(Multiplier.CODEC).fieldOf("multipliers").forGetter(DietProfile::multipliers),
-                Codec.list(Effect.CODEC).fieldOf("effects").forGetter(DietProfile::effects),
-                Effect.CODEC.optionalFieldOf("default_effect").forGetter(DietProfile::defaultEffect)
+                Codec.list(FoodGroupEffects.CODEC).fieldOf("effects").forGetter(DietProfile::effects),
+                FoodGroupEffects.CODEC.optionalFieldOf("default_effect").forGetter(DietProfile::defaultEffect)
     ).apply(instance, DietProfile::new));
 
     public DietProfile(PacketByteBuf buffer) {
-        this(buffer.readFloat(), buffer.readFloat(), buffer.readList(Multiplier::new), buffer.readList(Effect::new), buffer.readOptional(Effect::new));
+        this(buffer.readFloat(), buffer.readFloat(),
+                buffer.readList(Multiplier::new),
+                buffer.readList(b -> new FoodGroupEffects(b, FoodGroupKey.LOOKUP)),
+                buffer.readOptional(b -> new FoodGroupEffects(b, FoodGroupKey.LOOKUP))
+        );
+    }
+
+    public void validate(Consumer<String> issues, Predicate<Identifier> foodGroupExists) {
+        multipliers.stream().flatMap(i -> i.tags().stream()).forEach(key -> {
+            if (!foodGroupExists.test(key.id())) {
+                issues.accept("Multiplier referenced unknown food group: " + key.id());
+            }
+        });
+        effects.stream().flatMap(i -> i.tags().stream()).forEach(key -> {
+            if (!foodGroupExists.test(key.id())) {
+                issues.accept("Override defined for unknown food group: " + key.id());
+            }
+        });
+        defaultEffect.stream().flatMap(i -> i.tags().stream()).forEach(key -> {
+            if (!foodGroupExists.test(key.id())) {
+                issues.accept("Default override defined for unknown food group: " + key.id());
+            }
+        });
     }
 
     public void toBuffer(PacketByteBuf buffer) {
@@ -61,7 +81,7 @@ public record DietProfile(
     }
 
     public Optional<Effect> findEffect(ItemStack stack) {
-        return effects.stream().filter(m -> m.test(stack)).findFirst().or(this::defaultEffect);
+        return effects.stream().filter(m -> m.test(stack)).findFirst().or(this::defaultEffect).map(Effect.class::cast);
     }
 
     static boolean isForaged(ItemStack stack) {
@@ -145,11 +165,11 @@ public record DietProfile(
     }
 
     public record Multiplier(
-            Set<TagKey<Item>> tags,
+            Set<FoodGroupKey> tags,
             float hunger,
             float saturation
     ) implements Predicate<ItemStack> {
-        public static final Codec<Set<TagKey<Item>>> TAGS_CODEC = Codec.list(TagKey.unprefixedCodec(RegistryKeys.ITEM)).xmap(
+        public static final Codec<Set<FoodGroupKey>> TAGS_CODEC = FoodGroupKey.CODEC.listOf().xmap(
                 l -> l.stream().distinct().collect(Collectors.toSet()),
                 set -> new ArrayList<>(set)
         );
@@ -160,12 +180,12 @@ public record DietProfile(
         ).apply(instance, Multiplier::new));
 
         public Multiplier(PacketByteBuf buffer) {
-            this(buffer.readCollection(HashSet::new, p -> TagKey.of(RegistryKeys.ITEM, p.readIdentifier())), buffer.readFloat(), buffer.readFloat());
+            this(buffer.readCollection(HashSet::new, p -> FoodGroupKey.LOOKUP.apply(p.readIdentifier())), buffer.readFloat(), buffer.readFloat());
         }
 
         @Override
         public boolean test(ItemStack stack) {
-            return tags.stream().anyMatch(tag -> stack.isIn(tag));
+            return tags.stream().anyMatch(tag -> tag.contains(stack));
         }
 
         public void toBuffer(PacketByteBuf buffer) {
@@ -173,5 +193,30 @@ public record DietProfile(
             buffer.writeFloat(hunger);
             buffer.writeFloat(saturation);
         }
+
+        public static final class Builder {
+            private Set<FoodGroupKey> tags = new HashSet<>();
+            private float hunger = 1;
+            private float saturation = 1;
+
+            public Builder tag(Identifier tag) {
+                tags.add(FoodGroupKey.LOOKUP.apply(tag));
+                return this;
+            }
+
+            public Builder hunger(float hunger) {
+                this.hunger = hunger;
+                return this;
+            }
+
+            public Builder saturation(float saturation) {
+                this.saturation = saturation;
+                return this;
+            }
+
+            public Multiplier build() {
+                return new Multiplier(tags, hunger, saturation);
+            }
+        }
     }
 }
diff --git a/src/main/java/com/minelittlepony/unicopia/diet/DietsLoader.java b/src/main/java/com/minelittlepony/unicopia/diet/DietsLoader.java
index 963efb77..0c4eb7f5 100644
--- a/src/main/java/com/minelittlepony/unicopia/diet/DietsLoader.java
+++ b/src/main/java/com/minelittlepony/unicopia/diet/DietsLoader.java
@@ -1,12 +1,9 @@
 package com.minelittlepony.unicopia.diet;
 
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
-import java.util.Optional;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.Executor;
-
 import org.slf4j.Logger;
 
 import com.google.gson.JsonElement;
@@ -36,9 +33,24 @@ public class DietsLoader implements IdentifiableResourceReloadListener {
             Profiler prepareProfiler, Profiler applyProfiler,
             Executor prepareExecutor, Executor applyExecutor) {
 
-        var dietsLoadTask = loadData(manager, prepareExecutor, "diets/races").thenApplyAsync(data -> {
+        CompletableFuture<Map<Identifier, Effect>> foodGroupsFuture = CompletableFuture.supplyAsync(() -> {
+            Map<Identifier, Effect> foodGroups = new HashMap<>();
+            for (var group : loadData(manager, prepareExecutor, "diet/food_groups").entrySet()) {
+                try {
+                    FoodGroup.CODEC.parse(JsonOps.INSTANCE, group.getValue())
+                        .resultOrPartial(error -> LOGGER.error("Could not load food group {}: {}", group.getKey(), error))
+                        .ifPresent(value -> {
+                            foodGroups.put(group.getKey(), new FoodGroup(group.getKey(), value));
+                        });
+                } catch (Throwable t) {
+                    LOGGER.error("Could not load food effects {}", group.getKey(), t);
+                }
+            }
+            return foodGroups;
+        }, prepareExecutor);
+        CompletableFuture<Map<Race, DietProfile>> profilesFuture = CompletableFuture.supplyAsync(() -> {
             Map<Race, DietProfile> profiles = new HashMap<>();
-            for (var entry : data.entrySet()) {
+            for (var entry : loadData(manager, prepareExecutor, "diet/races").entrySet()) {
                 Identifier id = entry.getKey();
                 try {
                     Race.REGISTRY.getOrEmpty(id).ifPresentOrElse(race -> {
@@ -53,33 +65,26 @@ public class DietsLoader implements IdentifiableResourceReloadListener {
             return profiles;
         }, prepareExecutor);
 
-        var effectsLoadTask = loadData(manager, prepareExecutor, "diets/food_effects").thenApplyAsync(data -> data.entrySet().stream()
-                    .map(entry -> {
-                        try {
-                        return Effect.CODEC.parse(JsonOps.INSTANCE, entry.getValue())
-                                .resultOrPartial(error -> LOGGER.error("Could not load food effect {}: {}", entry.getKey(), error));
-                        } catch (Throwable t) {
-                            LOGGER.error("Could not load food effects {}", entry.getKey(), t);
-                        }
-                        return Optional.<Effect>empty();
-                    })
-                            .filter(Optional::isPresent)
-                            .map(Optional::get)
-                            .toList(), prepareExecutor);
-
-        return CompletableFuture.allOf(dietsLoadTask, effectsLoadTask).thenCompose(sync::whenPrepared).thenRunAsync(() -> {
-            PonyDiets.load(new PonyDiets(
-                    dietsLoadTask.getNow(Map.of()),
-                    effectsLoadTask.getNow(List.of())
-            ));
+        return CompletableFuture.allOf(foodGroupsFuture, profilesFuture).thenCompose(sync::whenPrepared).thenAcceptAsync(v -> {
+            var profiles = profilesFuture.getNow(Map.of());
+            var foodGroups = foodGroupsFuture.getNow(Map.of());
+            profiles.entrySet().removeIf(entry -> {
+                StringBuilder issueList = new StringBuilder();
+                entry.getValue().validate(issue -> {
+                    issueList.append(System.lineSeparator()).append(issue);
+                }, foodGroups::containsKey);
+                if (!issueList.isEmpty()) {
+                    LOGGER.error("Could not load diet profile {}. Caused by {}", entry.getKey(), issueList.toString());
+                }
+                return issueList.isEmpty();
+            });
+            PonyDiets.load(new PonyDiets(profiles, foodGroups));
         }, applyExecutor);
     }
 
-    private static CompletableFuture<Map<Identifier, JsonElement>> loadData(ResourceManager manager, Executor prepareExecutor, String path) {
-        return CompletableFuture.supplyAsync(() -> {
-            Map<Identifier, JsonElement> results = new HashMap<>();
-            JsonDataLoader.load(manager, path, Resources.GSON, results);
-            return results;
-        });
+    private static Map<Identifier, JsonElement> loadData(ResourceManager manager, Executor prepareExecutor, String path) {
+        Map<Identifier, JsonElement> results = new HashMap<>();
+        JsonDataLoader.load(manager, path, Resources.GSON, results);
+        return results;
     }
 }
diff --git a/src/main/java/com/minelittlepony/unicopia/diet/Effect.java b/src/main/java/com/minelittlepony/unicopia/diet/Effect.java
index 9b7ba05d..af9ad3d9 100644
--- a/src/main/java/com/minelittlepony/unicopia/diet/Effect.java
+++ b/src/main/java/com/minelittlepony/unicopia/diet/Effect.java
@@ -4,54 +4,29 @@ import java.util.List;
 import java.util.Optional;
 import java.util.function.Predicate;
 
-import com.minelittlepony.unicopia.entity.player.Pony;
-import com.mojang.serialization.Codec;
-import com.mojang.serialization.codecs.RecordCodecBuilder;
-
 import net.minecraft.client.item.TooltipContext;
 import net.minecraft.item.FoodComponent;
-import net.minecraft.item.Item;
 import net.minecraft.item.ItemStack;
 import net.minecraft.network.PacketByteBuf;
-import net.minecraft.registry.RegistryKeys;
-import net.minecraft.registry.tag.TagKey;
 import net.minecraft.text.Text;
 import net.minecraft.util.Formatting;
 import net.minecraft.util.UseAction;
-import net.minecraft.util.Util;
 
-public record Effect(
-        List<TagKey<Item>> tags,
-        Optional<FoodComponent> foodComponent,
-        Ailment ailment
-) implements Predicate<ItemStack> {
-    public static final Effect EMPTY = new Effect(List.of(), Optional.empty(), Ailment.EMPTY);
-    public static final Codec<Effect> CODEC = RecordCodecBuilder.create(instance -> instance.group(
-            TagKey.unprefixedCodec(RegistryKeys.ITEM).listOf().fieldOf("tags").forGetter(Effect::tags),
-            FoodAttributes.CODEC.optionalFieldOf("food_component").forGetter(Effect::foodComponent),
-            Ailment.CODEC.fieldOf("ailment").forGetter(Effect::ailment)
-    ).apply(instance, Effect::new));
+public interface Effect extends Predicate<ItemStack> {
+    Effect EMPTY = new FoodGroupEffects(List.of(), Optional.empty(), Ailment.EMPTY);
 
-    public Effect(PacketByteBuf buffer) {
-        this(buffer.readList(b -> TagKey.of(RegistryKeys.ITEM, b.readIdentifier())), buffer.readOptional(FoodAttributes::read), new Ailment(buffer));
-    }
+    List<FoodGroupKey> tags();
 
-    public void afflict(Pony pony, ItemStack stack) {
-        ailment().effects().afflict(pony.asEntity(), stack);
-    }
+    Optional<FoodComponent> foodComponent();
 
-    public void appendTooltip(ItemStack stack, List<Text> tooltip, TooltipContext context) {
-        int size = tooltip.size();
-        tags.forEach(tag -> {
-            if (stack.isIn(tag)) {
-                tooltip.add(Text.literal(" ").append(Text.translatable(Util.createTranslationKey("tag", tag.id()))).formatted(Formatting.GRAY));
-            }
-        });
-        if (tooltip.size() == size) {
+    Ailment ailment();
+
+    default void appendTooltip(ItemStack stack, List<Text> tooltip, TooltipContext context) {
+        if (!test(stack)) {
             if (stack.isFood()) {
-                tooltip.add(Text.literal(" ").append(Text.translatable("tag.unicopia.food_types.misc")).formatted(Formatting.GRAY));
+                tooltip.add(Text.literal(" ").append(Text.translatable("food_group.unicopia.misc")).formatted(Formatting.GRAY));
             } else if (stack.getUseAction() == UseAction.DRINK) {
-                tooltip.add(Text.literal(" ").append(Text.translatable("tag.unicopia.food_types.drinks")).formatted(Formatting.GRAY));
+                tooltip.add(Text.literal(" ").append(Text.translatable("food_group.unicopia.drinks")).formatted(Formatting.GRAY));
             }
         }
 
@@ -63,14 +38,14 @@ public record Effect(
         }
     }
 
-    public void toBuffer(PacketByteBuf buffer) {
-        buffer.writeCollection(tags, (b, t) -> b.writeIdentifier(t.id()));
-        buffer.writeOptional(foodComponent, FoodAttributes::write);
-        ailment.toBuffer(buffer);
+    default void toBuffer(PacketByteBuf buffer) {
+        buffer.writeCollection(tags(), (b, t) -> b.writeIdentifier(t.id()));
+        buffer.writeOptional(foodComponent(), FoodAttributes::write);
+        ailment().toBuffer(buffer);
     }
 
     @Override
-    public boolean test(ItemStack stack) {
-        return tags.stream().anyMatch(stack::isIn);
+    default boolean test(ItemStack stack) {
+        return tags().stream().anyMatch(tag -> tag.contains(stack));
     }
-}
\ No newline at end of file
+}
diff --git a/src/main/java/com/minelittlepony/unicopia/diet/FoodGroup.java b/src/main/java/com/minelittlepony/unicopia/diet/FoodGroup.java
new file mode 100644
index 00000000..173b1fef
--- /dev/null
+++ b/src/main/java/com/minelittlepony/unicopia/diet/FoodGroup.java
@@ -0,0 +1,56 @@
+package com.minelittlepony.unicopia.diet;
+
+import java.util.List;
+import java.util.Optional;
+
+import com.mojang.serialization.Codec;
+import com.mojang.serialization.codecs.RecordCodecBuilder;
+
+import net.minecraft.client.item.TooltipContext;
+import net.minecraft.item.FoodComponent;
+import net.minecraft.item.ItemStack;
+import net.minecraft.network.PacketByteBuf;
+import net.minecraft.text.Text;
+import net.minecraft.util.Formatting;
+import net.minecraft.util.Identifier;
+import net.minecraft.util.Util;
+
+public record FoodGroup(
+        Identifier id,
+        FoodGroupEffects attributes) implements Effect {
+    public static final Codec<FoodGroupEffects> CODEC = RecordCodecBuilder.create(instance -> instance.group(
+            FoodGroupKey.TAG_CODEC.listOf().fieldOf("tags").forGetter(FoodGroupEffects::tags),
+            FoodAttributes.CODEC.optionalFieldOf("food_component").forGetter(FoodGroupEffects::foodComponent),
+            Ailment.CODEC.fieldOf("ailment").forGetter(FoodGroupEffects::ailment)
+    ).apply(instance, FoodGroupEffects::new));
+
+    public FoodGroup(PacketByteBuf buffer) {
+        this(buffer.readIdentifier(), new FoodGroupEffects(buffer, FoodGroupKey.TAG_ID_LOOKUP));
+    }
+
+    @Override
+    public List<FoodGroupKey> tags() {
+        return attributes.tags();
+    }
+
+    @Override
+    public Optional<FoodComponent> foodComponent() {
+        return attributes.foodComponent();
+    }
+
+    @Override
+    public Ailment ailment() {
+        return attributes.ailment();
+    }
+    @Override
+    public void appendTooltip(ItemStack stack, List<Text> tooltip, TooltipContext context) {
+        tooltip.add(Text.literal(" ").append(Text.translatable(Util.createTranslationKey("food_group", id()))).formatted(Formatting.GRAY));
+        Effect.super.appendTooltip(stack, tooltip, context);
+    }
+
+    @Override
+    public void toBuffer(PacketByteBuf buffer) {
+        buffer.writeIdentifier(id());
+        Effect.super.toBuffer(buffer);
+    }
+}
diff --git a/src/main/java/com/minelittlepony/unicopia/diet/FoodGroupEffects.java b/src/main/java/com/minelittlepony/unicopia/diet/FoodGroupEffects.java
new file mode 100644
index 00000000..ad207ed1
--- /dev/null
+++ b/src/main/java/com/minelittlepony/unicopia/diet/FoodGroupEffects.java
@@ -0,0 +1,86 @@
+package com.minelittlepony.unicopia.diet;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.function.Function;
+
+import com.minelittlepony.unicopia.diet.affliction.Affliction;
+import com.minelittlepony.unicopia.item.UFoodComponents;
+import com.mojang.serialization.Codec;
+import com.mojang.serialization.codecs.RecordCodecBuilder;
+
+import net.minecraft.client.item.TooltipContext;
+import net.minecraft.item.FoodComponent;
+import net.minecraft.item.Item;
+import net.minecraft.item.ItemStack;
+import net.minecraft.network.PacketByteBuf;
+import net.minecraft.registry.RegistryKeys;
+import net.minecraft.registry.tag.TagKey;
+import net.minecraft.text.Text;
+import net.minecraft.util.Formatting;
+import net.minecraft.util.Identifier;
+import net.minecraft.util.Util;
+
+public record FoodGroupEffects(
+        List<FoodGroupKey> tags,
+        Optional<FoodComponent> foodComponent,
+        Ailment ailment
+) implements Effect {
+    public static final Codec<FoodGroupEffects> CODEC = RecordCodecBuilder.create(instance -> instance.group(
+            FoodGroupKey.CODEC.listOf().fieldOf("tags").forGetter(FoodGroupEffects::tags),
+            FoodAttributes.CODEC.optionalFieldOf("food_component").forGetter(FoodGroupEffects::foodComponent),
+            Ailment.CODEC.fieldOf("ailment").forGetter(FoodGroupEffects::ailment)
+    ).apply(instance, FoodGroupEffects::new));
+
+    public FoodGroupEffects(PacketByteBuf buffer, Function<Identifier, FoodGroupKey> lookup) {
+        this(buffer.readList(b -> lookup.apply(b.readIdentifier())), buffer.readOptional(FoodAttributes::read), new Ailment(buffer));
+    }
+
+    @Override
+    public void appendTooltip(ItemStack stack, List<Text> tooltip, TooltipContext context) {
+        tags.forEach(tag -> {
+            if (tag.contains(stack)) {
+                tooltip.add(Text.literal(" ").append(Text.translatable(Util.createTranslationKey("tag", tag.id()))).formatted(Formatting.GRAY));
+            }
+        });
+        Effect.super.appendTooltip(stack, tooltip, context);
+    }
+
+    public static final class Builder {
+        private final List<FoodGroupKey> tags = new ArrayList<>();
+        private Optional<FoodComponent> foodComponent = Optional.empty();
+        private Ailment ailment = new Ailment(Affliction.EMPTY);
+
+        public Builder tag(Identifier tag) {
+            return tag(TagKey.of(RegistryKeys.ITEM, tag));
+        }
+
+        public Builder tag(TagKey<Item> tag) {
+            tags.add(FoodGroupKey.TAG_LOOKUP.apply(tag));
+            return this;
+        }
+
+        public Builder ailment(Affliction affliction) {
+            ailment = new Ailment(affliction);
+            return this;
+        }
+
+        public Builder food(int hunger, float saturation) {
+            return food(UFoodComponents.builder(hunger, saturation));
+        }
+
+        public Builder food(FoodComponent.Builder food) {
+            return food(food.build());
+        }
+
+        public Builder food(FoodComponent food) {
+            foodComponent = Optional.of(food);
+            return this;
+        }
+
+        public FoodGroupEffects build() {
+            return new FoodGroupEffects(tags, foodComponent, ailment);
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/minelittlepony/unicopia/diet/FoodGroupKey.java b/src/main/java/com/minelittlepony/unicopia/diet/FoodGroupKey.java
new file mode 100644
index 00000000..567c4a36
--- /dev/null
+++ b/src/main/java/com/minelittlepony/unicopia/diet/FoodGroupKey.java
@@ -0,0 +1,80 @@
+package com.minelittlepony.unicopia.diet;
+
+import java.util.function.Function;
+
+import com.minelittlepony.unicopia.Debug;
+import com.minelittlepony.unicopia.Unicopia;
+import com.mojang.serialization.Codec;
+
+import net.minecraft.item.Item;
+import net.minecraft.item.ItemStack;
+import net.minecraft.registry.Registries;
+import net.minecraft.registry.RegistryKeys;
+import net.minecraft.registry.tag.TagKey;
+import net.minecraft.util.Identifier;
+import net.minecraft.util.Util;
+
+public interface FoodGroupKey {
+    Function<Identifier, FoodGroupKey> LOOKUP = Util.memoize(id -> {
+        return new FoodGroupKey() {
+            @Override
+            public Identifier id() {
+                return id;
+            }
+
+            @Override
+            public boolean contains(ItemStack stack) {
+                var group = PonyDiets.getEffect(id);
+                return group != null && group.test(stack);
+            }
+
+            @Override
+            public boolean equals(Object o) {
+                return o == this && (o instanceof FoodGroupKey k && k.id().equals(id()));
+            }
+
+            @Override
+            public int hashCode() {
+                return id().hashCode();
+            }
+        };
+    });
+    Function<TagKey<Item>, FoodGroupKey> TAG_LOOKUP = Util.memoize(tag -> {
+        return new FoodGroupKey() {
+            private boolean check;
+            @Override
+            public Identifier id() {
+                return tag.id();
+            }
+
+            @Override
+            public boolean contains(ItemStack stack) {
+                if (Debug.CHECK_GAME_VALUES && !check) {
+                    check = true;
+                    if (Registries.ITEM.getEntryList(tag).isEmpty()) {
+                        Unicopia.LOGGER.info("Tag is empty: " + tag.id());
+                    }
+                }
+
+                return stack.isIn(tag);
+            }
+
+            @Override
+            public boolean equals(Object o) {
+                return o == this && (o instanceof FoodGroupKey k && k.id().equals(id()));
+            }
+
+            @Override
+            public int hashCode() {
+                return id().hashCode();
+            }
+        };
+    });
+    Function<Identifier, FoodGroupKey> TAG_ID_LOOKUP = id -> TAG_LOOKUP.apply(TagKey.of(RegistryKeys.ITEM, id));
+    Codec<FoodGroupKey> CODEC = Identifier.CODEC.xmap(LOOKUP, FoodGroupKey::id);
+    Codec<FoodGroupKey> TAG_CODEC = TagKey.unprefixedCodec(RegistryKeys.ITEM).xmap(TAG_LOOKUP, k -> TagKey.of(RegistryKeys.ITEM, k.id()));
+
+    Identifier id();
+
+    boolean contains(ItemStack stack);
+}
diff --git a/src/main/java/com/minelittlepony/unicopia/diet/PonyDiets.java b/src/main/java/com/minelittlepony/unicopia/diet/PonyDiets.java
index 3566bf06..54990fee 100644
--- a/src/main/java/com/minelittlepony/unicopia/diet/PonyDiets.java
+++ b/src/main/java/com/minelittlepony/unicopia/diet/PonyDiets.java
@@ -1,8 +1,11 @@
 package com.minelittlepony.unicopia.diet;
 
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
+import java.util.function.Function;
+import java.util.stream.Collectors;
 
 import org.jetbrains.annotations.Nullable;
 
@@ -18,35 +21,44 @@ import net.minecraft.network.PacketByteBuf;
 import net.minecraft.text.Text;
 import net.minecraft.util.Formatting;
 import net.minecraft.util.Hand;
+import net.minecraft.util.Identifier;
 import net.minecraft.util.TypedActionResult;
 import net.minecraft.world.World;
 
 public class PonyDiets implements DietView {
     private final Map<Race, DietProfile> diets;
-    private final List<Effect> effects;
+    private final Map<Identifier, Effect> effects;
 
-    private static PonyDiets INSTANCE = new PonyDiets(Map.of(), List.of());
+    private static PonyDiets INSTANCE = new PonyDiets(Map.of(), Map.of());
 
     public static PonyDiets getInstance() {
         return INSTANCE;
     }
 
+    @Nullable
+    static Effect getEffect(Identifier id) {
+        return INSTANCE.effects.get(id);
+    }
+
     public static void load(PonyDiets diets) {
         INSTANCE = diets;
     }
 
-    PonyDiets(Map<Race, DietProfile> diets, List<Effect> effects) {
+    PonyDiets(Map<Race, DietProfile> diets, Map<Identifier, Effect> effects) {
         this.diets = diets;
         this.effects = effects;
     }
 
     public PonyDiets(PacketByteBuf buffer) {
-        this(buffer.readMap(b -> b.readRegistryValue(Race.REGISTRY), DietProfile::new), buffer.readList(Effect::new));
+        this(
+                buffer.readMap(b -> b.readRegistryValue(Race.REGISTRY), DietProfile::new),
+                buffer.readCollection(ArrayList::new, FoodGroup::new).stream().collect(Collectors.toMap(FoodGroup::id, Function.identity()))
+        );
     }
 
     public void toBuffer(PacketByteBuf buffer) {
         buffer.writeMap(diets, (b, r) -> b.writeRegistryValue(Race.REGISTRY, r), (b, e) -> e.toBuffer(b));
-        buffer.writeCollection(effects, (b, e) -> e.toBuffer(b));
+        buffer.writeCollection(effects.values(), (b, e) -> e.toBuffer(b));
     }
 
     private DietProfile getDiet(Pony pony) {
@@ -54,7 +66,7 @@ public class PonyDiets implements DietView {
     }
 
     Effect getEffects(ItemStack stack) {
-        return effects.stream().filter(effect -> effect.test(stack)).findFirst().orElse(Effect.EMPTY);
+        return effects.values().stream().filter(effect -> effect.test(stack)).findFirst().orElse(Effect.EMPTY);
     }
 
     private Effect getEffects(ItemStack stack, Pony pony) {
@@ -71,7 +83,7 @@ public class PonyDiets implements DietView {
     @Override
     public void finishUsing(ItemStack stack, World world, LivingEntity entity) {
         if (initEdibility(stack, entity)) {
-            Pony.of(entity).ifPresent(pony -> getEffects(stack, pony).afflict(pony, stack));
+            Pony.of(entity).ifPresent(pony -> getEffects(stack, pony).ailment().effects().afflict(pony.asEntity(), stack));
         }
     }
 
diff --git a/src/main/java/com/minelittlepony/unicopia/diet/affliction/Affliction.java b/src/main/java/com/minelittlepony/unicopia/diet/affliction/Affliction.java
index 013d3f51..ff228b31 100644
--- a/src/main/java/com/minelittlepony/unicopia/diet/affliction/Affliction.java
+++ b/src/main/java/com/minelittlepony/unicopia/diet/affliction/Affliction.java
@@ -37,7 +37,7 @@ public interface Affliction {
             affliction -> ((CompoundAffliction)affliction).afflictions
     )).xmap(
             either -> either.left().or(either::right).get(),
-            affliction -> affliction instanceof CompoundAffliction ? Either.left(affliction) : Either.right(affliction)
+            affliction -> affliction instanceof CompoundAffliction ? Either.right(affliction) : Either.left(affliction)
     );
 
     void afflict(PlayerEntity player, ItemStack stack);
diff --git a/src/main/java/com/minelittlepony/unicopia/diet/affliction/ClearLoveSicknessAffliction.java b/src/main/java/com/minelittlepony/unicopia/diet/affliction/ClearLoveSicknessAffliction.java
index 79343432..ab8786a4 100644
--- a/src/main/java/com/minelittlepony/unicopia/diet/affliction/ClearLoveSicknessAffliction.java
+++ b/src/main/java/com/minelittlepony/unicopia/diet/affliction/ClearLoveSicknessAffliction.java
@@ -7,7 +7,7 @@ import net.minecraft.entity.player.PlayerEntity;
 import net.minecraft.item.ItemStack;
 import net.minecraft.network.PacketByteBuf;
 
-final class ClearLoveSicknessAffliction implements Affliction {
+public final class ClearLoveSicknessAffliction implements Affliction {
     public static final ClearLoveSicknessAffliction INSTANCE = new ClearLoveSicknessAffliction();
     public static final Codec<ClearLoveSicknessAffliction> CODEC = Codec.unit(INSTANCE);
 
@@ -21,6 +21,7 @@ final class ClearLoveSicknessAffliction implements Affliction {
         player.heal(stack.isFood() ? stack.getItem().getFoodComponent().getHunger() : 1);
         player.removeStatusEffect(StatusEffects.NAUSEA);
         player.removeStatusEffect(UEffects.FOOD_POISONING);
+        player.removeStatusEffect(StatusEffects.WEAKNESS);
     }
 
     @Override
diff --git a/src/main/java/com/minelittlepony/unicopia/diet/affliction/CompoundAffliction.java b/src/main/java/com/minelittlepony/unicopia/diet/affliction/CompoundAffliction.java
index d41cf4ad..ff77dcbd 100644
--- a/src/main/java/com/minelittlepony/unicopia/diet/affliction/CompoundAffliction.java
+++ b/src/main/java/com/minelittlepony/unicopia/diet/affliction/CompoundAffliction.java
@@ -7,7 +7,7 @@ import net.minecraft.item.ItemStack;
 import net.minecraft.network.PacketByteBuf;
 import net.minecraft.text.Text;
 
-class CompoundAffliction implements Affliction {
+public class CompoundAffliction implements Affliction {
     public final List<Affliction> afflictions;
     private final Text name;
 
@@ -18,6 +18,10 @@ class CompoundAffliction implements Affliction {
         });
     }
 
+    public static CompoundAffliction of(Affliction...afflictions) {
+        return new CompoundAffliction(List.of(afflictions));
+    }
+
     public CompoundAffliction(PacketByteBuf buffer) {
         this(buffer.readList(Affliction::read));
     }
diff --git a/src/main/java/com/minelittlepony/unicopia/diet/affliction/HealingAffliction.java b/src/main/java/com/minelittlepony/unicopia/diet/affliction/HealingAffliction.java
index 71590879..8e6bc53d 100644
--- a/src/main/java/com/minelittlepony/unicopia/diet/affliction/HealingAffliction.java
+++ b/src/main/java/com/minelittlepony/unicopia/diet/affliction/HealingAffliction.java
@@ -8,7 +8,7 @@ import net.minecraft.item.ItemStack;
 import net.minecraft.network.PacketByteBuf;
 import net.minecraft.text.Text;
 
-record HealingAffliction(float health) implements Affliction {
+public record HealingAffliction(float health) implements Affliction {
     public static final Codec<HealingAffliction> CODEC = RecordCodecBuilder.create(instance -> instance.group(
             Codec.FLOAT.fieldOf("health").forGetter(HealingAffliction::health)
     ).apply(instance, HealingAffliction::new));
diff --git a/src/main/java/com/minelittlepony/unicopia/diet/affliction/Range.java b/src/main/java/com/minelittlepony/unicopia/diet/affliction/Range.java
index ed84ad97..78c3abe1 100644
--- a/src/main/java/com/minelittlepony/unicopia/diet/affliction/Range.java
+++ b/src/main/java/com/minelittlepony/unicopia/diet/affliction/Range.java
@@ -7,7 +7,7 @@ import com.mojang.serialization.codecs.RecordCodecBuilder;
 import net.minecraft.network.PacketByteBuf;
 import net.minecraft.util.dynamic.Codecs;
 
-record Range(int min, int max) {
+public record Range(int min, int max) {
     public static final Codec<Range> CODEC = Codecs.xor(
             Codec.INT.xmap(value -> Range.of(value, -1), range -> range.min()),
             RecordCodecBuilder.<Range>create(instance -> instance.group(
@@ -20,6 +20,10 @@ record Range(int min, int max) {
         return new Range(min, max);
     }
 
+    public static Range of(int exact) {
+        return of(exact, exact);
+    }
+
     public static Range of(PacketByteBuf buffer) {
         return of(buffer.readInt(), buffer.readInt());
     }
diff --git a/src/main/java/com/minelittlepony/unicopia/diet/affliction/StatusEffectAffliction.java b/src/main/java/com/minelittlepony/unicopia/diet/affliction/StatusEffectAffliction.java
index d0c0b91c..9bc7adff 100644
--- a/src/main/java/com/minelittlepony/unicopia/diet/affliction/StatusEffectAffliction.java
+++ b/src/main/java/com/minelittlepony/unicopia/diet/affliction/StatusEffectAffliction.java
@@ -4,6 +4,7 @@ import com.mojang.serialization.Codec;
 import com.mojang.serialization.codecs.RecordCodecBuilder;
 
 import net.minecraft.entity.attribute.EntityAttributes;
+import net.minecraft.entity.effect.StatusEffect;
 import net.minecraft.entity.effect.StatusEffectInstance;
 import net.minecraft.entity.player.PlayerEntity;
 import net.minecraft.item.ItemStack;
@@ -11,25 +12,24 @@ import net.minecraft.network.PacketByteBuf;
 import net.minecraft.registry.Registries;
 import net.minecraft.text.MutableText;
 import net.minecraft.text.Text;
-import net.minecraft.util.Identifier;
 import net.minecraft.util.StringHelper;
 import net.minecraft.util.math.MathHelper;
 
-record StatusEffectAffliction(Identifier effect, Range seconds, Range amplifier, int chance) implements Affliction {
+public record StatusEffectAffliction(StatusEffect effect, Range seconds, Range amplifier, int chance) implements Affliction {
     public static final Codec<StatusEffectAffliction> CODEC = RecordCodecBuilder.create(instance -> instance.group(
-            Identifier.CODEC.fieldOf("effect").forGetter(StatusEffectAffliction::effect),
+            Registries.STATUS_EFFECT.getCodec().fieldOf("effect").forGetter(StatusEffectAffliction::effect),
             Range.CODEC.fieldOf("seconds").forGetter(StatusEffectAffliction::seconds),
             Range.CODEC.optionalFieldOf("amplifier", Range.of(0, -1)).forGetter(StatusEffectAffliction::amplifier),
             Codec.INT.optionalFieldOf("chance", 0).forGetter(StatusEffectAffliction::chance)
     ).apply(instance, StatusEffectAffliction::new));
 
     public StatusEffectAffliction(PacketByteBuf buffer) {
-        this(buffer.readIdentifier(), Range.of(buffer), Range.of(buffer), buffer.readInt());
+        this(Registries.STATUS_EFFECT.get(buffer.readIdentifier()), Range.of(buffer), Range.of(buffer), buffer.readInt());
     }
 
     @Override
     public void toBuffer(PacketByteBuf buffer) {
-        buffer.writeIdentifier(effect);
+        buffer.writeIdentifier(Registries.STATUS_EFFECT.getId(effect));
         seconds.toBuffer(buffer);
         amplifier.toBuffer(buffer);
         buffer.writeInt(chance);
@@ -45,35 +45,31 @@ record StatusEffectAffliction(Identifier effect, Range seconds, Range amplifier,
         if (chance > 0 && player.getWorld().random.nextInt(chance) > 0) {
             return;
         }
-        Registries.STATUS_EFFECT.getOrEmpty(effect).ifPresent(effect -> {
-            float health = player.getHealth();
-            StatusEffectInstance current = player.getStatusEffect(effect);
-            player.addStatusEffect(new StatusEffectInstance(effect,
-                    seconds.getClamped(current == null ? 0 : current.getDuration(), 20),
-                    amplifier.getClamped(current == null ? 0 : current.getAmplifier(), 1)
-            ));
-            // keep original health
-            if (effect.getAttributeModifiers().containsKey(EntityAttributes.GENERIC_MAX_HEALTH)) {
-                player.setHealth(MathHelper.clamp(health, 0, player.getMaxHealth()));
-            }
-        });
+        float health = player.getHealth();
+        StatusEffectInstance current = player.getStatusEffect(effect);
+        player.addStatusEffect(new StatusEffectInstance(effect,
+                seconds.getClamped(current == null ? 0 : current.getDuration(), 20),
+                amplifier.getClamped(current == null ? 0 : current.getAmplifier(), 1)
+        ));
+        // keep original health
+        if (effect.getAttributeModifiers().containsKey(EntityAttributes.GENERIC_MAX_HEALTH)) {
+            player.setHealth(MathHelper.clamp(health, 0, player.getMaxHealth()));
+        }
     }
 
     @Override
     public Text getName() {
-        return Registries.STATUS_EFFECT.getOrEmpty(effect).map(effect -> {
-            MutableText text = effect.getName().copy();
+        MutableText text = effect.getName().copy();
 
-            if (amplifier.min() > 0) {
-                text = Text.translatable("potion.withAmplifier", text, Text.translatable("potion.potency." + (amplifier.min())));
-            }
+        if (amplifier.min() > 0) {
+            text = Text.translatable("potion.withAmplifier", text, Text.translatable("potion.potency." + (amplifier.min())));
+        }
 
-            text = Text.translatable("potion.withDuration", text, StringHelper.formatTicks(seconds.min() * 20));
+        text = Text.translatable("potion.withDuration", text, StringHelper.formatTicks(seconds.min() * 20));
 
-            if (chance > 0) {
-                text = Text.translatable("potion.withChance", chance, text);
-            }
-            return (Text)text;
-        }).orElse(EMPTY.getName());
+        if (chance > 0) {
+            text = Text.translatable("potion.withChance", chance, text);
+        }
+        return text;
     }
 }
\ No newline at end of file
diff --git a/src/main/java/com/minelittlepony/unicopia/entity/ItemImpl.java b/src/main/java/com/minelittlepony/unicopia/entity/ItemImpl.java
index 59d84ddb..27e8ca7f 100644
--- a/src/main/java/com/minelittlepony/unicopia/entity/ItemImpl.java
+++ b/src/main/java/com/minelittlepony/unicopia/entity/ItemImpl.java
@@ -111,7 +111,7 @@ public class ItemImpl implements Equine<ItemEntity> {
                     });
             }
 
-            if (stack.isIn(UTags.FALLS_SLOWLY)) {
+            if (stack.isIn(UTags.Items.FALLS_SLOWLY)) {
                 if (!entity.isOnGround() && Math.signum(entity.getVelocity().y) != getPhysics().getGravitySignum()) {
                     double ticks = ((Entity)entity).age;
                     double shift = Math.sin(ticks / 9D) / 9D;
@@ -160,7 +160,7 @@ public class ItemImpl implements Equine<ItemEntity> {
 
     @Override
     public boolean collidesWithClouds() {
-        return entity.getStack().isIn(UTags.FLOATS_ON_CLOUDS) || getSpecies().hasPersistentWeatherMagic();
+        return entity.getStack().isIn(UTags.Items.FLOATS_ON_CLOUDS) || getSpecies().hasPersistentWeatherMagic();
     }
 
     @Override
diff --git a/src/main/java/com/minelittlepony/unicopia/entity/Living.java b/src/main/java/com/minelittlepony/unicopia/entity/Living.java
index fecfe073..1696abef 100644
--- a/src/main/java/com/minelittlepony/unicopia/entity/Living.java
+++ b/src/main/java/com/minelittlepony/unicopia/entity/Living.java
@@ -310,7 +310,7 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
                     ItemStack payload = stack.payload();
                     Item item = payload.getItem();
 
-                    boolean deliverAggressively = payload.isIn(UTags.IS_DELIVERED_AGGRESSIVELY);
+                    boolean deliverAggressively = payload.isIn(UTags.Items.IS_DELIVERED_AGGRESSIVELY);
 
                     Vec3d randomPos = deliverAggressively ? targetPos.add(0, 2, 0) : targetPos.add(VecHelper.supply(() -> entity.getRandom().nextTriangular(0.1, 0.5)));
 
@@ -400,7 +400,7 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
                 this.attacker = attacker;
             }
 
-            if (magical.isIn(UTags.BREAKS_SUNGLASSES)) {
+            if (magical.isIn(UTags.DamageTypes.BREAKS_SUNGLASSES)) {
                 ItemStack glasses = GlassesItem.getForEntity(entity);
                 if (glasses.getItem() == UItems.SUNGLASSES) {
                     ItemStack broken = UItems.BROKEN_SUNGLASSES.getDefaultStack();
diff --git a/src/main/java/com/minelittlepony/unicopia/entity/damage/UDamageTypes.java b/src/main/java/com/minelittlepony/unicopia/entity/damage/UDamageTypes.java
index eae9bb47..3bdc4a8f 100644
--- a/src/main/java/com/minelittlepony/unicopia/entity/damage/UDamageTypes.java
+++ b/src/main/java/com/minelittlepony/unicopia/entity/damage/UDamageTypes.java
@@ -1,18 +1,14 @@
 package com.minelittlepony.unicopia.entity.damage;
 
-import java.util.ArrayList;
-import java.util.List;
-
 import com.minelittlepony.unicopia.Unicopia;
+import com.minelittlepony.unicopia.util.registry.DynamicRegistry;
 
-import net.fabricmc.fabric.api.event.registry.DynamicRegistrySetupCallback;
 import net.minecraft.entity.damage.DamageType;
-import net.minecraft.registry.Registry;
 import net.minecraft.registry.RegistryKey;
 import net.minecraft.registry.RegistryKeys;
 
 public interface UDamageTypes {
-    List<RegistryKey<DamageType>> REGISTRY = new ArrayList<>();
+    DynamicRegistry<DamageType> REGISTRY = new DynamicRegistry<>(RegistryKeys.DAMAGE_TYPE, key -> new DamageType(key.getValue().getNamespace() + "." + key.getValue().getPath(), 0));
 
     RegistryKey<DamageType> EXHAUSTION = register("magical_exhaustion");
     RegistryKey<DamageType> ALICORN_AMULET = register("alicorn_amulet");
@@ -34,18 +30,8 @@ public interface UDamageTypes {
     RegistryKey<DamageType> SPIKES = register("spikes");
 
     private static RegistryKey<DamageType> register(String name) {
-        var key = RegistryKey.of(RegistryKeys.DAMAGE_TYPE, Unicopia.id(name));
-        REGISTRY.add(key);
-        return key;
+        return REGISTRY.register(Unicopia.id(name));
     }
 
-    static void bootstrap() {
-        DynamicRegistrySetupCallback.EVENT.register(registries -> {
-            registries.getOptional(RegistryKeys.DAMAGE_TYPE).ifPresent(registry -> {
-                REGISTRY.forEach(key -> {
-                    Registry.register(registry, key.getValue(), new DamageType(key.getValue().getNamespace() + "." + key.getValue().getPath(), 0));
-                });
-            });
-        });
-    }
+    static void bootstrap() {}
 }
diff --git a/src/main/java/com/minelittlepony/unicopia/entity/effect/SunBlindnessStatusEffect.java b/src/main/java/com/minelittlepony/unicopia/entity/effect/SunBlindnessStatusEffect.java
index c9f679c6..10e607a9 100644
--- a/src/main/java/com/minelittlepony/unicopia/entity/effect/SunBlindnessStatusEffect.java
+++ b/src/main/java/com/minelittlepony/unicopia/entity/effect/SunBlindnessStatusEffect.java
@@ -72,8 +72,8 @@ public class SunBlindnessStatusEffect extends StatusEffect {
             return true;
         }
 
-        if (entity.getEquippedStack(EquipmentSlot.HEAD).isIn(UTags.SHADES)
-            || TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.FACE).anyMatch(i -> i.isIn(UTags.SHADES))
+        if (entity.getEquippedStack(EquipmentSlot.HEAD).isIn(UTags.Items.SHADES)
+            || TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.FACE).anyMatch(i -> i.isIn(UTags.Items.SHADES))
             || entity.isSubmergedInWater()) {
             return false;
         }
diff --git a/src/main/java/com/minelittlepony/unicopia/entity/mob/ButterflyEntity.java b/src/main/java/com/minelittlepony/unicopia/entity/mob/ButterflyEntity.java
index d1a43978..6a0731b4 100644
--- a/src/main/java/com/minelittlepony/unicopia/entity/mob/ButterflyEntity.java
+++ b/src/main/java/com/minelittlepony/unicopia/entity/mob/ButterflyEntity.java
@@ -11,6 +11,7 @@ import java.util.stream.Collectors;
 import org.jetbrains.annotations.Nullable;
 
 import com.minelittlepony.unicopia.USounds;
+import com.minelittlepony.unicopia.UTags;
 import com.minelittlepony.unicopia.Unicopia;
 import com.minelittlepony.unicopia.item.ButterflyItem;
 import com.minelittlepony.unicopia.util.NbtSerialisable;
@@ -73,7 +74,7 @@ public class ButterflyEntity extends AmbientEntity {
     }
 
     public static boolean canSpawn(EntityType<? extends ButterflyEntity> type, WorldAccess world, SpawnReason spawnReason, BlockPos pos, Random random) {
-        return world.getBlockState(pos.down()).isIn(BlockTags.ANIMALS_SPAWNABLE_ON);
+        return world.getBlockState(pos.down()).isIn(UTags.Blocks.BUTTERFLIES_SPAWNABLE_ON);
     }
 
     @Override
diff --git a/src/main/java/com/minelittlepony/unicopia/entity/mob/SpellbookEntity.java b/src/main/java/com/minelittlepony/unicopia/entity/mob/SpellbookEntity.java
index da18363f..5808aea4 100644
--- a/src/main/java/com/minelittlepony/unicopia/entity/mob/SpellbookEntity.java
+++ b/src/main/java/com/minelittlepony/unicopia/entity/mob/SpellbookEntity.java
@@ -373,7 +373,7 @@ public class SpellbookEntity extends MobEntity implements MagicImmune {
 
     @Override
     public boolean isInvulnerableTo(DamageSource damageSource) {
-        return super.isInvulnerableTo(damageSource) || damageSource.isIn(UTags.SPELLBOOK_IMMUNE_TO);
+        return super.isInvulnerableTo(damageSource) || damageSource.isIn(UTags.DamageTypes.SPELLBOOK_IMMUNE_TO);
     }
 
     @Override
diff --git a/src/main/java/com/minelittlepony/unicopia/entity/mob/UTradeOffers.java b/src/main/java/com/minelittlepony/unicopia/entity/mob/UTradeOffers.java
index ff73a2f8..74e38429 100644
--- a/src/main/java/com/minelittlepony/unicopia/entity/mob/UTradeOffers.java
+++ b/src/main/java/com/minelittlepony/unicopia/entity/mob/UTradeOffers.java
@@ -35,7 +35,7 @@ public interface UTradeOffers {
             factories.add(buyForEmeralds(UItems.GEMSTONE, 3, 1, 20, 1, 0.05F));
         });
         TradeOfferHelper.registerVillagerOffers(VillagerProfession.FARMER, 2, factories -> {
-            factories.add(buy(Items.EMERALD, 4, UTags.APPLE_SEEDS, 2, 20, 1, 0.05F));
+            factories.add(buy(Items.EMERALD, 4, UTags.Items.APPLE_SEEDS, 2, 20, 1, 0.05F));
             factories.add(buy(Items.EMERALD, 8, UItems.MANGO, 1, 15, 1, 0.025F));
         });
 
@@ -47,7 +47,7 @@ public interface UTradeOffers {
             factories.add(buy(ItemTags.SMALL_FLOWERS, 2, UItems.DAFFODIL_DAISY_SANDWICH, 1, 10, 6, 0.08F));
             factories.add(buy(UItems.ZAP_APPLE, 45, UItems.ZAP_APPLE_JAM_JAR, 5, 50, 3, 0.07F));
             factories.add(buy(UItems.CIDER, 1, UItems.FRIENDSHIP_BRACELET, 1, 6, 1, 0.05F));
-            factories.add(buy(UItems.GEMSTONE, 5, UTags.FRESH_APPLES, 2, 12, 3, 0.05F));
+            factories.add(buy(UItems.GEMSTONE, 5, UTags.Items.FRESH_APPLES, 2, 12, 3, 0.05F));
             factories.add(buy(Items.EMERALD, 4, UItems.MANGO, 1, 35, 1, 0.025F));
             factories.add(new JarredItemTradeOfferFactory());
         });
diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java
index b4db56d0..fc53f9b0 100644
--- a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java
+++ b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java
@@ -194,7 +194,7 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
     private FlightType recalculateFlightType() {
         DimensionType dimension = entity.getWorld().getDimension();
 
-        if ((RegistryUtils.isIn(entity.getWorld(), dimension, RegistryKeys.DIMENSION_TYPE, UTags.HAS_NO_ATMOSPHERE)
+        if ((RegistryUtils.isIn(entity.getWorld(), dimension, RegistryKeys.DIMENSION_TYPE, UTags.DimensionTypes.HAS_NO_ATMOSPHERE)
                 || Unicopia.getConfig().dimensionsWithoutAtmosphere.get().contains(RegistryUtils.getId(entity.getWorld(), dimension, RegistryKeys.DIMENSION_TYPE).toString()))
                 && !OxygenUtils.API.hasOxygen(entity)) {
             return FlightType.NONE;
@@ -582,7 +582,7 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
 
         if (entity.isOnGround() || !force) {
             BlockState steppingState = pony.asEntity().getSteppingBlockState();
-            if (steppingState.isIn(UTags.KICKS_UP_DUST)) {
+            if (steppingState.isIn(UTags.Blocks.KICKS_UP_DUST)) {
                 pony.addParticle(new BlockStateParticleEffect(UParticles.DUST_CLOUD, steppingState), pony.getOrigin().toCenterPos(), Vec3d.ZERO);
             } else {
                 Supplier<Vec3d> pos = VecHelper.sphere(pony.asWorld().getRandom(), 0.5D);
diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java
index 10efd22d..fad4a95d 100644
--- a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java
+++ b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java
@@ -551,7 +551,7 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
         }
 
         if (getObservedSpecies() == Race.BAT && !entity.hasPortalCooldown()) {
-            boolean hasShades = TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.FACE).anyMatch(s -> s.isIn(UTags.SHADES));
+            boolean hasShades = TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.FACE).anyMatch(s -> s.isIn(UTags.Items.SHADES));
             if (!this.hasShades && hasShades && getObservedSpecies() == Race.BAT) {
                 UCriteria.WEAR_SHADES.trigger(entity);
             }
@@ -754,7 +754,7 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
         }
 
         if (getObservedSpecies() == Race.KIRIN
-                && (stack.isIn(UTags.COOLS_OFF_KIRINS) || PotionUtil.getPotion(stack) == Potions.WATER)) {
+                && (stack.isIn(UTags.Items.COOLS_OFF_KIRINS) || PotionUtil.getPotion(stack) == Potions.WATER)) {
             getMagicalReserves().getCharge().multiply(0.5F);
             getSpellSlot().get(SpellType.RAGE, false).ifPresent(RageAbilitySpell::setExtenguishing);
         }
diff --git a/src/main/java/com/minelittlepony/unicopia/item/DrinkableItem.java b/src/main/java/com/minelittlepony/unicopia/item/ConsumableItem.java
similarity index 55%
rename from src/main/java/com/minelittlepony/unicopia/item/DrinkableItem.java
rename to src/main/java/com/minelittlepony/unicopia/item/ConsumableItem.java
index 23fa0dd1..747115e1 100644
--- a/src/main/java/com/minelittlepony/unicopia/item/DrinkableItem.java
+++ b/src/main/java/com/minelittlepony/unicopia/item/ConsumableItem.java
@@ -4,16 +4,22 @@ import java.util.Optional;
 
 import net.minecraft.advancement.criterion.Criteria;
 import net.minecraft.entity.LivingEntity;
+import net.minecraft.entity.player.PlayerEntity;
 import net.minecraft.item.Item;
 import net.minecraft.item.ItemStack;
+import net.minecraft.item.ItemUsage;
 import net.minecraft.server.network.ServerPlayerEntity;
 import net.minecraft.stat.Stats;
 import net.minecraft.util.UseAction;
 import net.minecraft.world.World;
 
-public class DrinkableItem extends Item {
-    public DrinkableItem(Item.Settings settings) {
+public class ConsumableItem extends Item {
+
+    private final UseAction action;
+
+    public ConsumableItem(Item.Settings settings, UseAction action) {
         super(settings);
+        this.action = action;
     }
 
     @Override
@@ -25,11 +31,20 @@ public class DrinkableItem extends Item {
             serverPlayerEntity.incrementStat(Stats.USED.getOrCreateStat(this));
         }
 
-        return stack.isEmpty() ? Optional.ofNullable(getRecipeRemainder()).map(Item::getDefaultStack).orElse(ItemStack.EMPTY) : stack;
+        if (stack.isEmpty()) {
+            return stack.isEmpty() ? Optional.ofNullable(getRecipeRemainder()).map(Item::getDefaultStack).orElse(ItemStack.EMPTY) : stack;
+        }
+
+        if (user instanceof PlayerEntity player) {
+            return Optional.ofNullable(getRecipeRemainder()).map(Item::getDefaultStack).map(remainder -> {
+                return ItemUsage.exchangeStack(stack, player, remainder);
+            }).orElse(stack);
+        }
+        return stack;
     }
 
     @Override
     public UseAction getUseAction(ItemStack stack) {
-        return UseAction.DRINK;
+        return action;
     }
 }
diff --git a/src/main/java/com/minelittlepony/unicopia/item/CrystalHeartItem.java b/src/main/java/com/minelittlepony/unicopia/item/CrystalHeartItem.java
index d4f9607c..c334124f 100644
--- a/src/main/java/com/minelittlepony/unicopia/item/CrystalHeartItem.java
+++ b/src/main/java/com/minelittlepony/unicopia/item/CrystalHeartItem.java
@@ -188,7 +188,7 @@ public class CrystalHeartItem extends Item implements FloatingArtefactEntity.Art
 
         BlockPos tip = entity.getBlockPos().offset(direction);
         BlockState tipState = entity.getWorld().getBlockState(tip);
-        if (!tipState.isIn(UTags.CRYSTAL_HEART_ORNAMENT) || (!tipState.contains(EndRodBlock.FACING)|| tipState.get(EndRodBlock.FACING) != direction.getOpposite())) {
+        if (!tipState.isIn(UTags.Blocks.CRYSTAL_HEART_ORNAMENT) || (!tipState.contains(EndRodBlock.FACING)|| tipState.get(EndRodBlock.FACING) != direction.getOpposite())) {
             return false;
         }
 
@@ -207,6 +207,6 @@ public class CrystalHeartItem extends Item implements FloatingArtefactEntity.Art
     }
 
     private boolean isDiamond(BlockState state) {
-        return state.isIn(UTags.CRYSTAL_HEART_BASE);
+        return state.isIn(UTags.Blocks.CRYSTAL_HEART_BASE);
     }
 }
diff --git a/src/main/java/com/minelittlepony/unicopia/item/PineappleItem.java b/src/main/java/com/minelittlepony/unicopia/item/PineappleItem.java
index 7098e7a4..9ff3941f 100644
--- a/src/main/java/com/minelittlepony/unicopia/item/PineappleItem.java
+++ b/src/main/java/com/minelittlepony/unicopia/item/PineappleItem.java
@@ -29,7 +29,7 @@ public class PineappleItem extends Item {
                 });
 
                 if (world.random.nextInt(20) == 0) {
-                    RegistryUtils.pickRandom(world, UTags.PINEAPPLE_EFFECTS, e -> !user.hasStatusEffect(e)).ifPresent(effect -> {
+                    RegistryUtils.pickRandom(world, UTags.StatusEffects.PINEAPPLE_EFFECTS, e -> !user.hasStatusEffect(e)).ifPresent(effect -> {
                         user.addStatusEffect(new StatusEffectInstance(effect, 10, 1));
                     });
                 }
diff --git a/src/main/java/com/minelittlepony/unicopia/item/PolearmItem.java b/src/main/java/com/minelittlepony/unicopia/item/PolearmItem.java
index a7f430c4..5dc90908 100644
--- a/src/main/java/com/minelittlepony/unicopia/item/PolearmItem.java
+++ b/src/main/java/com/minelittlepony/unicopia/item/PolearmItem.java
@@ -41,7 +41,7 @@ public class PolearmItem extends SwordItem {
 
     @Override
     public boolean isSuitableFor(BlockState state) {
-        return state.isIn(UTags.POLEARM_MINEABLE);
+        return state.isIn(UTags.Blocks.POLEARM_MINEABLE);
     }
 
     @Override
diff --git a/src/main/java/com/minelittlepony/unicopia/item/UFoodComponents.java b/src/main/java/com/minelittlepony/unicopia/item/UFoodComponents.java
index ee093b08..80a2e9a5 100644
--- a/src/main/java/com/minelittlepony/unicopia/item/UFoodComponents.java
+++ b/src/main/java/com/minelittlepony/unicopia/item/UFoodComponents.java
@@ -29,11 +29,8 @@ public interface UFoodComponents {
     FoodComponent OATMEAL_COOKIE = FoodComponents.COOKIE; //builder(2, 0.1F).build();
     FoodComponent CHOCOLATE_OATMEAL_COOKIE = builder(3, 0.4F).build();
     FoodComponent SCONE = builder(2, 0.2F).build();
+    FoodComponent FRIED_EGG = builder(4, 0.4F).build();
 
-    @Deprecated
-    FoodComponent RANDOM_FOLIAGE = builder(2, 1).build();
-    @Deprecated
-    FoodComponent RANDOM_FOLIAGE_FILLING = builder(18, 1).build();
     FoodComponent WORMS = builder(1, 1.5F).alwaysEdible().meat().build();
     FoodComponent INSECTS = builder(1, 0).alwaysEdible().build();
 
@@ -62,9 +59,7 @@ public interface UFoodComponents {
 
     FoodComponent POISON_JOKE = builder(0, 0F).alwaysEdible().snack().build();
 
-    @Deprecated
     FoodComponent SHELL = builder(3, 5).build();
-    @Deprecated
     FoodComponent SHELLY = builder(6, 7).build();
 
     static FoodComponent.Builder builder(int hunger, float saturation) {
diff --git a/src/main/java/com/minelittlepony/unicopia/item/UItems.java b/src/main/java/com/minelittlepony/unicopia/item/UItems.java
index be2973db..9ec070b3 100644
--- a/src/main/java/com/minelittlepony/unicopia/item/UItems.java
+++ b/src/main/java/com/minelittlepony/unicopia/item/UItems.java
@@ -12,6 +12,7 @@ import com.minelittlepony.unicopia.item.cloud.CloudBedItem;
 import com.minelittlepony.unicopia.item.enchantment.UEnchantments;
 import com.minelittlepony.unicopia.item.group.ItemGroupRegistry;
 import com.minelittlepony.unicopia.item.group.UItemGroups;
+import com.minelittlepony.unicopia.recipe.URecipes;
 import com.terraformersmc.terraform.boat.api.TerraformBoatType;
 import com.terraformersmc.terraform.boat.api.TerraformBoatTypeRegistry;
 import com.terraformersmc.terraform.boat.api.item.TerraformBoatItemHelper;
@@ -27,6 +28,7 @@ import net.fabricmc.fabric.api.registry.CompostingChanceRegistry;
 import net.fabricmc.fabric.api.registry.FuelRegistry;
 import net.minecraft.sound.SoundEvent;
 import net.minecraft.util.Rarity;
+import net.minecraft.util.UseAction;
 import net.minecraft.registry.Registry;
 import net.minecraft.registry.RegistryKey;
 import net.minecraft.registry.Registries;
@@ -109,7 +111,7 @@ public interface UItems {
     Item TOM = register("tom", new BluntWeaponItem(new Item.Settings(), ImmutableMultimap.of(
             EntityAttributes.GENERIC_KNOCKBACK_RESISTANCE, new EntityAttributeModifier(BluntWeaponItem.KNOCKBACK_MODIFIER_ID, "Weapon modifier", 0.9, EntityAttributeModifier.Operation.ADDITION)
     )), ItemGroups.NATURAL);
-    Item ROCK_STEW = register("rock_stew", new StewItem(new Item.Settings().food(FoodComponents.MUSHROOM_STEW).recipeRemainder(Items.BOWL)), ItemGroups.FOOD_AND_DRINK);
+    Item ROCK_STEW = register("rock_stew", new StewItem(new Item.Settings().food(FoodComponents.MUSHROOM_STEW).maxCount(1).recipeRemainder(Items.BOWL)), ItemGroups.FOOD_AND_DRINK);
     Item ROCK_CANDY = register("rock_candy", new Item(new Item.Settings().food(UFoodComponents.CANDY).maxCount(16)), ItemGroups.FOOD_AND_DRINK);
     Item SALT_CUBE = register("salt_cube", new Item(new Item.Settings().food(UFoodComponents.SALT_CUBE)), ItemGroups.FOOD_AND_DRINK);
 
@@ -119,17 +121,17 @@ public interface UItems {
     Item GOLDEN_OAK_SEEDS = register("golden_oak_seeds", new AliasedBlockItem(UBlocks.GOLDEN_OAK_SPROUT, new Item.Settings()), ItemGroups.NATURAL);
 
     Item MUG = register("mug", new Item(new Settings()), ItemGroups.TOOLS);
-    Item CIDER = register("cider", new DrinkableItem(new Item.Settings().food(UFoodComponents.CIDER).maxCount(16).recipeRemainder(MUG)), ItemGroups.FOOD_AND_DRINK);
-    Item JUICE = register("juice", new DrinkableItem(new Item.Settings().recipeRemainder(Items.GLASS_BOTTLE).maxCount(16).food(UFoodComponents.JUICE)), ItemGroups.FOOD_AND_DRINK);
-    Item BURNED_JUICE = register("burned_juice", new DrinkableItem(new Item.Settings().recipeRemainder(Items.GLASS_BOTTLE).maxCount(16).food(UFoodComponents.BURNED_JUICE)), ItemGroups.FOOD_AND_DRINK);
+    Item CIDER = register("cider", new ConsumableItem(new Item.Settings().food(UFoodComponents.CIDER).maxCount(16).recipeRemainder(MUG), UseAction.DRINK), ItemGroups.FOOD_AND_DRINK);
+    Item JUICE = register("juice", new ConsumableItem(new Item.Settings().recipeRemainder(Items.GLASS_BOTTLE).maxCount(16).food(UFoodComponents.JUICE), UseAction.DRINK), ItemGroups.FOOD_AND_DRINK);
+    Item BURNED_JUICE = register("burned_juice", new ConsumableItem(new Item.Settings().recipeRemainder(Items.GLASS_BOTTLE).maxCount(16).food(UFoodComponents.BURNED_JUICE), UseAction.DRINK), ItemGroups.FOOD_AND_DRINK);
     Item APPLE_PIE = register("apple_pie", new BlockItem(UBlocks.APPLE_PIE, new Item.Settings().maxCount(1)), ItemGroups.FOOD_AND_DRINK);
     Item APPLE_PIE_HOOF = register("apple_pie_hoof", new AliasedBlockItem(UBlocks.APPLE_PIE, new Item.Settings().maxCount(1)), ItemGroups.FOOD_AND_DRINK);
     Item APPLE_PIE_SLICE = register("apple_pie_slice", new Item(new Item.Settings().maxCount(16).food(UFoodComponents.PIE)), ItemGroups.FOOD_AND_DRINK);
     Item CANDIED_APPLE = register("candied_apple", new StagedFoodItem(new Item.Settings().food(UFoodComponents.CANDY).maxDamage(3), () -> Items.STICK), ItemGroups.FOOD_AND_DRINK);
 
-    Item LOVE_BOTTLE = register("love_bottle", new DrinkableItem(new Item.Settings().food(UFoodComponents.LOVE_BOTTLE).maxCount(1).recipeRemainder(Items.GLASS_BOTTLE)), ItemGroups.FOOD_AND_DRINK);
-    Item LOVE_BUCKET = register("love_bucket", new DrinkableItem(new Item.Settings().food(UFoodComponents.LOVE_BUCKET).recipeRemainder(Items.BUCKET)), ItemGroups.FOOD_AND_DRINK);
-    Item LOVE_MUG = register("love_mug", new DrinkableItem(new Item.Settings().food(UFoodComponents.LOVE_MUG).recipeRemainder(MUG)), ItemGroups.FOOD_AND_DRINK);
+    Item LOVE_BOTTLE = register("love_bottle", new ConsumableItem(new Item.Settings().food(UFoodComponents.LOVE_BOTTLE).maxCount(1).recipeRemainder(Items.GLASS_BOTTLE), UseAction.DRINK), ItemGroups.FOOD_AND_DRINK);
+    Item LOVE_BUCKET = register("love_bucket", new ConsumableItem(new Item.Settings().food(UFoodComponents.LOVE_BUCKET).recipeRemainder(Items.BUCKET), UseAction.DRINK), ItemGroups.FOOD_AND_DRINK);
+    Item LOVE_MUG = register("love_mug", new ConsumableItem(new Item.Settings().food(UFoodComponents.LOVE_MUG).recipeRemainder(MUG), UseAction.DRINK), ItemGroups.FOOD_AND_DRINK);
 
     Item GOLDEN_FEATHER = register("golden_feather", new Item(new Item.Settings().rarity(Rarity.UNCOMMON)), ItemGroups.NATURAL);
     Item GOLDEN_WING = register("golden_wing", new Item(new Item.Settings().rarity(Rarity.UNCOMMON)), ItemGroups.NATURAL);
@@ -226,6 +228,16 @@ public interface UItems {
     Item TURRET_SHELL = register("turret_shell", new Item(new Item.Settings()), ItemGroups.INGREDIENTS);
     Item SHELLY = register("shelly", new Item(new Item.Settings()), ItemGroups.INGREDIENTS);
 
+    Item ROTTEN_COD = register("rotten_cod", new Item(new Item.Settings().food(FoodComponents.ROTTEN_FLESH)), ItemGroups.FOOD_AND_DRINK);
+    Item ROTTEN_SALMON = register("rotten_salmon", new Item(new Item.Settings().food(FoodComponents.ROTTEN_FLESH)), ItemGroups.FOOD_AND_DRINK);
+    Item ROTTEN_TROPICAL_FISH = register("rotten_tropical_fish", new Item(new Item.Settings().food(FoodComponents.ROTTEN_FLESH)), ItemGroups.FOOD_AND_DRINK);
+    Item ROTTEN_PUFFERFISH = register("rotten_pufferfish", new Item(new Item.Settings().food(FoodComponents.ROTTEN_FLESH)), ItemGroups.FOOD_AND_DRINK);
+
+    Item COOKED_TROPICAL_FISH = register("cooked_tropical_fish", new Item(new Item.Settings().food(FoodComponents.COOKED_COD)), ItemGroups.FOOD_AND_DRINK);
+    Item COOKED_PUFFERFISH = register("cooked_pufferfish", new Item(new Item.Settings().food(FoodComponents.COOKED_COD)), ItemGroups.FOOD_AND_DRINK);
+    Item FRIED_AXOLOTL = register("fried_axolotl", new ConsumableItem(new Item.Settings().food(FoodComponents.COOKED_CHICKEN).maxCount(1).recipeRemainder(Items.BUCKET), UseAction.EAT), ItemGroups.FOOD_AND_DRINK);
+    Item GREEN_FRIED_EGG = register("green_fried_egg", new Item(new Item.Settings().food(UFoodComponents.FRIED_EGG)), ItemGroups.FOOD_AND_DRINK);
+
     Item CARAPACE = register("carapace", new Item(new Item.Settings()), ItemGroups.INGREDIENTS);
     Item CLOTH_BED = register("cloth_bed", new FancyBedItem(UBlocks.CLOTH_BED, new Item.Settings().maxCount(1)), ItemGroups.FUNCTIONAL);
     Item CLOUD_BED = register("cloud_bed", new CloudBedItem(UBlocks.CLOUD_BED, new Item.Settings().maxCount(1)), ItemGroups.FUNCTIONAL);
@@ -272,7 +284,7 @@ public interface UItems {
         FuelRegistry.INSTANCE.add(SPELLBOOK, 9000);
         FuelRegistry.INSTANCE.add(MEADOWBROOKS_STAFF, 800);
         FuelRegistry.INSTANCE.add(BURNED_TOAST, 1600);
-        FuelRegistry.INSTANCE.add(UTags.BASKETS, 1700);
+        FuelRegistry.INSTANCE.add(UTags.Items.BASKETS, 1700);
 
         CompostingChanceRegistry.INSTANCE.add(GREEN_APPLE, 0.65F);
         CompostingChanceRegistry.INSTANCE.add(SWEET_APPLE, 0.65F);
diff --git a/src/main/java/com/minelittlepony/unicopia/item/ZapAppleItem.java b/src/main/java/com/minelittlepony/unicopia/item/ZapAppleItem.java
index 63cfb026..f8fe1ee3 100644
--- a/src/main/java/com/minelittlepony/unicopia/item/ZapAppleItem.java
+++ b/src/main/java/com/minelittlepony/unicopia/item/ZapAppleItem.java
@@ -103,7 +103,7 @@ public class ZapAppleItem extends Item implements ChameleonItem, MultiItem {
     public List<ItemStack> getDefaultStacks() {
         return Unicopia.SIDE.getPony().map(Pony::asWorld)
                 .stream()
-                .flatMap(world -> RegistryUtils.valuesForTag(world, UConventionalTags.APPLES))
+                .flatMap(world -> RegistryUtils.valuesForTag(world, UConventionalTags.Items.APPLES))
                 .filter(a -> a != this).map(item -> {
             ItemStack stack = new ItemStack(this);
             stack.getOrCreateNbt().putString("appearance", Registries.ITEM.getId(item).toString());
diff --git a/src/main/java/com/minelittlepony/unicopia/item/enchantment/GemFindingEnchantment.java b/src/main/java/com/minelittlepony/unicopia/item/enchantment/GemFindingEnchantment.java
index 0010a097..d07383cc 100644
--- a/src/main/java/com/minelittlepony/unicopia/item/enchantment/GemFindingEnchantment.java
+++ b/src/main/java/com/minelittlepony/unicopia/item/enchantment/GemFindingEnchantment.java
@@ -21,7 +21,7 @@ public class GemFindingEnchantment extends SimpleEnchantment {
 
         BlockPos origin = user.getOrigin();
 
-        double volume = BlockPos.findClosest(origin, radius, radius, pos -> user.asWorld().getBlockState(pos).isIn(UTags.INTERESTING))
+        double volume = BlockPos.findClosest(origin, radius, radius, pos -> user.asWorld().getBlockState(pos).isIn(UTags.Blocks.INTERESTING))
             .map(p -> user.getOriginVector().squaredDistanceTo(p.getX(), p.getY(), p.getZ()))
             .map(find -> (1 - (Math.sqrt(find) / radius)))
             .orElse(-1D);
diff --git a/src/main/java/com/minelittlepony/unicopia/item/group/ItemGroupRegistry.java b/src/main/java/com/minelittlepony/unicopia/item/group/ItemGroupRegistry.java
index 3998f13b..c276d2c6 100644
--- a/src/main/java/com/minelittlepony/unicopia/item/group/ItemGroupRegistry.java
+++ b/src/main/java/com/minelittlepony/unicopia/item/group/ItemGroupRegistry.java
@@ -4,7 +4,6 @@ import java.util.*;
 import java.util.function.Supplier;
 import java.util.stream.Stream;
 
-import com.minelittlepony.unicopia.UTags;
 import com.minelittlepony.unicopia.Unicopia;
 
 import net.fabricmc.fabric.api.itemgroup.v1.FabricItemGroup;
@@ -57,10 +56,9 @@ public interface ItemGroupRegistry {
         return key;
     }
 
-    static RegistryKey<ItemGroup> createGroupFromTag(String name, Supplier<ItemStack> icon) {
-        TagKey<Item> key = UTags.item("groups/" + name);
+    static RegistryKey<ItemGroup> createGroupFromTag(String name, TagKey<Item> tag, Supplier<ItemStack> icon) {
         return createDynamic(name, icon, () -> {
-            return Registries.ITEM.getEntryList(key)
+            return Registries.ITEM.getEntryList(tag)
                     .stream()
                     .flatMap(named -> named.stream())
                     .map(entry -> entry.value());
diff --git a/src/main/java/com/minelittlepony/unicopia/item/group/UItemGroups.java b/src/main/java/com/minelittlepony/unicopia/item/group/UItemGroups.java
index a1f0efae..a479fa90 100644
--- a/src/main/java/com/minelittlepony/unicopia/item/group/UItemGroups.java
+++ b/src/main/java/com/minelittlepony/unicopia/item/group/UItemGroups.java
@@ -2,6 +2,7 @@ package com.minelittlepony.unicopia.item.group;
 
 import java.util.stream.Stream;
 
+import com.minelittlepony.unicopia.UTags;
 import com.minelittlepony.unicopia.item.ChameleonItem;
 import com.minelittlepony.unicopia.item.UItems;
 import net.minecraft.item.*;
@@ -12,13 +13,13 @@ public interface UItemGroups {
         return Stream.concat(Stream.of(Items.APPLE), ItemGroupRegistry.ITEMS.stream()
                 .filter(item -> !(item instanceof ChameleonItem) || ((ChameleonItem)item).isFullyDisguised()));
     });
-    RegistryKey<ItemGroup> FORAGING_ITEMS = ItemGroupRegistry.createGroupFromTag("foraging", Items.HAY_BLOCK::getDefaultStack);
-    RegistryKey<ItemGroup> EARTH_PONY_ITEMS = ItemGroupRegistry.createGroupFromTag("earth_pony", UItems.EARTH_BADGE::getDefaultStack);
-    RegistryKey<ItemGroup> UNICORN_ITEMS = ItemGroupRegistry.createGroupFromTag("unicorn", UItems.UNICORN_BADGE::getDefaultStack);
-    RegistryKey<ItemGroup> PEGASUS_ITEMS = ItemGroupRegistry.createGroupFromTag("pegasus", UItems.PEGASUS_BADGE::getDefaultStack);
-    RegistryKey<ItemGroup> BAT_PONY_ITEMS = ItemGroupRegistry.createGroupFromTag("bat_pony", UItems.BAT_BADGE::getDefaultStack);
-    RegistryKey<ItemGroup> SEA_PON_ITEMS = ItemGroupRegistry.createGroupFromTag("sea_pony", UItems.PEARL_NECKLACE::getDefaultStack);
-    RegistryKey<ItemGroup> CHANGELING_ITEMS = ItemGroupRegistry.createGroupFromTag("changeling", UItems.CHANGELING_BADGE::getDefaultStack);
+    RegistryKey<ItemGroup> FORAGING_ITEMS = ItemGroupRegistry.createGroupFromTag("foraging", UTags.Items.GROUP_FORAGING, Items.HAY_BLOCK::getDefaultStack);
+    RegistryKey<ItemGroup> EARTH_PONY_ITEMS = ItemGroupRegistry.createGroupFromTag("earth_pony", UTags.Items.GROUP_EARTH_PONY, UItems.EARTH_BADGE::getDefaultStack);
+    RegistryKey<ItemGroup> UNICORN_ITEMS = ItemGroupRegistry.createGroupFromTag("unicorn", UTags.Items.GROUP_UNICORN, UItems.UNICORN_BADGE::getDefaultStack);
+    RegistryKey<ItemGroup> PEGASUS_ITEMS = ItemGroupRegistry.createGroupFromTag("pegasus", UTags.Items.GROUP_PEGASUS, UItems.PEGASUS_BADGE::getDefaultStack);
+    RegistryKey<ItemGroup> BAT_PONY_ITEMS = ItemGroupRegistry.createGroupFromTag("bat_pony", UTags.Items.GROUP_BAT_PONY, UItems.BAT_BADGE::getDefaultStack);
+    RegistryKey<ItemGroup> SEA_PON_ITEMS = ItemGroupRegistry.createGroupFromTag("sea_pony", UTags.Items.GROUP_SEA_PONY, UItems.PEARL_NECKLACE::getDefaultStack);
+    RegistryKey<ItemGroup> CHANGELING_ITEMS = ItemGroupRegistry.createGroupFromTag("changeling", UTags.Items.GROUP_CHANGELING, UItems.CHANGELING_BADGE::getDefaultStack);
 
     static void bootstrap() {
         ItemGroupRegistry.bootstrap();
diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/MixinEntityBucketItem.java b/src/main/java/com/minelittlepony/unicopia/mixin/MixinEntityBucketItem.java
new file mode 100644
index 00000000..978c2636
--- /dev/null
+++ b/src/main/java/com/minelittlepony/unicopia/mixin/MixinEntityBucketItem.java
@@ -0,0 +1,16 @@
+package com.minelittlepony.unicopia.mixin;
+
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.gen.Accessor;
+
+import net.minecraft.entity.EntityType;
+import net.minecraft.item.EntityBucketItem;
+import net.minecraft.sound.SoundEvent;
+
+@Mixin(EntityBucketItem.class)
+public interface MixinEntityBucketItem {
+    @Accessor
+    EntityType<?> getEntityType();
+    @Accessor
+    SoundEvent getEmptyingSound();
+}
diff --git a/src/main/java/com/minelittlepony/unicopia/projectile/PhysicsBodyProjectileEntity.java b/src/main/java/com/minelittlepony/unicopia/projectile/PhysicsBodyProjectileEntity.java
index 531f670e..de74181e 100644
--- a/src/main/java/com/minelittlepony/unicopia/projectile/PhysicsBodyProjectileEntity.java
+++ b/src/main/java/com/minelittlepony/unicopia/projectile/PhysicsBodyProjectileEntity.java
@@ -145,7 +145,7 @@ public class PhysicsBodyProjectileEntity extends PersistentProjectileEntity impl
             return;
         } else {
             ItemStack stack = asItemStack();
-            if (stack.isIn(UTags.HORSE_SHOES)) {
+            if (stack.isIn(UTags.Items.HORSE_SHOES)) {
                 if (stack.damage(1 + random.nextInt(10), random, null)) {
                     playSound(USounds.Vanilla.ENTITY_ITEM_BREAK, 1, 1);
                 } else {
@@ -205,7 +205,7 @@ public class PhysicsBodyProjectileEntity extends PersistentProjectileEntity impl
             boolean ownerCanModify = !getWorld().isClient && Caster.of(getOwner()).filter(pony -> pony.canModifyAt(hit.getBlockPos())).isPresent();
 
             if (ownerCanModify && getWorld().getGameRules().getBoolean(GameRules.DO_MOB_GRIEFING)) {
-                if ((!isBouncy() || getWorld().random.nextInt(200) == 0) && state.isIn(UTags.FRAGILE)) {
+                if ((!isBouncy() || getWorld().random.nextInt(200) == 0) && state.isIn(UTags.Blocks.FRAGILE)) {
                     getWorld().breakBlock(hit.getBlockPos(), true);
                 }
             }
@@ -246,7 +246,7 @@ public class PhysicsBodyProjectileEntity extends PersistentProjectileEntity impl
         emitGameEvent(GameEvent.STEP);
 
         if (!isBouncy()) {
-            if (stack.isIn(UTags.HORSE_SHOES)) {
+            if (stack.isIn(UTags.Items.HORSE_SHOES)) {
                 if (stack.damage(1 + random.nextInt(10), random, null)) {
                     playSound(USounds.Vanilla.ENTITY_ITEM_BREAK, 1, 1);
                     discard();
@@ -262,7 +262,7 @@ public class PhysicsBodyProjectileEntity extends PersistentProjectileEntity impl
 
     @Override
     protected SoundEvent getHitSound() {
-        if (getStack().isIn(UTags.HORSE_SHOES)) {
+        if (getStack().isIn(UTags.Items.HORSE_SHOES)) {
             return USounds.Vanilla.ITEM_TRIDENT_HIT_GROUND;
         }
         return isBouncy() ? USounds.ITEM_MUFFIN_BOUNCE.value() : USounds.ITEM_ROCK_LAND;
diff --git a/src/main/java/com/minelittlepony/unicopia/item/cloud/CloudShapingRecipe.java b/src/main/java/com/minelittlepony/unicopia/recipe/CloudShapingRecipe.java
similarity index 90%
rename from src/main/java/com/minelittlepony/unicopia/item/cloud/CloudShapingRecipe.java
rename to src/main/java/com/minelittlepony/unicopia/recipe/CloudShapingRecipe.java
index 4f12f7db..063130fd 100644
--- a/src/main/java/com/minelittlepony/unicopia/item/cloud/CloudShapingRecipe.java
+++ b/src/main/java/com/minelittlepony/unicopia/recipe/CloudShapingRecipe.java
@@ -1,7 +1,6 @@
-package com.minelittlepony.unicopia.item.cloud;
+package com.minelittlepony.unicopia.recipe;
 
 import com.minelittlepony.unicopia.block.UBlocks;
-import com.minelittlepony.unicopia.item.URecipes;
 
 import net.minecraft.item.ItemStack;
 import net.minecraft.recipe.Ingredient;
diff --git a/src/main/java/com/minelittlepony/unicopia/item/GlowingRecipe.java b/src/main/java/com/minelittlepony/unicopia/recipe/GlowingRecipe.java
similarity index 93%
rename from src/main/java/com/minelittlepony/unicopia/item/GlowingRecipe.java
rename to src/main/java/com/minelittlepony/unicopia/recipe/GlowingRecipe.java
index 663dd8a5..32fdfc37 100644
--- a/src/main/java/com/minelittlepony/unicopia/item/GlowingRecipe.java
+++ b/src/main/java/com/minelittlepony/unicopia/recipe/GlowingRecipe.java
@@ -1,4 +1,6 @@
-package com.minelittlepony.unicopia.item;
+package com.minelittlepony.unicopia.recipe;
+
+import com.minelittlepony.unicopia.item.GlowableItem;
 
 import net.minecraft.inventory.RecipeInputInventory;
 import net.minecraft.item.ItemStack;
diff --git a/src/main/java/com/minelittlepony/unicopia/item/ItemCombinationRecipe.java b/src/main/java/com/minelittlepony/unicopia/recipe/ItemCombinationRecipe.java
similarity index 97%
rename from src/main/java/com/minelittlepony/unicopia/item/ItemCombinationRecipe.java
rename to src/main/java/com/minelittlepony/unicopia/recipe/ItemCombinationRecipe.java
index ccdaa038..7a3b998e 100644
--- a/src/main/java/com/minelittlepony/unicopia/item/ItemCombinationRecipe.java
+++ b/src/main/java/com/minelittlepony/unicopia/recipe/ItemCombinationRecipe.java
@@ -1,4 +1,4 @@
-package com.minelittlepony.unicopia.item;
+package com.minelittlepony.unicopia.recipe;
 
 import net.minecraft.inventory.RecipeInputInventory;
 import net.minecraft.item.ItemStack;
diff --git a/src/main/java/com/minelittlepony/unicopia/item/JarExtractRecipe.java b/src/main/java/com/minelittlepony/unicopia/recipe/JarExtractRecipe.java
similarity index 94%
rename from src/main/java/com/minelittlepony/unicopia/item/JarExtractRecipe.java
rename to src/main/java/com/minelittlepony/unicopia/recipe/JarExtractRecipe.java
index b480d05e..5d28fd91 100644
--- a/src/main/java/com/minelittlepony/unicopia/item/JarExtractRecipe.java
+++ b/src/main/java/com/minelittlepony/unicopia/recipe/JarExtractRecipe.java
@@ -1,7 +1,9 @@
-package com.minelittlepony.unicopia.item;
+package com.minelittlepony.unicopia.recipe;
 
 import org.jetbrains.annotations.Nullable;
 
+import com.minelittlepony.unicopia.item.UItems;
+
 import net.minecraft.inventory.RecipeInputInventory;
 import net.minecraft.item.ItemStack;
 import net.minecraft.recipe.RecipeSerializer;
diff --git a/src/main/java/com/minelittlepony/unicopia/item/JarInsertRecipe.java b/src/main/java/com/minelittlepony/unicopia/recipe/JarInsertRecipe.java
similarity index 91%
rename from src/main/java/com/minelittlepony/unicopia/item/JarInsertRecipe.java
rename to src/main/java/com/minelittlepony/unicopia/recipe/JarInsertRecipe.java
index 776a8bc3..694c347a 100644
--- a/src/main/java/com/minelittlepony/unicopia/item/JarInsertRecipe.java
+++ b/src/main/java/com/minelittlepony/unicopia/recipe/JarInsertRecipe.java
@@ -1,4 +1,7 @@
-package com.minelittlepony.unicopia.item;
+package com.minelittlepony.unicopia.recipe;
+
+import com.minelittlepony.unicopia.item.EmptyJarItem;
+import com.minelittlepony.unicopia.item.UItems;
 
 import net.minecraft.inventory.RecipeInputInventory;
 import net.minecraft.item.ItemStack;
diff --git a/src/main/java/com/minelittlepony/unicopia/item/TransformCropsRecipe.java b/src/main/java/com/minelittlepony/unicopia/recipe/TransformCropsRecipe.java
similarity index 99%
rename from src/main/java/com/minelittlepony/unicopia/item/TransformCropsRecipe.java
rename to src/main/java/com/minelittlepony/unicopia/recipe/TransformCropsRecipe.java
index edc9924a..1d914706 100644
--- a/src/main/java/com/minelittlepony/unicopia/item/TransformCropsRecipe.java
+++ b/src/main/java/com/minelittlepony/unicopia/recipe/TransformCropsRecipe.java
@@ -1,4 +1,4 @@
-package com.minelittlepony.unicopia.item;
+package com.minelittlepony.unicopia.recipe;
 
 import java.util.HashSet;
 import java.util.Set;
diff --git a/src/main/java/com/minelittlepony/unicopia/item/URecipes.java b/src/main/java/com/minelittlepony/unicopia/recipe/URecipes.java
similarity index 97%
rename from src/main/java/com/minelittlepony/unicopia/item/URecipes.java
rename to src/main/java/com/minelittlepony/unicopia/recipe/URecipes.java
index 52aff325..d45af14c 100644
--- a/src/main/java/com/minelittlepony/unicopia/item/URecipes.java
+++ b/src/main/java/com/minelittlepony/unicopia/recipe/URecipes.java
@@ -1,10 +1,9 @@
-package com.minelittlepony.unicopia.item;
+package com.minelittlepony.unicopia.recipe;
 
 import java.util.List;
 
 import com.google.gson.JsonArray;
 import com.minelittlepony.unicopia.ability.magic.spell.crafting.*;
-import com.minelittlepony.unicopia.item.cloud.CloudShapingRecipe;
 
 import net.fabricmc.fabric.api.loot.v2.LootTableEvents;
 import net.minecraft.loot.LootTable;
diff --git a/src/main/java/com/minelittlepony/unicopia/item/ZapAppleRecipe.java b/src/main/java/com/minelittlepony/unicopia/recipe/ZapAppleRecipe.java
similarity index 96%
rename from src/main/java/com/minelittlepony/unicopia/item/ZapAppleRecipe.java
rename to src/main/java/com/minelittlepony/unicopia/recipe/ZapAppleRecipe.java
index 82c1d162..a92b956a 100644
--- a/src/main/java/com/minelittlepony/unicopia/item/ZapAppleRecipe.java
+++ b/src/main/java/com/minelittlepony/unicopia/recipe/ZapAppleRecipe.java
@@ -1,8 +1,9 @@
-package com.minelittlepony.unicopia.item;
+package com.minelittlepony.unicopia.recipe;
 
 import com.google.gson.JsonObject;
 import com.google.gson.JsonParseException;
 import com.google.gson.JsonSyntaxException;
+import com.minelittlepony.unicopia.item.UItems;
 
 import net.minecraft.item.ItemStack;
 import net.minecraft.network.PacketByteBuf;
diff --git a/src/main/java/com/minelittlepony/unicopia/server/world/UTreeGen.java b/src/main/java/com/minelittlepony/unicopia/server/world/UTreeGen.java
index 143db033..77f43a34 100644
--- a/src/main/java/com/minelittlepony/unicopia/server/world/UTreeGen.java
+++ b/src/main/java/com/minelittlepony/unicopia/server/world/UTreeGen.java
@@ -69,7 +69,7 @@ public interface UTreeGen {
             .sapling(Unicopia.id("palm_sapling")).sapling((generator, settings) -> {
                 return new SaplingBlock(generator, settings) {
                     @Override
-                    protected boolean canPlantOnTop(BlockState floor, BlockView world, BlockPos pos) {
+                    public boolean canPlantOnTop(BlockState floor, BlockView world, BlockPos pos) {
                         return floor.isIn(BlockTags.SAND);
                     }
                 };
diff --git a/src/main/java/com/minelittlepony/unicopia/util/FluidHelper.java b/src/main/java/com/minelittlepony/unicopia/util/FluidHelper.java
new file mode 100644
index 00000000..48508815
--- /dev/null
+++ b/src/main/java/com/minelittlepony/unicopia/util/FluidHelper.java
@@ -0,0 +1,69 @@
+package com.minelittlepony.unicopia.util;
+
+import java.util.Iterator;
+import java.util.Optional;
+import java.util.function.Function;
+
+import net.fabricmc.fabric.api.transfer.v1.context.ContainerItemContext;
+import net.fabricmc.fabric.api.transfer.v1.fluid.FluidConstants;
+import net.fabricmc.fabric.api.transfer.v1.fluid.FluidStorage;
+import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant;
+import net.fabricmc.fabric.api.transfer.v1.storage.Storage;
+import net.fabricmc.fabric.api.transfer.v1.storage.StorageView;
+import net.fabricmc.fabric.api.transfer.v1.transaction.Transaction;
+import net.minecraft.entity.player.PlayerEntity;
+import net.minecraft.fluid.FluidState;
+import net.minecraft.item.ItemStack;
+import net.minecraft.util.Hand;
+import net.minecraft.util.Pair;
+
+/**
+ * Here be dragons
+ */
+public interface FluidHelper {
+    static FluidState getFullFluidState(FluidVariant variant) {
+        return PsyFluidHelper.getFullFluidState(variant);
+    }
+
+    static Optional<Pair<Long, FluidVariant>> extract(ItemStack stack, PlayerEntity player, Hand hand) {
+        return getAsContainer(stack, ContainerItemContext.forPlayerInteraction(player, hand))
+                .filter(c -> !c.isResourceBlank())
+                .map(container -> applyTransaction(t -> {
+                    FluidVariant type = container.getResource();
+                    long amountExtracted = container.extract(type, FluidConstants.BUCKET, t);
+                    if (amountExtracted > 0) {
+                        return new Pair<>(amountExtracted, type);
+                    }
+                    return null;
+                }));
+    }
+
+    static long deposit(ItemStack stack, PlayerEntity player, Hand hand, FluidVariant variant, long amount) {
+        return amount - getAsStorage(stack, ContainerItemContext.forPlayerInteraction(player, hand))
+                .map(storage -> applyTransaction(t -> storage.insert(variant, amount, t)))
+                .orElse(0L);
+    }
+
+    private static Optional<Storage<FluidVariant>> getAsStorage(ItemStack stack, ContainerItemContext context) {
+        return Optional.ofNullable(FluidStorage.ITEM.find(stack, context));
+    }
+
+    private static Optional<StorageView<FluidVariant>> getAsContainer(ItemStack stack, ContainerItemContext context) {
+        return getAsStorage(stack, context).map(storage -> {
+            Iterator<StorageView<FluidVariant>> iter = storage.iterator();
+            return iter.hasNext() ? iter.next() : null;
+        });
+    }
+
+    private static <T> T applyTransaction(Function<Transaction, T> action) {
+        try (@SuppressWarnings("deprecation") var transaction = Transaction.isOpen()
+                ? Transaction.getCurrentUnsafe().openNested()
+                : Transaction.openOuter()) {
+            try {
+                return action.apply(transaction);
+            } finally {
+                transaction.commit();
+            }
+        }
+    }
+}
diff --git a/src/main/java/com/minelittlepony/unicopia/util/NbtSerialisable.java b/src/main/java/com/minelittlepony/unicopia/util/NbtSerialisable.java
index 819153e5..54093f51 100644
--- a/src/main/java/com/minelittlepony/unicopia/util/NbtSerialisable.java
+++ b/src/main/java/com/minelittlepony/unicopia/util/NbtSerialisable.java
@@ -8,12 +8,14 @@ import java.util.stream.Stream;
 import com.mojang.datafixers.util.Pair;
 import com.mojang.serialization.Codec;
 
+import net.minecraft.item.ItemStack;
 import net.minecraft.nbt.*;
 import net.minecraft.util.math.BlockPos;
 import net.minecraft.util.math.Vec3d;
 
 public interface NbtSerialisable {
     Serializer<BlockPos> BLOCK_POS = Serializer.of(NbtHelper::toBlockPos, NbtHelper::fromBlockPos);
+    Serializer<ItemStack> ITEM_STACK = Serializer.of(ItemStack::fromNbt, stack -> stack.writeNbt(new NbtCompound()));
 
     /**
      * Called to save this to nbt to persist state on file or to transmit over the network
@@ -44,6 +46,7 @@ public interface NbtSerialisable {
     }
 
     static Vec3d readVector(NbtList list) {
+
         return new Vec3d(list.getDouble(0), list.getDouble(1), list.getDouble(2));
     }
 
diff --git a/src/main/java/com/minelittlepony/unicopia/util/PosHelper.java b/src/main/java/com/minelittlepony/unicopia/util/PosHelper.java
index 7e203abd..2cb644e4 100644
--- a/src/main/java/com/minelittlepony/unicopia/util/PosHelper.java
+++ b/src/main/java/com/minelittlepony/unicopia/util/PosHelper.java
@@ -21,7 +21,7 @@ import net.minecraft.world.BlockView;
 import net.minecraft.world.World;
 
 public interface PosHelper {
-
+    Direction[] ALL = Direction.values();
     Direction[] HORIZONTAL = Arrays.stream(Direction.values()).filter(d -> d.getAxis().isHorizontal()).toArray(Direction[]::new);
 
     static Vec3d offset(Vec3d a, Vec3i b) {
diff --git a/src/main/java/com/minelittlepony/unicopia/util/PsyFluidHelper.java b/src/main/java/com/minelittlepony/unicopia/util/PsyFluidHelper.java
new file mode 100644
index 00000000..f83e44df
--- /dev/null
+++ b/src/main/java/com/minelittlepony/unicopia/util/PsyFluidHelper.java
@@ -0,0 +1,51 @@
+package com.minelittlepony.unicopia.util;
+
+import java.lang.reflect.Method;
+import java.util.Optional;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+import com.google.common.base.Suppliers;
+
+import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant;
+import net.minecraft.fluid.FluidState;
+import net.minecraft.item.ItemStack;
+import net.minecraft.item.Items;
+import net.minecraft.nbt.NbtCompound;
+import net.minecraft.registry.Registries;
+
+final class PsyFluidHelper {
+    private static final Supplier<Optional<Class<?>>> SIMPLE_FLUID_CLASS = Suppliers.memoize(() -> {
+        try {
+            return Optional.ofNullable(Class.forName("ivorius.psychedelicraft.fluid.SimpleFluid"));
+        } catch (Throwable t) {
+            return Optional.empty();
+        }
+    });
+    private static final Function<FluidVariant, FluidState> FALLBACK_METHOD = fluid -> fluid.getFluid().getDefaultState();
+    private static final Supplier<Function<FluidVariant, FluidState>> GET_FULL_FLUID_STATE = Suppliers.memoize(() -> SIMPLE_FLUID_CLASS.get().<Function<FluidVariant, FluidState>>map(type -> {
+            try {
+                final Method method = type.getDeclaredMethod("getFluidState", ItemStack.class);
+                if (method != null) {
+                    return fluid -> {
+                        try {
+                            ItemStack stack = Items.STONE.getDefaultStack();
+                            NbtCompound fluidTag = stack.getOrCreateSubNbt("fluid");
+                            fluidTag.putString("id", Registries.FLUID.getId(fluid.getFluid()).toString());
+                            fluidTag.put("attributes", fluid.getNbt());
+                            return FluidState.class.cast(method.invoke(type.cast(fluid), stack));
+                        } catch (Throwable tt) {}
+                        return FALLBACK_METHOD.apply(fluid);
+                    };
+                }
+            } catch (Throwable t) {}
+            return FALLBACK_METHOD;
+        }).orElse(FALLBACK_METHOD));
+
+    static FluidState getFullFluidState(FluidVariant variant) {
+        return SIMPLE_FLUID_CLASS.get()
+                .filter(type -> type.isAssignableFrom(variant.getFluid().getClass()))
+                .map(type -> GET_FULL_FLUID_STATE.get().apply(variant))
+                .orElseGet(() -> variant.getFluid().getDefaultState());
+    }
+}
diff --git a/src/main/java/com/minelittlepony/unicopia/util/registry/DynamicRegistry.java b/src/main/java/com/minelittlepony/unicopia/util/registry/DynamicRegistry.java
new file mode 100644
index 00000000..0dd2949a
--- /dev/null
+++ b/src/main/java/com/minelittlepony/unicopia/util/registry/DynamicRegistry.java
@@ -0,0 +1,45 @@
+package com.minelittlepony.unicopia.util.registry;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.Function;
+
+import net.fabricmc.fabric.api.event.registry.DynamicRegistrySetupCallback;
+import net.minecraft.registry.Registerable;
+import net.minecraft.registry.Registry;
+import net.minecraft.registry.RegistryBuilder;
+import net.minecraft.registry.RegistryKey;
+import net.minecraft.util.Identifier;
+
+public class DynamicRegistry<T> implements RegistryBuilder.BootstrapFunction<T> {
+    private final RegistryKey<Registry<T>> registry;
+    private final Map<RegistryKey<T>, Entry<T>> keys = new HashMap<>();
+    private final Function<RegistryKey<T>, T> valueFactory;
+
+    public DynamicRegistry(RegistryKey<Registry<T>> registry, Function<RegistryKey<T>, T> valueFactory) {
+        this.registry = registry;
+        this.valueFactory = valueFactory;
+
+        DynamicRegistrySetupCallback.EVENT.register(registries -> {
+            registries.getOptional(registry).ifPresent(r -> {
+                keys.forEach((key, entry)-> Registry.register(r, key.getValue(), entry.factory().apply(key)));
+            });
+        });
+    }
+
+    @Override
+    public void run(Registerable<T> registerable) {
+        keys.forEach((key, entry) -> registerable.register(key, entry.factory().apply(key)));
+    }
+
+    public RegistryKey<T> register(Identifier id) {
+        return register(id, valueFactory);
+    }
+
+    public RegistryKey<T> register(Identifier id, Function<RegistryKey<T>, T> valueFactory) {
+        return keys.computeIfAbsent(RegistryKey.of(registry, id), k -> new Entry<>(k, valueFactory)).key();
+    }
+
+    record Entry<T>(RegistryKey<T> key, Function<RegistryKey<T>, T> factory) {}
+
+}
diff --git a/src/main/resources/assets/unicopia/lang/en_us.json b/src/main/resources/assets/unicopia/lang/en_us.json
index 54133a8a..df8a8f2e 100644
--- a/src/main/resources/assets/unicopia/lang/en_us.json
+++ b/src/main/resources/assets/unicopia/lang/en_us.json
@@ -74,6 +74,14 @@
   "item.unicopia.cooked_zap_apple": "Cooked Zap Apple",
   "item.unicopia.zap_apple": "Zap Apple",
   "item.unicopia.zap_bulb": "Unripened Zap Apple",
+  "item.unicopia.rotten_cod": "Rotten Cod",
+  "item.unicopia.rotten_salmon": "Rotten Salmon",
+  "item.unicopia.rotten_tropical_fish": "Rotten Tropical Fish",
+  "item.unicopia.rotten_pufferfish": "Rotten Pufferfish",
+  "item.unicopia.cooked_tropical_fish": "Cooked Tropical Fish",
+  "item.unicopia.cooked_pufferfish": "Cooked Pufferfish",
+  "item.unicopia.fried_axolotl": "Fried Axolotl",
+  "item.unicopia.green_fried_egg": "Green Fried Egg",
 
   "item.unicopia.love_bottle": "Bottle o' Love",
   "item.unicopia.love_bucket": "Love Bucket",
@@ -619,42 +627,43 @@
   "unicopia.diet.hunger": "Hunger Ratio: %s%%",
   "unicopia.diet.saturation": "Saturation Ratio: %s%%",
   
-  "tag.unicopia.food_types.rotten_meat": "Rotting Meat",
-  "tag.unicopia.food_types.raw_meat": "Fresh Meat",
-  "tag.unicopia.food_types.cooked_meat": "Prepared Meat",
-  "tag.unicopia.food_types.raw_fish": "Fresh Fish",
-  "tag.unicopia.food_types.cooked_fish": "Prepared Fish",
-  "tag.unicopia.food_types.raw_insect": "Bugs & Insects",
-  "tag.unicopia.food_types.cooked_insect": "Cooked Bugs & Insects",
-  "tag.unicopia.food_types.nuts_and_seeds": "Nuts & Seeds",
-  "tag.unicopia.food_types.love": "Love",
-  "tag.unicopia.food_types.rocks": "Rocks",
-  "tag.unicopia.food_types.pinecone": "Nuts & Seeds",
-  "tag.unicopia.food_types.bat_ponys_delight": "Bat Pony Treats",
-  "tag.unicopia.food_types.cooked_sea_vegitables": "Prepared Fish Food",
-  "tag.unicopia.food_types.raw_sea_vegitables": "Fresh Fish Food",
-  "tag.unicopia.food_types.shells": "Sea Shells",
-  "tag.unicopia.food_types.shelly": "Sea Shells",
-  "tag.unicopia.food_types.candy": "Candy",
-  "tag.unicopia.food_types.desserts": "Desserts",
-  "tag.unicopia.food_types.fruit": "Fruit",
-  "tag.unicopia.food_types.baked_goods": "Baked Goods",
-  "tag.unicopia.food_types.misc": "Misc",
-  "tag.unicopia.food_types.fruits_and_vegetables": "Fruits & Vegetables",
-  "tag.unicopia.food_types.drinks": "Drinks",
-  "tag.minecraft.leaves": "Leaves",
-
-  "tag.unicopia.food_types.forage_edible_filling": "Bulky Plant Matter",
-  "tag.unicopia.food_types.forage_edible": "Plant Matter",
-  "tag.unicopia.food_types.forage_nauseating": "Nauseating",
-  "tag.unicopia.food_types.forage_prickly": "Prickly",
-  "tag.unicopia.food_types.forage_risky": "Unsafe",
-  "tag.unicopia.food_types.forage_strengthening": "Strength Enhancing",
-  "tag.unicopia.food_types.forage_severely_prickly": "Very Prickly",
-  "tag.unicopia.food_types.forage_severely_nauseating": "Sickening",
-  "tag.unicopia.food_types.forage_radioactive": "Glowy",
-  "tag.unicopia.food_types.forage_dangerous": "Dangerous",
-  "tag.unicopia.food_types.forage_blinding": "Toxic",
+  "food_group.unicopia.meat.rotten": "Rotting Meat",
+  "food_group.unicopia.meat.raw": "Fresh Meat",
+  "food_group.unicopia.meat.cooked": "Prepared Meat",
+  "food_group.unicopia.fish.rotten": "Rotten Fish",
+  "food_group.unicopia.fish.raw": "Fresh Fish",
+  "food_group.unicopia.fish.cooked": "Prepared Fish",
+  "food_group.unicopia.insect.rotten": "Rotted Bugs & Insects",
+  "food_group.unicopia.insect.raw": "Bugs & Insects",
+  "food_group.unicopia.insect.cooked": "Cooked Bugs & Insects",
+  "food_group.unicopia.nuts_and_seeds": "Nuts & Seeds",
+  "food_group.unicopia.love": "Love",
+  "food_group.unicopia.rocks": "Rocks",
+  "food_group.unicopia.pinecone": "Nuts & Seeds",
+  "food_group.unicopia.bat_ponys_delight": "Bat Pony Treats",
+  "food_group.unicopia.sea_vegetable.cooked": "Prepared Shells & Coral",
+  "food_group.unicopia.sea_vegetable.raw": "Shells & Coral",
+  "food_group.unicopia.shells": "Sea Shells",
+  "food_group.unicopia.special_shells": "Companions",
+  "food_group.unicopia.candy": "Candy",
+  "food_group.unicopia.desserts": "Desserts",
+  "food_group.unicopia.fruit": "Fruit",
+  "food_group.unicopia.baked_goods": "Baked Goods",
+  "food_group.unicopia.misc": "Misc",
+  "food_group.unicopia.fruits_and_vegetables": "Fruits & Vegetables",
+  "food_group.unicopia.drinks": "Drinks",
+  "food_group.unicopia.foraging.edible_filling": "Bulky Plant Matter",
+  "food_group.unicopia.foraging.edible": "Plant Matter",
+  "food_group.unicopia.foraging.nauseating": "Nauseating",
+  "food_group.unicopia.foraging.prickly": "Prickly",
+  "food_group.unicopia.foraging.risky": "Unsafe",
+  "food_group.unicopia.foraging.strengthening": "Strength Enhancing",
+  "food_group.unicopia.foraging.severely_prickly": "Very Prickly",
+  "food_group.unicopia.foraging.severely_nauseating": "Sickening",
+  "food_group.unicopia.foraging.radioactive": "Glowy",
+  "food_group.unicopia.foraging.dangerous": "Dangerous",
+  "food_group.unicopia.foraging.blinding": "Toxic",
+  "food_group.unicopia.foraging.leafy_greens": "Leafy Greens",
 
   "toxicity.safe.name": "Safe",
   "toxicity.mild.name": "Mildly Toxic",
@@ -1638,6 +1647,8 @@
   "advancements.unicopia.eat_trick_apple.description": "Bite into a zap apple",
   "advancements.unicopia.eat_pinecone.title": "Desperation",
   "advancements.unicopia.eat_pinecone.description": "Eat a pinecone",
+  "advancements.unicopia.tastes_like_chicken.title": "Tastes Like Chicken",
+  "advancements.unicopia.tastes_like_chicken.description": "Fry and eat an axolotl",
   "advancements.unicopia.what_the_hay.title": "What The Hay",
   "advancements.unicopia.what_the_hay.description": "Eat an entire block of hay",
   "advancements.unicopia.oats_so_easy.title": "Oats So Easy",
diff --git a/src/main/resources/assets/unicopia/models/item/mysterious_egg.json b/src/main/resources/assets/unicopia/models/item/mysterious_egg.json
deleted file mode 100644
index 7c9548c9..00000000
--- a/src/main/resources/assets/unicopia/models/item/mysterious_egg.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
-    "parent": "unicopia:block/mysterious_egg_stage1",
-    "gui_light": "side",
-    "display": {
-        "gui": {
-            "rotation": [ 30, 225, 0 ],
-            "translation": [ 0, 0, 0],
-            "scale":[ 0.625, 0.625, 0.625 ]
-        },
-        "fixed": {
-            "rotation": [ 0, 0, 0 ],
-            "translation": [ 0, 0, 0],
-            "scale":[ 0.5, 0.5, 0.5 ]
-        }
-    }
-}
diff --git a/src/main/resources/assets/unicopia/textures/item/cooked_pufferfish.png b/src/main/resources/assets/unicopia/textures/item/cooked_pufferfish.png
new file mode 100644
index 00000000..eef6293b
Binary files /dev/null and b/src/main/resources/assets/unicopia/textures/item/cooked_pufferfish.png differ
diff --git a/src/main/resources/assets/unicopia/textures/item/cooked_tropical_fish.png b/src/main/resources/assets/unicopia/textures/item/cooked_tropical_fish.png
new file mode 100644
index 00000000..93747e0f
Binary files /dev/null and b/src/main/resources/assets/unicopia/textures/item/cooked_tropical_fish.png differ
diff --git a/src/main/resources/assets/unicopia/textures/item/fried_axolotl.png b/src/main/resources/assets/unicopia/textures/item/fried_axolotl.png
new file mode 100644
index 00000000..c1f00289
Binary files /dev/null and b/src/main/resources/assets/unicopia/textures/item/fried_axolotl.png differ
diff --git a/src/main/resources/assets/unicopia/textures/item/fried_egg.png b/src/main/resources/assets/unicopia/textures/item/fried_egg.png
new file mode 100644
index 00000000..55d4a4ac
Binary files /dev/null and b/src/main/resources/assets/unicopia/textures/item/fried_egg.png differ
diff --git a/src/main/resources/assets/unicopia/textures/item/green_fried_egg.png b/src/main/resources/assets/unicopia/textures/item/green_fried_egg.png
new file mode 100644
index 00000000..46e85b59
Binary files /dev/null and b/src/main/resources/assets/unicopia/textures/item/green_fried_egg.png differ
diff --git a/src/main/resources/assets/unicopia/textures/item/mysterious_egg.png b/src/main/resources/assets/unicopia/textures/item/mysterious_egg.png
new file mode 100644
index 00000000..bc1d9a42
Binary files /dev/null and b/src/main/resources/assets/unicopia/textures/item/mysterious_egg.png differ
diff --git a/src/main/resources/assets/unicopia/textures/item/rotten_cod.png b/src/main/resources/assets/unicopia/textures/item/rotten_cod.png
new file mode 100644
index 00000000..9cd70e51
Binary files /dev/null and b/src/main/resources/assets/unicopia/textures/item/rotten_cod.png differ
diff --git a/src/main/resources/assets/unicopia/textures/item/rotten_pufferfish.png b/src/main/resources/assets/unicopia/textures/item/rotten_pufferfish.png
new file mode 100644
index 00000000..24ade9a5
Binary files /dev/null and b/src/main/resources/assets/unicopia/textures/item/rotten_pufferfish.png differ
diff --git a/src/main/resources/assets/unicopia/textures/item/rotten_salmon.png b/src/main/resources/assets/unicopia/textures/item/rotten_salmon.png
new file mode 100644
index 00000000..fc4d53c0
Binary files /dev/null and b/src/main/resources/assets/unicopia/textures/item/rotten_salmon.png differ
diff --git a/src/main/resources/assets/unicopia/textures/item/rotten_tropical_fish.png b/src/main/resources/assets/unicopia/textures/item/rotten_tropical_fish.png
new file mode 100644
index 00000000..7c035402
Binary files /dev/null and b/src/main/resources/assets/unicopia/textures/item/rotten_tropical_fish.png differ
diff --git a/src/main/resources/assets/unicopia/textures/item/slime_pustule.png b/src/main/resources/assets/unicopia/textures/item/slime_pustule.png
new file mode 100644
index 00000000..e3111b43
Binary files /dev/null and b/src/main/resources/assets/unicopia/textures/item/slime_pustule.png differ
diff --git a/src/main/resources/data/c/tags/blocks/concrete_powders.json b/src/main/resources/data/c/tags/blocks/concrete_powders.json
deleted file mode 100644
index e3142856..00000000
--- a/src/main/resources/data/c/tags/blocks/concrete_powders.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "minecraft:white_concrete_powder",
-    "minecraft:orange_concrete_powder",
-    "minecraft:magenta_concrete_powder",
-    "minecraft:light_blue_concrete_powder",
-    "minecraft:yellow_concrete_powder",
-    "minecraft:lime_concrete_powder",
-    "minecraft:pink_concrete_powder",
-    "minecraft:gray_concrete_powder",
-    "minecraft:light_gray_concrete_powder",
-    "minecraft:cyan_concrete_powder",
-    "minecraft:purple_concrete_powder",
-    "minecraft:blue_concrete_powder",
-    "minecraft:brown_concrete_powder",
-    "minecraft:green_concrete_powder",
-    "minecraft:red_concrete_powder",
-    "minecraft:black_concrete_powder"
-  ]
-}
diff --git a/src/main/resources/data/c/tags/blocks/glass_blocks.json b/src/main/resources/data/c/tags/blocks/glass_blocks.json
deleted file mode 100644
index f55e9719..00000000
--- a/src/main/resources/data/c/tags/blocks/glass_blocks.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "minecraft:glass",
-    "minecraft:white_stained_glass",
-    "minecraft:orange_stained_glass",
-    "minecraft:magenta_stained_glass",
-    "minecraft:light_blue_stained_glass",
-    "minecraft:yellow_stained_glass",
-    "minecraft:lime_stained_glass",
-    "minecraft:pink_stained_glass",
-    "minecraft:gray_stained_glass",
-    "minecraft:light_gray_stained_glass",
-    "minecraft:cyan_stained_glass",
-    "minecraft:purple_stained_glass",
-    "minecraft:blue_stained_glass",
-    "minecraft:brown_stained_glass",
-    "minecraft:green_stained_glass",
-    "minecraft:red_stained_glass",
-    "minecraft:black_stained_glass",
-    { "id": "#c:glass", "required": false },
-    { "id": "#c:glass_blocks", "required": false }
-  ]
-}
diff --git a/src/main/resources/data/c/tags/blocks/glass_panes.json b/src/main/resources/data/c/tags/blocks/glass_panes.json
deleted file mode 100644
index ff9176f7..00000000
--- a/src/main/resources/data/c/tags/blocks/glass_panes.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "minecraft:glass_pane",
-    "minecraft:white_stained_glass_pane",
-    "minecraft:orange_stained_glass_pane",
-    "minecraft:magenta_stained_glass_pane",
-    "minecraft:light_blue_stained_glass_pane",
-    "minecraft:yellow_stained_glass_pane",
-    "minecraft:lime_stained_glass_pane",
-    "minecraft:pink_stained_glass_pane",
-    "minecraft:gray_stained_glass_pane",
-    "minecraft:light_gray_stained_glass_pane",
-    "minecraft:cyan_stained_glass_pane",
-    "minecraft:purple_stained_glass_pane",
-    "minecraft:blue_stained_glass_pane",
-    "minecraft:brown_stained_glass_pane",
-    "minecraft:green_stained_glass_pane",
-    "minecraft:red_stained_glass_pane",
-    "minecraft:black_stained_glass_pane"
-  ]
-}
diff --git a/src/main/resources/data/c/tags/blocks/ores.json b/src/main/resources/data/c/tags/blocks/ores.json
deleted file mode 100644
index 1a53e7a3..00000000
--- a/src/main/resources/data/c/tags/blocks/ores.json
+++ /dev/null
@@ -1,78 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "minecraft:coal_ore",
-    "minecraft:iron_ore",
-    "minecraft:gold_ore",
-    "minecraft:emerald_ore",
-    "minecraft:lapis_ore",
-    "minecraft:copper_ore",
-    "minecraft:diamond_ore",
-    "minecraft:nether_gold_ore",
-    "minecraft:nether_quartz_ore",
-    { "id": "#c:iron_ores", "required": false },
-    { "id": "#c:gold_ores", "required": false },
-    { "id": "#c:diamond_ores", "required": false },
-    { "id": "#c:emerald_ores", "required": false },
-    { "id": "#c:copper_ores", "required": false },
-    { "id": "#c:quartz_ores", "required": false },
-    { "id": "#c:lapis_ores", "required": false },
-    { "id": "#c:aluminium_ores", "required": false },
-    { "id": "#c:methyst_ores", "required": false },
-    { "id": "#c:antimony_ores", "required": false },
-    { "id": "#c:aquarium_ores", "required": false },
-    { "id": "#c:asterite_ores", "required": false },
-    { "id": "#c:banglum_ores", "required": false },
-    { "id": "#c:bauxite_ores", "required": false },
-    { "id": "#c:carmot_ores", "required": false },
-    { "id": "#c:certus_quartz_ores", "required": false },
-    { "id": "#c:cinnabar_ores", "required": false },
-    { "id": "#c:cobalt_ores", "required": false },
-    { "id": "#c:galaxium_ores", "required": false },
-    { "id": "#c:galena_ores", "required": false },
-    { "id": "#c:iridium_ores", "required": false },
-    { "id": "#c:kyber_ores", "required": false },
-    { "id": "#c:lunum_ores", "required": false },
-    { "id": "#c:lutetium_ores", "required": false },
-    { "id": "#c:menganese_ores", "required": false },
-    { "id": "#c:metite_ores", "required": false },
-    { "id": "#c:midas_gold_ores", "required": false },
-    { "id": "#c:moon_lunum_ores", "required": false },
-    { "id": "#c:mozanite_ores", "required": false },
-    { "id": "#c:mythril_ores", "required": false },
-    { "id": "#c:nickle_ores", "required": false },
-    { "id": "#c:nikolite_ores", "required": false },
-    { "id": "#c:orichalcum_ores", "required": false },
-    { "id": "#c:osmium_ores", "required": false },
-    { "id": "#c:palladium_ores", "required": false },
-    { "id": "#c:peridot_ores", "required": false },
-    { "id": "#c:platinum_ores", "required": false },
-    { "id": "#c:plutonium_blocks", "required": false },
-    { "id": "#c:prometheum_ores", "required": false },
-    { "id": "#c:pyrite_ores", "required": false },
-    { "id": "#c:quadrillium_ores", "required": false },
-    { "id": "#c:ruby_ores", "required": false },
-    { "id": "#c:runite_ores", "required": false },
-    { "id": "#c:sapphire_ores", "required": false },
-    { "id": "#c:sheldonite_ores", "required": false },
-    { "id": "#c:silver_ores", "required": false },
-    { "id": "#c:sodalite_ores", "required": false },
-    { "id": "#c:sphalerite_ores", "required": false },
-    { "id": "#c:starrite_ores", "required": false },
-    { "id": "#c:stellum_ores", "required": false },
-    { "id": "#c:stormyx_ores", "required": false },
-    { "id": "#c:sulfur_ores", "required": false },
-    { "id": "#c:tantalite_ores", "required": false },
-    { "id": "#c:tin_ore", "required": false },
-    { "id": "#c:tin_ores", "required": false },
-    { "id": "#c:titanium_ores", "required": false },
-    { "id": "#c:topaz_ores", "required": false },
-    { "id": "#c:truesilver_ores", "required": false },
-    { "id": "#c:tungsten_ores", "required": false },
-    { "id": "#c:unobtainium_ores", "required": false },
-    { "id": "#c:ur_ores", "required": false },
-    { "id": "#c:uranium_ores", "required": false },
-    { "id": "#c:vermiculite_ores", "required": false },
-    { "id": "#c:zinc_ores", "required": false }
-  ]
-}
diff --git a/src/main/resources/data/c/tags/items/concrete.json b/src/main/resources/data/c/tags/items/concrete.json
deleted file mode 100644
index c09d67ba..00000000
--- a/src/main/resources/data/c/tags/items/concrete.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "minecraft:white_concrete",
-    "minecraft:orange_concrete",
-    "minecraft:magenta_concrete",
-    "minecraft:light_blue_concrete",
-    "minecraft:yellow_concrete",
-    "minecraft:lime_concrete",
-    "minecraft:pink_concrete",
-    "minecraft:gray_concrete",
-    "minecraft:light_gray_concrete",
-    "minecraft:cyan_concrete",
-    "minecraft:purple_concrete",
-    "minecraft:blue_concrete",
-    "minecraft:brown_concrete",
-    "minecraft:green_concrete",
-    "minecraft:red_concrete",
-    "minecraft:black_concrete"
-  ]
-}
diff --git a/src/main/resources/data/c/tags/items/concrete_powders.json b/src/main/resources/data/c/tags/items/concrete_powders.json
deleted file mode 100644
index e3142856..00000000
--- a/src/main/resources/data/c/tags/items/concrete_powders.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "minecraft:white_concrete_powder",
-    "minecraft:orange_concrete_powder",
-    "minecraft:magenta_concrete_powder",
-    "minecraft:light_blue_concrete_powder",
-    "minecraft:yellow_concrete_powder",
-    "minecraft:lime_concrete_powder",
-    "minecraft:pink_concrete_powder",
-    "minecraft:gray_concrete_powder",
-    "minecraft:light_gray_concrete_powder",
-    "minecraft:cyan_concrete_powder",
-    "minecraft:purple_concrete_powder",
-    "minecraft:blue_concrete_powder",
-    "minecraft:brown_concrete_powder",
-    "minecraft:green_concrete_powder",
-    "minecraft:red_concrete_powder",
-    "minecraft:black_concrete_powder"
-  ]
-}
diff --git a/src/main/resources/data/c/tags/items/cooked_insects.json b/src/main/resources/data/c/tags/items/cooked_insects.json
deleted file mode 100644
index 1a241c36..00000000
--- a/src/main/resources/data/c/tags/items/cooked_insects.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "minecraft:fermented_spider_eye",
-    { "id": "#c:cooked_insect", "required": false }
-  ]
-}
diff --git a/src/main/resources/data/c/tags/items/cooked_meats.json b/src/main/resources/data/c/tags/items/cooked_meats.json
deleted file mode 100644
index 52b592bc..00000000
--- a/src/main/resources/data/c/tags/items/cooked_meats.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "minecraft:cooked_porkchop",
-    "minecraft:cooked_beef",
-    "minecraft:cooked_mutton",
-    "minecraft:cooked_rabbit",
-    "minecraft:rabbit_stew",
-    "minecraft:cooked_chicken",
-    { "id": "#c:cooked_meat", "required": false },
-    { "id": "#c:cooked_bacon", "required": false },
-    { "id": "#c:cooked_beef", "required": false },
-    { "id": "#c:cooked_chicken", "required": false },
-    { "id": "#c:cooked_mutton", "required": false },
-    { "id": "#c:cooked_pork", "required": false },
-    { "id": "#c:fried_chickens", "required": false },
-    { "id": "#c:hamburgers", "required": false },
-    { "id": "#c:pork_and_beans", "required": false },
-    { "id": "#c:pork_jerkies", "required": false },
-    { "id": "#c:protein", "required": false }
-  ]
-}
diff --git a/src/main/resources/data/c/tags/items/coral_blocks.json b/src/main/resources/data/c/tags/items/coral_blocks.json
deleted file mode 100644
index e907eedc..00000000
--- a/src/main/resources/data/c/tags/items/coral_blocks.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "minecraft:tube_coral_block",
-    "minecraft:brain_coral_block",
-    "minecraft:bubble_coral_block",
-    "minecraft:fire_coral_block",
-    "minecraft:horn_coral_block"
-  ]
-}
diff --git a/src/main/resources/data/c/tags/items/coral_fans.json b/src/main/resources/data/c/tags/items/coral_fans.json
deleted file mode 100644
index 531d24c9..00000000
--- a/src/main/resources/data/c/tags/items/coral_fans.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "minecraft:tube_coral_fan",
-    "minecraft:brain_coral_fan",
-    "minecraft:bubble_coral_fan",
-    "minecraft:fire_coral_fan",
-    "minecraft:horn_coral_fan"
-  ]
-}
diff --git a/src/main/resources/data/c/tags/items/corals.json b/src/main/resources/data/c/tags/items/corals.json
deleted file mode 100644
index cec1b08e..00000000
--- a/src/main/resources/data/c/tags/items/corals.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "minecraft:tube_coral",
-    "minecraft:brain_coral",
-    "minecraft:bubble_coral",
-    "minecraft:fire_coral",
-    "minecraft:horn_coral"
-  ]
-}
diff --git a/src/main/resources/data/c/tags/items/foraging/edibles.json b/src/main/resources/data/c/tags/items/foraging/edibles.json
deleted file mode 100644
index a0432ed7..00000000
--- a/src/main/resources/data/c/tags/items/foraging/edibles.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    { "id": "#c:mushrooms", "required": false },
-    { "id": "#c:saplings", "required": false },
-    { "id": "farmersdelight:sandy_shrub", "required": false },
-    { "id": "farmersdelight:wild_cabbages", "required": false },
-    { "id": "farmersdelight:wild_onions", "required": false },
-    { "id": "farmersdelight:wild_carrots", "required": false },
-    { "id": "farmersdelight:wild_beetroots", "required": false },
-    { "id": "farmersdelight:wild_rice", "required": false }
-  ]
-}
diff --git a/src/main/resources/data/c/tags/items/foraging/edibles_filling.json b/src/main/resources/data/c/tags/items/foraging/edibles_filling.json
deleted file mode 100644
index bc799386..00000000
--- a/src/main/resources/data/c/tags/items/foraging/edibles_filling.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    { "id": "farmersdelight:horse_feed", "required": false },
-    { "id": "farmersdelight:rice_bale", "required": false },
-    { "id": "farmersdelight:straw_bale", "required": false }
-  ]
-}
diff --git a/src/main/resources/data/c/tags/items/foraging/risky.json b/src/main/resources/data/c/tags/items/foraging/risky.json
deleted file mode 100644
index aa54573a..00000000
--- a/src/main/resources/data/c/tags/items/foraging/risky.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    { "id": "#c:meads", "required": false },
-    { "id": "farmersdelight:wild_tomatoes", "required": false },
-    { "id": "farmersdelight:wild_potatoes", "required": false }
-  ]
-}
diff --git a/src/main/resources/data/c/tags/items/glazed_terracotta.json b/src/main/resources/data/c/tags/items/glazed_terracotta.json
deleted file mode 100644
index 02b98848..00000000
--- a/src/main/resources/data/c/tags/items/glazed_terracotta.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "minecraft:white_glazed_terracotta",
-    "minecraft:orange_glazed_terracotta",
-    "minecraft:magenta_glazed_terracotta",
-    "minecraft:light_blue_glazed_terracotta",
-    "minecraft:yellow_glazed_terracotta",
-    "minecraft:lime_glazed_terracotta",
-    "minecraft:pink_glazed_terracotta",
-    "minecraft:gray_glazed_terracotta",
-    "minecraft:light_gray_glazed_terracotta",
-    "minecraft:cyan_glazed_terracotta",
-    "minecraft:purple_glazed_terracotta",
-    "minecraft:blue_glazed_terracotta",
-    "minecraft:brown_glazed_terracotta",
-    "minecraft:green_glazed_terracotta",
-    "minecraft:red_glazed_terracotta",
-    "minecraft:black_glazed_terracotta"
-  ]
-}
diff --git a/src/main/resources/data/c/tags/items/love.json b/src/main/resources/data/c/tags/items/love.json
deleted file mode 100644
index 213d70aa..00000000
--- a/src/main/resources/data/c/tags/items/love.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "unicopia:love_bottle",
-    "unicopia:love_bucket",
-    "unicopia:love_mug"
-  ]
-}
diff --git a/src/main/resources/data/c/tags/items/raw_fish.json b/src/main/resources/data/c/tags/items/raw_fish.json
deleted file mode 100644
index 902fad0f..00000000
--- a/src/main/resources/data/c/tags/items/raw_fish.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "minecraft:pufferfish",
-    "minecraft:cod",
-    "minecraft:salmon",
-    "minecraft:tropical_fish",
-    { "id": "#c:mollusks", "required": false }
-  ]
-}
diff --git a/src/main/resources/data/c/tags/items/raw_insects.json b/src/main/resources/data/c/tags/items/raw_insects.json
deleted file mode 100644
index ad219e8b..00000000
--- a/src/main/resources/data/c/tags/items/raw_insects.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "minecraft:spider_eye",
-    "unicopia:butterfly",
-    "unicopia:wheat_worms",
-    "unicopia:worm_block"
-  ]
-}
diff --git a/src/main/resources/data/c/tags/items/raw_meats.json b/src/main/resources/data/c/tags/items/raw_meats.json
deleted file mode 100644
index 5333f1f8..00000000
--- a/src/main/resources/data/c/tags/items/raw_meats.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "minecraft:porkchop",
-    "minecraft:beef",
-    "minecraft:mutton",
-    "minecraft:rabbit",
-    "minecraft:chicken",
-    { "id": "#c:raw_meat", "required": false },
-    { "id": "#c:lemon_chickens", "required": false },
-    { "id": "#c:raw_bacon", "required": false },
-    { "id": "#c:raw_beef", "required": false },
-    { "id": "#c:raw_chicken", "required": false },
-    { "id": "#c:raw_mutton", "required": false },
-    { "id": "#c:raw_pork", "required": false }
-  ]
-}
diff --git a/src/main/resources/data/c/tags/items/rocks.json b/src/main/resources/data/c/tags/items/rocks.json
deleted file mode 100644
index 9ab866dd..00000000
--- a/src/main/resources/data/c/tags/items/rocks.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "unicopia:rock"
-  ]
-}
diff --git a/src/main/resources/data/c/tags/items/rotten_meats.json b/src/main/resources/data/c/tags/items/rotten_meats.json
deleted file mode 100644
index 3f3bc662..00000000
--- a/src/main/resources/data/c/tags/items/rotten_meats.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "minecraft:rotten_flesh"
-  ]
-}
diff --git a/src/main/resources/data/c/tags/items/worms.json b/src/main/resources/data/c/tags/items/worms.json
deleted file mode 100644
index 9c8b8692..00000000
--- a/src/main/resources/data/c/tags/items/worms.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "unicopia:wheat_worms"
-  ]
-}
diff --git a/src/main/resources/data/minecraft/traits/blocks/overworld/conglomerate_materials_from_ground.json b/src/main/resources/data/minecraft/traits/blocks/overworld/conglomerate_materials_from_ground.json
index a19e4901..200f8b3f 100644
--- a/src/main/resources/data/minecraft/traits/blocks/overworld/conglomerate_materials_from_ground.json
+++ b/src/main/resources/data/minecraft/traits/blocks/overworld/conglomerate_materials_from_ground.json
@@ -3,7 +3,7 @@
   "traits": "earth:1 order:1 knowledge:4",
   "items": [
     "#minecraft:terracotta",
-    "#c:concrete",
-    "#c:glazed_terracotta"
+    "#c:concretes",
+    "#c:glazed_terracottas"
   ]
 }
\ No newline at end of file
diff --git a/src/main/resources/data/minecraft/traits/items/overworld/edible_cooked_meat.json b/src/main/resources/data/minecraft/traits/items/overworld/edible_cooked_meat.json
index e65442d1..8dd2afb5 100644
--- a/src/main/resources/data/minecraft/traits/items/overworld/edible_cooked_meat.json
+++ b/src/main/resources/data/minecraft/traits/items/overworld/edible_cooked_meat.json
@@ -2,8 +2,6 @@
   "replace": false,
   "traits": "famine:-0.5 life:-1 knowledge:2",
   "items": [
-    "#c:cooked_meats",
-    "#c:cooked_fish",
     "minecraft:fermented_spider_eye",
     "#unicopia:food_types/cooked_fish",
     "#unicopia:food_types/cooked_meat"
diff --git a/src/main/resources/data/minecraft/traits/items/overworld/edible_raw_meat.json b/src/main/resources/data/minecraft/traits/items/overworld/edible_raw_meat.json
index 07371361..19d29187 100644
--- a/src/main/resources/data/minecraft/traits/items/overworld/edible_raw_meat.json
+++ b/src/main/resources/data/minecraft/traits/items/overworld/edible_raw_meat.json
@@ -2,6 +2,6 @@
   "replace": false,
   "traits": "blood:1 famine:-2",
   "items": [
-    "#c:raw_meats"
+    "#c:raw_meat"
   ]
 }
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/diets/food_effects/baked_goods.json b/src/main/resources/data/unicopia/diets/food_effects/baked_goods.json
deleted file mode 100644
index 31306e54..00000000
--- a/src/main/resources/data/unicopia/diets/food_effects/baked_goods.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-  "tags": [ "unicopia:food_types/baked_goods" ],
-  "food_component": {
-    "hunger": 1,
-    "saturation": 1
-  },
-  "ailment": {
-    "effects": [
-    ]
-  }
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/diets/food_effects/candy.json b/src/main/resources/data/unicopia/diets/food_effects/candy.json
deleted file mode 100644
index a7d7d64b..00000000
--- a/src/main/resources/data/unicopia/diets/food_effects/candy.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-  "tags": [ "unicopia:food_types/candy" ],
-  "food_component": {
-    "hunger": 1,
-    "saturation": 1
-  },
-  "ailment": {
-    "effects": [
-    ]
-  }
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/diets/food_effects/desserts.json b/src/main/resources/data/unicopia/diets/food_effects/desserts.json
deleted file mode 100644
index 63913e02..00000000
--- a/src/main/resources/data/unicopia/diets/food_effects/desserts.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-  "tags": [ "unicopia:food_types/desserts" ],
-  "food_component": {
-    "hunger": 1,
-    "saturation": 1
-  },
-  "ailment": {
-    "effects": [
-    ]
-  }
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/diets/food_effects/fish/cooked.json b/src/main/resources/data/unicopia/diets/food_effects/fish/cooked.json
deleted file mode 100644
index 423e578f..00000000
--- a/src/main/resources/data/unicopia/diets/food_effects/fish/cooked.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
-  "tags": [ "unicopia:food_types/cooked_fish" ],
-  "food_component": {
-    "hunger": 1,
-    "saturation": 0.1
-  },
-  "ailment": {
-    "effects": [
-      {
-        "effect": "unicopia:food_poisoning",
-        "seconds": 100,
-        "amplifier": 2
-      }
-    ]
-  }
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/diets/food_effects/fish/raw.json b/src/main/resources/data/unicopia/diets/food_effects/fish/raw.json
deleted file mode 100644
index 40368a26..00000000
--- a/src/main/resources/data/unicopia/diets/food_effects/fish/raw.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
-  "tags": [ "unicopia:food_types/raw_fish" ],
-  "food_component": {
-    "hunger": 1,
-    "saturation": 0.1
-  },
-  "ailment": {
-    "effects": [
-      {
-        "effect": "minecraft:poison",
-        "seconds": 45,
-        "amplifier": 2,
-        "chance": 80
-      },
-      {
-        "effect": "unicopia:food_poisoning",
-        "seconds": 100,
-        "amplifier": 2
-      }
-    ]
-  }
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/diets/food_effects/fish/rotten.json b/src/main/resources/data/unicopia/diets/food_effects/fish/rotten.json
deleted file mode 100644
index 4259828b..00000000
--- a/src/main/resources/data/unicopia/diets/food_effects/fish/rotten.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
-  "tags": [ "unicopia:food_types/rotten_fish" ],
-  "food_component": {
-    "hunger": 1,
-    "saturation": 0.1
-  },
-  "ailment": {
-    "effects": [
-      {
-        "effect": "minecraft:poison",
-        "seconds": 45,
-        "amplifier": 2,
-        "chance": 80
-      },
-      {
-        "effect": "unicopia:food_poisoning",
-        "seconds": 400,
-        "amplifier": 3,
-        "chance": 5
-      }
-    ]
-  }
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/diets/food_effects/foraging/blinding.json b/src/main/resources/data/unicopia/diets/food_effects/foraging/blinding.json
deleted file mode 100644
index ca392e74..00000000
--- a/src/main/resources/data/unicopia/diets/food_effects/foraging/blinding.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
-  "tags": [ "unicopia:food_types/forage_blinding" ],
-  "food_component": {
-    "hunger": 2,
-    "saturation": 1
-  },
-  "ailment": {
-    "effects": [
-      {
-        "effect": "minecraft:blindness",
-        "seconds": 30,
-        "amplifier": 0
-      },
-      {
-        "effect": "unicopia:food_poisoning",
-        "seconds": 100,
-        "amplifier": 2
-      }
-    ]
-  }
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/diets/food_effects/foraging/dangerous.json b/src/main/resources/data/unicopia/diets/food_effects/foraging/dangerous.json
deleted file mode 100644
index 372abede..00000000
--- a/src/main/resources/data/unicopia/diets/food_effects/foraging/dangerous.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
-  "tags": [ "unicopia:food_types/forage_dangerous" ],
-  "food_component": {
-    "hunger": 2,
-    "saturation": 1
-  },
-  "ailment": {
-    "effects": [
-      {
-        "effect": "unicopia:food_poisoning",
-        "seconds": 250,
-        "amplifier": 2,
-        "chance": 4
-      }
-    ]
-  }
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/diets/food_effects/foraging/edible.json b/src/main/resources/data/unicopia/diets/food_effects/foraging/edible.json
deleted file mode 100644
index 33887410..00000000
--- a/src/main/resources/data/unicopia/diets/food_effects/foraging/edible.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-  "tags": [ "unicopia:food_types/forage_edible" ],
-  "food_component": {
-    "hunger": 2,
-    "saturation": 1
-  },
-  "ailment": {
-    "effects": []
-  }
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/diets/food_effects/foraging/edible_filling.json b/src/main/resources/data/unicopia/diets/food_effects/foraging/edible_filling.json
deleted file mode 100644
index b6721b3f..00000000
--- a/src/main/resources/data/unicopia/diets/food_effects/foraging/edible_filling.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-  "tags": [ "unicopia:food_types/forage_edible_filling" ],
-  "food_component": {
-    "hunger": 18,
-    "saturation": 9
-  },
-  "ailment": {
-    "effects": []
-  }
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/diets/food_effects/foraging/leafy_greens.json b/src/main/resources/data/unicopia/diets/food_effects/foraging/leafy_greens.json
deleted file mode 100644
index 0c81ee64..00000000
--- a/src/main/resources/data/unicopia/diets/food_effects/foraging/leafy_greens.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-  "tags": [ "minecraft:leaves" ],
-  "food_component": {
-    "hunger": 2,
-    "saturation": 1.5
-  },
-  "ailment": {
-    "effects": []
-  }
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/diets/food_effects/foraging/moderate.json b/src/main/resources/data/unicopia/diets/food_effects/foraging/moderate.json
deleted file mode 100644
index 4d7a238a..00000000
--- a/src/main/resources/data/unicopia/diets/food_effects/foraging/moderate.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
-  "tags": [ "unicopia:food_types/forage_moderate" ],
-  "food_component": {
-    "hunger": 2,
-    "saturation": 1
-  },
-  "ailment": {
-    "effects": [
-      {
-        "effect": "unicopia:food_poisoning",
-        "seconds": 100,
-        "amplifier": 2,
-        "chance": 40
-      }
-    ]
-  }
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/diets/food_effects/foraging/nauseating.json b/src/main/resources/data/unicopia/diets/food_effects/foraging/nauseating.json
deleted file mode 100644
index e79628a0..00000000
--- a/src/main/resources/data/unicopia/diets/food_effects/foraging/nauseating.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
-  "tags": [ "unicopia:food_types/forage_nauseating" ],
-  "food_component": {
-    "hunger": 2,
-    "saturation": 1
-  },
-  "ailment": {
-    "effects": [
-      {
-        "effect": "minecraft:weakness",
-        "seconds": 200,
-        "amplifier": 1,
-        "chance": 30
-      },
-      {
-        "effect": "unicopia:food_poisoning",
-        "seconds": 100,
-        "amplifier": 2
-      }
-    ]
-  }
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/diets/food_effects/foraging/prickly.json b/src/main/resources/data/unicopia/diets/food_effects/foraging/prickly.json
deleted file mode 100644
index d3c61180..00000000
--- a/src/main/resources/data/unicopia/diets/food_effects/foraging/prickly.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
-  "tags": [ "unicopia:food_types/forage_prickly" ],
-  "food_component": {
-    "hunger": 2,
-    "saturation": 1
-  },
-  "ailment": {
-    "effects": [
-      {
-        "effect": "minecraft:instant_damage",
-        "seconds": 1,
-        "amplifier": 0,
-        "chance": 30
-      }
-    ]
-  }
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/diets/food_effects/foraging/radioactive.json b/src/main/resources/data/unicopia/diets/food_effects/foraging/radioactive.json
deleted file mode 100644
index 7a023788..00000000
--- a/src/main/resources/data/unicopia/diets/food_effects/foraging/radioactive.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
-  "tags": [ "unicopia:food_types/forage_radioactive" ],
-  "food_component": {
-    "hunger": 2,
-    "saturation": 1
-  },
-  "ailment": {
-    "effects": [
-      {
-        "effect": "minecraft:glowing",
-        "seconds": 15,
-        "amplifier": 0,
-        "chance": 30
-      },
-      {
-        "effect": "unicopia:food_poisoning",
-        "seconds": 100,
-        "amplifier": 2
-      }
-    ]
-  }
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/diets/food_effects/foraging/risky.json b/src/main/resources/data/unicopia/diets/food_effects/foraging/risky.json
deleted file mode 100644
index 9ee5d1dc..00000000
--- a/src/main/resources/data/unicopia/diets/food_effects/foraging/risky.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
-  "tags": [ "unicopia:food_types/forage_risky" ],
-  "food_component": {
-    "hunger": 2,
-    "saturation": 1
-  },
-  "ailment": {
-    "effects": [
-      {
-        "effect": "unicopia:food_poisoning",
-        "seconds": 100,
-        "amplifier": 2,
-        "chance": 80
-      }
-    ]
-  }
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/diets/food_effects/foraging/severely_nauseating.json b/src/main/resources/data/unicopia/diets/food_effects/foraging/severely_nauseating.json
deleted file mode 100644
index 7f4ef36e..00000000
--- a/src/main/resources/data/unicopia/diets/food_effects/foraging/severely_nauseating.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
-  "tags": [ "unicopia:food_types/forage_severely_nauseating" ],
-  "food_component": {
-    "hunger": 2,
-    "saturation": 1
-  },
-  "ailment": {
-    "effects": [
-      {
-        "effect": "minecraft:weakness",
-        "seconds": 200,
-        "amplifier": 1
-      },
-      {
-        "effect": "unicopia:food_poisoning",
-        "seconds": 100,
-        "amplifier": 2
-      }
-    ]
-  }
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/diets/food_effects/foraging/severely_prickly.json b/src/main/resources/data/unicopia/diets/food_effects/foraging/severely_prickly.json
deleted file mode 100644
index 3b5a1cd6..00000000
--- a/src/main/resources/data/unicopia/diets/food_effects/foraging/severely_prickly.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
-  "tags": [ "unicopia:food_types/forage_severely_prickly" ],
-  "food_component": {
-    "hunger": 2,
-    "saturation": 1
-  },
-  "ailment": {
-    "effects": [
-      {
-        "effect": "minecraft:instant_damage",
-        "seconds": 1,
-        "amplifier": 0
-      },
-      {
-        "effect": "unicopia:food_poisoning",
-        "seconds": 100,
-        "amplifier": 2
-      }
-    ]
-  }
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/diets/food_effects/foraging/strengthening.json b/src/main/resources/data/unicopia/diets/food_effects/foraging/strengthening.json
deleted file mode 100644
index 11477833..00000000
--- a/src/main/resources/data/unicopia/diets/food_effects/foraging/strengthening.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
-  "tags": [ "unicopia:food_types/forage_strengthening" ],
-  "food_component": {
-    "hunger": 2,
-    "saturation": 1
-  },
-  "ailment": {
-    "effects": [
-      {
-        "effect": "minecraft:strength",
-        "seconds": 30,
-        "amplifier": 0
-      },
-      {
-        "effect": "unicopia:food_poisoning",
-        "seconds": 100,
-        "amplifier": 2,
-        "chance": 10
-      }
-    ]
-  }
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/diets/food_effects/fruit.json b/src/main/resources/data/unicopia/diets/food_effects/fruit.json
deleted file mode 100644
index 20793232..00000000
--- a/src/main/resources/data/unicopia/diets/food_effects/fruit.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-  "tags": [ "unicopia:food_types/fruit" ],
-  "food_component": {
-    "hunger": 1,
-    "saturation": 1
-  },
-  "ailment": {
-    "effects": [
-    ]
-  }
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/diets/food_effects/insect/cooked.json b/src/main/resources/data/unicopia/diets/food_effects/insect/cooked.json
deleted file mode 100644
index 9dbdc566..00000000
--- a/src/main/resources/data/unicopia/diets/food_effects/insect/cooked.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
-  "tags": [  "unicopia:food_types/cooked_insect" ],
-  "food_component": {
-    "hunger": 1,
-    "saturation": 0.1
-  },
-  "ailment": {
-    "effects": [
-      {
-        "effect": "unicopia:food_poisoning",
-        "seconds": 100,
-        "amplifier": 2
-      }
-    ]
-  }
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/diets/food_effects/insect/raw.json b/src/main/resources/data/unicopia/diets/food_effects/insect/raw.json
deleted file mode 100644
index 01a176d0..00000000
--- a/src/main/resources/data/unicopia/diets/food_effects/insect/raw.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
-  "tags": [ "unicopia:food_types/raw_insect" ],
-  "food_component": {
-    "hunger": 6,
-    "saturation": 0.3
-  },
-  "ailment": {
-    "effects": [
-      {
-        "effect": "unicopia:food_poisoning",
-        "seconds": 100,
-        "amplifier": 2
-      }
-    ]
-  }
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/diets/food_effects/meat/cooked.json b/src/main/resources/data/unicopia/diets/food_effects/meat/cooked.json
deleted file mode 100644
index 80b1e542..00000000
--- a/src/main/resources/data/unicopia/diets/food_effects/meat/cooked.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
-  "tags": [ "unicopia:food_types/cooked_meat" ],
-  "food_component": {
-    "hunger": 12,
-    "saturation": 1.2
-  },
-  "ailment": {
-    "effects": [
-      {
-        "effect": "unicopia:food_poisoning",
-        "seconds": 100,
-        "amplifier": 2
-      }
-    ]
-  }
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/diets/food_effects/meat/raw.json b/src/main/resources/data/unicopia/diets/food_effects/meat/raw.json
deleted file mode 100644
index f2c547d9..00000000
--- a/src/main/resources/data/unicopia/diets/food_effects/meat/raw.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
-  "tags": [ "unicopia:food_types/raw_meat" ],
-  "food_component": {
-    "hunger": 1,
-    "saturation": 1
-  },
-  "ailment": {
-    "effects": [
-      {
-        "effect": "minecraft:poison",
-        "seconds": 45,
-        "amplifier": 2,
-        "chance": 80
-      },
-      {
-        "effect": "unicopia:food_poisoning",
-        "seconds": 100,
-        "amplifier": 2,
-        "chance": 5
-      }
-    ]
-  }
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/diets/food_effects/meat/rotten.json b/src/main/resources/data/unicopia/diets/food_effects/meat/rotten.json
deleted file mode 100644
index 72faee0e..00000000
--- a/src/main/resources/data/unicopia/diets/food_effects/meat/rotten.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
-  "tags": [ "unicopia:food_types/rotten_meat" ],
-  "food_component": {
-    "hunger": 1,
-    "saturation": 1
-  },
-  "ailment": {
-    "effects": [
-      {
-        "effect": "minecraft:poison",
-        "seconds": 45,
-        "amplifier": 2,
-        "chance": 80
-      },
-      {
-        "effect": "unicopia:food_poisoning",
-        "seconds": 400,
-        "amplifier": 3,
-        "chance": 5
-      }
-    ]
-  }
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/diets/food_effects/nuts_and_seeds.json b/src/main/resources/data/unicopia/diets/food_effects/nuts_and_seeds.json
deleted file mode 100644
index 30f205a2..00000000
--- a/src/main/resources/data/unicopia/diets/food_effects/nuts_and_seeds.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-  "tags": [ "unicopia:food_types/nuts_and_seeds" ],
-  "food_component": {
-    "hunger": 2,
-    "saturation": 2.5
-  },
-  "ailment": {
-    "effects": [
-    ]
-  }
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/diets/food_effects/pinecone.json b/src/main/resources/data/unicopia/diets/food_effects/pinecone.json
deleted file mode 100644
index 75f92718..00000000
--- a/src/main/resources/data/unicopia/diets/food_effects/pinecone.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
-  "tags": [ "unicopia:food_types/pinecone" ],
-  "food_component": {
-    "hunger": 1,
-    "saturation": 0.1
-  },
-  "ailment": {
-    "effects": [
-      {
-        "type": "unicopia:healing",
-        "health": 1
-      }
-    ]
-  }
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/diets/food_effects/rocks.json b/src/main/resources/data/unicopia/diets/food_effects/rocks.json
deleted file mode 100644
index ebe7b986..00000000
--- a/src/main/resources/data/unicopia/diets/food_effects/rocks.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-  "tags": [ "unicopia:food_types/rocks" ],
-  "food_component": {
-    "hunger": 1,
-    "saturation": 0.1
-  },
-  "ailment": {
-    "effects": []
-  }
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/diets/races/alicorn.json b/src/main/resources/data/unicopia/diets/races/alicorn.json
deleted file mode 100644
index caf175c1..00000000
--- a/src/main/resources/data/unicopia/diets/races/alicorn.json
+++ /dev/null
@@ -1,64 +0,0 @@
-{
-  "default_multiplier": 1.4,
-  "foraging_multiplier": 0.9,
-  "multipliers": [
-    {
-      "tags": [ "unicopia:food_types/cooked_fish" ],
-      "hunger": 1.5,
-      "saturation": 1.5
-    },
-    {
-      "tags": [ "unicopia:food_types/raw_fish" ],
-      "hunger": 0.5,
-      "saturation": 0.6
-    },
-    {
-      "tags": [
-        "unicopia:food_types/baked_goods"
-      ],
-      "hunger": 1,
-      "saturation": 1
-    },
-    {
-      "tags": [
-        "unicopia:food_types/cooked_insect",
-        "unicopia:food_types/cooked_meat"
-      ],
-      "hunger": 0.1,
-      "saturation": 0.1
-    },
-    {
-      "tags": [
-        "unicopia:food_types/love",
-        "unicopia:food_types/raw_insect",
-        "unicopia:food_types/raw_meat",
-        "unicopia:food_types/rotten_meat"
-      ],
-      "hunger": 0,
-      "saturation": 0
-    },
-    {
-      "tags": [ "unicopia:food_types/pinecone" ],
-      "hunger": 0.9,
-      "saturation": 0.9
-    }
-  ],
-  "effects": [
-    {
-      "tags": [ "unicopia:food_types/cooked_fish" ],
-      "food_component": {
-        "hunger": 2,
-        "saturation": 1
-      },
-      "ailment": {
-        "effects": [ ]
-      }
-    },
-    {
-      "tags": [ "unicopia:food_types/raw_fish" ],
-      "ailment": {
-        "effects": [ ]
-      }
-    }
-  ]
-}
diff --git a/src/main/resources/data/unicopia/diets/races/bat.json b/src/main/resources/data/unicopia/diets/races/bat.json
deleted file mode 100644
index 283a8788..00000000
--- a/src/main/resources/data/unicopia/diets/races/bat.json
+++ /dev/null
@@ -1,130 +0,0 @@
-{
-  "default_multiplier": 0.6,
-  "foraging_multiplier": 0.9,
-  "multipliers": [
-    {
-      "tags": [ "unicopia:food_types/cooked_fish" ],
-      "hunger": 0.75,
-      "saturation": 0.75
-    },
-    {
-      "tags": [ "unicopia:food_types/raw_fish" ],
-      "hunger": 0.5,
-      "saturation": 0.6
-    },
-    {
-      "tags": [ "unicopia:food_types/cooked_insect" ],
-      "hunger": 1.75,
-      "saturation": 1.75
-    },
-    {
-      "tags": [ "unicopia:food_types/cooked_meat" ],
-      "hunger": 1.15,
-      "saturation": 1.15
-    },
-    {
-      "tags": [ "unicopia:food_types/raw_insect" ],
-      "hunger": 1,
-      "saturation": 1
-    },
-    {
-      "tags": [ "unicopia:food_types/raw_meat" ],
-      "hunger": 0.25,
-      "saturation": 0.25
-    },
-    {
-      "tags": [ "unicopia:food_types/rotten_meat" ],
-      "hunger": 0.2,
-      "saturation": 0.2
-    },
-    {
-      "tags": [ "unicopia:food_types/love" ],
-      "hunger": 0,
-      "saturation": 0
-    },
-    {
-      "tags": [ "unicopia:food_types/pinecone" ],
-      "hunger": 0.9,
-      "saturation": 0.9
-    }
-  ],
-  "effects": [
-    {
-      "tags": [ "unicopia:food_types/rotten_fish" ],
-      "ailment": {
-        "effects": [
-          {
-            "effect": "unicopia:food_poisoning",
-            "seconds": 100,
-            "amplifier": 2,
-            "chance": 5
-          }
-        ]
-      }
-    },
-    {
-      "tags": [
-        "unicopia:food_types/cooked_insect",
-        "unicopia:food_types/cooked_meat"
-      ],
-      "ailment": {
-        "effects": [ ]
-      }
-    },
-    {
-      "tags": [ "unicopia:food_types/raw_insect" ],
-      "ailment": {
-        "effects": [
-          {
-            "effect": "unicopia:food_poisoning",
-            "seconds": 50,
-            "amplifier": 1
-          }
-        ]
-      }
-    },
-    {
-      "tags": [
-        "unicopia:food_types/raw_meat",
-        "unicopia:food_types/rotten_meat"
-      ],
-      "ailment": {
-        "effects": [
-          {
-            "effect": "unicopia:food_poisoning",
-            "seconds": 100,
-            "amplifier": 2,
-            "chance": 5
-          }
-        ]
-      }
-    },
-    {
-      "tags": [ "unicopia:food_types/bat_ponys_delight" ],
-      "ailment": {
-        "effects": [
-          {
-            "effect": "minecraft:health_boost",
-            "seconds": { "min": 30, "max": 60 },
-            "amplifier": { "min": 2, "max": 6 }
-          },
-          {
-            "effect": "minecraft:jump_boost",
-            "seconds": { "min": 30, "max": 60 },
-            "amplifier": { "min": 1, "max": 6 }
-          },
-          {
-            "effect": "minecraft:health_boost",
-            "seconds": 30,
-            "amplifier": { "min": 1, "max": 6 }
-          },
-          {
-            "effect": "minecraft:regeneration",
-            "seconds": { "min": 3, "max": 30 },
-            "amplifier": { "min": 3, "max": 6 }
-          }
-        ]
-      }
-    }
-  ]
-}
diff --git a/src/main/resources/data/unicopia/diets/races/changeling.json b/src/main/resources/data/unicopia/diets/races/changeling.json
deleted file mode 100644
index c20c7753..00000000
--- a/src/main/resources/data/unicopia/diets/races/changeling.json
+++ /dev/null
@@ -1,159 +0,0 @@
-{
-  "default_multiplier": 0.15,
-  "foraging_multiplier": 0.1,
-  "multipliers": [
-    {
-      "tags": [ "unicopia:food_types/cooked_insect" ],
-      "hunger": 2.0,
-      "saturation": 1.3
-    },
-    {
-      "tags": [ "unicopia:food_types/cooked_meat" ],
-      "hunger": 1.9,
-      "saturation": 1.2
-    },
-    {
-      "tags": [ "unicopia:food_types/raw_insect" ],
-      "hunger": 1,
-      "saturation": 1
-    },
-    {
-      "tags": [ "unicopia:food_types/raw_meat" ],
-      "hunger": 1.25,
-      "saturation": 1.25
-    },
-    {
-      "tags": [ "unicopia:food_types/rotten_meat" ],
-      "hunger": 0.6,
-      "saturation": 0.6
-    },
-    {
-      "tags": [
-        "unicopia:food_types/baked_goods"
-      ],
-      "hunger": 0.5,
-      "saturation": 0.9
-    },
-    {
-      "tags": [ "unicopia:food_types/love" ],
-      "hunger": 5,
-      "saturation": 3
-    }
-  ],
-  "default_effects": {
-    "effects": [
-      {
-        "effect": "unicopia:food_poisoning",
-        "seconds": 100,
-        "amplifier": 2
-      },
-      {
-        "effect": "minecraft:weakness",
-        "seconds": 200,
-        "amplifier": 1
-      },
-      {
-        "type": "unicopia:lose_hunger",
-        "multiplier": 0.5
-      }
-    ]
-  },
-  "effects": [
-    {
-      "tags": [ "unicopia:food_types/love" ],
-      "food_component": {
-        "hunger": 2,
-        "saturation": 1
-      },
-      "ailment": {
-        "effects": [
-          {
-            "name": "Love Consumption",
-            "type": "unicopia:cure_love_sickness"
-          }
-        ]
-      }
-    },
-    {
-      "tags": [
-        "unicopia:food_types/raw_insect"
-      ],
-      "food_component": {
-        "hunger": 3,
-        "saturation": 2
-      },
-      "ailment": {
-        "effects": [ ]
-      }
-    },
-    {
-      "tags": [
-        "unicopia:food_types/cooked_fish",
-        "unicopia:food_types/raw_fish"
-      ],
-      "ailment": {
-        "effects": [
-          {
-            "effect": "unicopia:food_poisoning",
-            "seconds": 50,
-            "amplifier": 2
-          },
-          {
-            "name": "unicopia.affliction.love_sickness",
-            "type": "unicopia:lose_hunger",
-            "multiplier": 0.5
-          }
-        ]
-      }
-    },
-    {
-      "tags": [
-        "unicopia:food_types/rotten_fish",
-        "unicopia:food_types/cooked_insect",
-        "unicopia:food_types/cooked_meat",
-        "unicopia:food_types/raw_meat",
-        "unicopia:food_types/rotten_meat"
-      ],
-      "food_component": {
-        "hunger": 6,
-        "saturation": 9
-      },
-      "ailment": {
-        "effects": [
-          {
-            "name": "Love Consumption",
-            "type": "unicopia:cure_love_sickness"
-          }
-        ]
-      }
-    },
-    {
-      "tags": [
-        "unicopia:food_types/forage_edible",
-        "unicopia:food_types/forage_edible_filling"
-      ],
-      "food_component": {
-        "hunger": 18,
-        "saturation": 9
-      },
-      "ailment": {
-        "effects": [
-          {
-            "effect": "unicopia:food_poisoning",
-            "seconds": 10,
-            "amplifier": 2
-          },
-          {
-            "effect": "minecraft:weakness",
-            "seconds": 2,
-            "amplifier": 1
-          },
-          {
-            "type": "unicopia:lose_hunger",
-            "multiplier": 0.5
-          }
-        ]
-      }
-    }
-  ]
-}
diff --git a/src/main/resources/data/unicopia/diets/races/earth.json b/src/main/resources/data/unicopia/diets/races/earth.json
deleted file mode 100644
index e06a0fd5..00000000
--- a/src/main/resources/data/unicopia/diets/races/earth.json
+++ /dev/null
@@ -1,81 +0,0 @@
-{
-  "default_multiplier": 0.7,
-  "foraging_multiplier": 1,
-  "multipliers": [
-    {
-      "tags": [
-        "unicopia:food_types/candy",
-        "unicopia:food_types/desserts",
-        "unicopia:food_types/rocks"
-      ],
-      "hunger": 2.5,
-      "saturation": 1.7
-    },
-    {
-      "tags": [
-        "unicopia:food_types/baked_goods"
-      ],
-      "hunger": 1.2,
-      "saturation": 2
-    },
-    {
-      "tags": [ "unicopia:food_types/cooked_fish" ],
-      "hunger": 0.2,
-      "saturation": 0.2
-    },
-    {
-      "tags": [
-        "unicopia:food_types/cooked_insect",
-        "unicopia:food_types/cooked_meat"
-      ],
-      "hunger": 0.1,
-      "saturation": 0.1
-    },
-    {
-      "tags": [
-        "unicopia:food_types/love",
-        "unicopia:food_types/raw_fish",
-        "unicopia:food_types/raw_insect",
-        "unicopia:food_types/raw_meat",
-        "unicopia:food_types/rotten_meat"
-      ],
-      "hunger": 0,
-      "saturation": 0
-    },
-    {
-      "tags": [ "unicopia:food_types/pinecone" ],
-      "hunger": 1,
-      "saturation": 1
-    }
-  ],
-  "effects": [
-    {
-      "tags": [
-        "unicopia:food_types/candy",
-        "unicopia:food_types/rocks"
-      ],
-      "food_component": {
-        "hunger": 5,
-        "saturation": 12,
-        "fastFood": true
-      },
-      "ailment": {
-        "effects": [ ]
-      }
-    },
-    {
-      "tags": [
-        "unicopia:food_types/desserts"
-      ],
-      "food_component": {
-        "hunger": 12,
-        "saturation": 32,
-        "eatenQuickly": true,
-        "fastFood": true
-      },
-      "ailment": {
-        "effects": [ ]
-      }
-    }
-  ]
-}
diff --git a/src/main/resources/data/unicopia/diets/races/hippogriff.json b/src/main/resources/data/unicopia/diets/races/hippogriff.json
deleted file mode 100644
index c91d791e..00000000
--- a/src/main/resources/data/unicopia/diets/races/hippogriff.json
+++ /dev/null
@@ -1,97 +0,0 @@
-{
-  "default_multiplier": 0.5,
-  "foraging_multiplier": 0.8,
-  "multipliers": [
-    {
-      "tags": [
-        "unicopia:food_types/cooked_meat",
-        "unicopia:food_types/cooked_fish"
-       ],
-      "hunger": 1.6,
-      "saturation": 1.6
-    },
-    {
-      "tags": [
-        "unicopia:food_types/nuts_and_seeds"
-       ],
-      "hunger": 1.4,
-      "saturation": 1.4
-    },
-    {
-      "tags": [
-        "unicopia:food_types/baked_goods"
-      ],
-      "hunger": 1,
-      "saturation": 1
-    },
-    {
-      "tags": [
-        "unicopia:food_types/raw_meat",
-        "unicopia:food_types/raw_fish"
-      ],
-      "hunger": 0.6,
-      "saturation": 0.6
-    },
-    {
-      "tags": [ "unicopia:food_types/rotten_meat" ],
-      "hunger": 0.3,
-      "saturation": 0.3
-    },
-    {
-      "tags": [
-        "unicopia:food_types/love",
-        "unicopia:food_types/raw_insect",
-        "unicopia:food_types/cooked_insect"
-      ],
-      "hunger": 0,
-      "saturation": 0
-    },
-    {
-      "tags": [ "unicopia:food_types/pinecone" ],
-      "hunger": 1,
-      "saturation": 1
-    }
-  ],
-  "effects": [
-    {
-      "tags": [ "unicopia:food_types/cooked_fish" ],
-      "food_component": {
-        "hunger": 2,
-        "saturation": 1
-      },
-      "ailment": {
-        "effects": [ ]
-      }
-    },
-    {
-      "tags": [ "unicopia:food_types/raw_fish" ],
-      "ailment": {
-        "effects": [ ]
-      }
-    },
-    {
-      "tags": [
-        "unicopia:food_types/forage_prickly",
-        "unicopia:food_types/forage_severely_prickly"
-      ],
-      "food_component": {
-        "hunger": 2,
-        "saturation": 1
-      },
-      "ailment": {
-        "effects": [ ]
-      }
-    },
-    {
-      "tags": [ "unicopia:food_types/pinecone" ],
-      "ailment": {
-        "effects": [
-          {
-            "type": "unicopia:healing",
-            "health": 3
-          }
-        ]
-      }
-    }
-  ]
-}
diff --git a/src/main/resources/data/unicopia/diets/races/human.json b/src/main/resources/data/unicopia/diets/races/human.json
deleted file mode 100644
index ddf024b3..00000000
--- a/src/main/resources/data/unicopia/diets/races/human.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
-  "default_multiplier": 1,
-  "foraging_multiplier": 0,
-  "multipliers": [ ],
-  "effects": [
-    {
-      "tags": [
-        "unicopia:food_types/cooked_fish",
-        "unicopia:food_types/raw_fish",
-        "unicopia:food_types/rotten_fish",
-        "unicopia:food_types/cooked_meat",
-        "unicopia:food_types/raw_meat",
-        "unicopia:food_types/rotten_meat",
-        "unicopia:food_types/pinecone"
-      ],
-      "ailment": {
-        "effects": [ ]
-      }
-    }
-  ]
-}
diff --git a/src/main/resources/data/unicopia/diets/races/kirin.json b/src/main/resources/data/unicopia/diets/races/kirin.json
deleted file mode 100644
index 42b41a67..00000000
--- a/src/main/resources/data/unicopia/diets/races/kirin.json
+++ /dev/null
@@ -1,68 +0,0 @@
-{
-  "default_multiplier": 0.25,
-  "foraging_multiplier": 0.9,
-  "multipliers": [
-    {
-      "tags": [ "unicopia:food_types/cooked_meat" ],
-      "hunger": 1.5,
-      "saturation": 1.5
-    },
-    {
-      "tags": [ "unicopia:food_types/raw_meat" ],
-      "hunger": 0.5,
-      "saturation": 0.6
-    },
-    {
-      "tags": [
-        "unicopia:food_types/baked_goods"
-      ],
-      "hunger": 1,
-      "saturation": 1
-    },
-    {
-      "tags": [
-        "unicopia:food_types/cooked_insect",
-        "unicopia:food_types/cooked_fish"
-      ],
-      "hunger": 0.1,
-      "saturation": 0.1
-    },
-    {
-      "tags": [
-        "unicopia:food_types/love",
-        "unicopia:food_types/raw_insect",
-        "unicopia:food_types/raw_fish",
-        "unicopia:food_types/rotten_meat"
-      ],
-      "hunger": 0,
-      "saturation": 0
-    },
-    {
-      "tags": [ "unicopia:food_types/pinecone" ],
-      "hunger": 0.9,
-      "saturation": 0.9
-    }
-  ],
-  "effects": [
-    {
-      "tags": [
-        "unicopia:food_types/rotten_fish",
-        "unicopia:food_types/cooked_insect",
-        "unicopia:food_types/cooked_meat",
-        "unicopia:food_types/raw_meat",
-        "unicopia:food_types/rotten_meat",
-        "unicopia:food_types/forage_blinding",
-        "unicopia:food_types/forage_prickly",
-        "unicopia:food_types/forage_severely_prickly",
-        "unicopia:food_types/forage_strengthening"
-      ],
-      "food_component": {
-        "hunger": 2,
-        "saturation": 1
-      },
-      "ailment": {
-        "effects": [ ]
-      }
-    }
-  ]
-}
diff --git a/src/main/resources/data/unicopia/diets/races/pegasus.json b/src/main/resources/data/unicopia/diets/races/pegasus.json
deleted file mode 100644
index d1208202..00000000
--- a/src/main/resources/data/unicopia/diets/races/pegasus.json
+++ /dev/null
@@ -1,66 +0,0 @@
-{
-  "default_multiplier": 0.9,
-  "foraging_multiplier": 1,
-  "multipliers": [
-    {
-      "tags": [ "unicopia:food_types/cooked_fish" ],
-      "hunger": 1.5,
-      "saturation": 1.5
-    },
-    {
-      "tags": [ "unicopia:food_types/raw_fish" ],
-      "hunger": 0.5,
-      "saturation": 0.6
-    },
-    {
-      "tags": [
-        "unicopia:food_types/baked_goods"
-      ],
-      "hunger": 1,
-      "saturation": 1
-    },
-    {
-      "tags": [
-        "unicopia:food_types/cooked_insect",
-        "unicopia:food_types/cooked_meat"
-      ],
-      "hunger": 0.1,
-      "saturation": 0.1
-    },
-    {
-      "tags": [
-        "unicopia:food_types/love",
-        "unicopia:food_types/raw_insect",
-        "unicopia:food_types/raw_meat",
-        "unicopia:food_types/rotten_meat"
-      ],
-      "hunger": 0,
-      "saturation": 0
-    },
-    {
-      "tags": [ "unicopia:food_types/pinecone" ],
-      "hunger": 0.9,
-      "saturation": 0.9
-    }
-  ],
-  "effects": [
-    {
-      "tags": [ "unicopia:food_types/cooked_fish" ],
-      "ailment": {
-        "effects": [ ]
-      }
-    },
-    {
-      "tags": [ "unicopia:food_types/raw_fish" ],
-      "ailment": {
-        "effects": [
-          {
-            "effect": "unicopia:food_poisoning",
-            "seconds": 50,
-            "amplifier": 2
-          }
-        ]
-      }
-    }
-  ]
-}
diff --git a/src/main/resources/data/unicopia/diets/races/seapony.json b/src/main/resources/data/unicopia/diets/races/seapony.json
deleted file mode 100644
index 6558338a..00000000
--- a/src/main/resources/data/unicopia/diets/races/seapony.json
+++ /dev/null
@@ -1,101 +0,0 @@
-{
-  "default_multiplier": 0.4,
-  "foraging_multiplier": 0.7,
-  "multipliers": [
-    {
-      "tags": [ "unicopia:food_types/raw_sea_vegitable" ],
-      "hunger": 1,
-      "saturation": 1
-    },
-    {
-      "tags": [
-        "unicopia:food_types/shells",
-        "unicopia:food_types/shelly"
-      ],
-      "hunger": 1,
-      "saturation": 1
-    }
-  ],
-  "default_effects": {
-    "effects": [
-      {
-        "effect": "unicopia:food_poisoning",
-        "seconds": 100,
-        "amplifier": 2
-      }
-    ]
-  },
-  "effects": [
-    {
-      "tags": [ "unicopia:food_types/cooked_fish" ],
-      "ailment": {
-        "effects": [ ]
-      }
-    },
-    {
-      "tags": [ "unicopia:food_types/raw_fish" ],
-      "ailment": {
-        "effects": [ ]
-      }
-    },
-    {
-      "tags": [
-        "unicopia:food_types/forage_edible",
-        "unicopia:food_types/forage_edible_filling"
-      ],
-      "food_component": {
-        "hunger": 18,
-        "saturation": 9
-      },
-      "ailment": {
-        "effects": [
-          {
-            "effect": "unicopia:food_poisoning",
-            "seconds": 100,
-            "amplifier": 2
-          }
-        ]
-      }
-    },
-    {
-      "tags": [ "unicopia:food_types/raw_sea_vegitable" ],
-      "food_component": {
-        "hunger": 2,
-        "saturation": 1
-      },
-      "ailment": {
-        "effects": [ ]
-      }
-    },
-    {
-      "tags": [ "unicopia:food_types/cooked_sea_vegitable" ],
-      "food_component": {
-        "hunger": 6,
-        "saturation": 2
-      },
-      "ailment": {
-        "effects": [ ]
-      }
-    },
-    {
-      "tags": [ "unicopia:food_types/shells" ],
-      "food_component": {
-        "hunger": 3,
-        "saturation": 5
-      },
-      "ailment": {
-        "effects": [ ]
-      }
-    },
-    {
-      "tags": [ "unicopia:food_types/shelly" ],
-      "food_component": {
-        "hunger": 6,
-        "saturation": 7
-      },
-      "ailment": {
-        "effects": [ ]
-      }
-    }
-  ]
-}
diff --git a/src/main/resources/data/unicopia/diets/races/unicorn.json b/src/main/resources/data/unicopia/diets/races/unicorn.json
deleted file mode 100644
index be679a08..00000000
--- a/src/main/resources/data/unicopia/diets/races/unicorn.json
+++ /dev/null
@@ -1,39 +0,0 @@
-{
-  "default_multiplier": 1.2,
-  "foraging_multiplier": 1,
-  "multipliers": [
-    {
-      "tags": [
-        "unicopia:food_types/cooked_insect",
-        "unicopia:food_types/cooked_meat",
-        "unicopia:food_types/cooked_fish"
-      ],
-      "hunger": 0.1,
-      "saturation": 0.1
-    },
-    {
-      "tags": [
-        "unicopia:food_types/baked_goods"
-      ],
-      "hunger": 1,
-      "saturation": 1
-    },
-    {
-      "tags": [
-        "unicopia:food_types/love",
-        "unicopia:food_types/raw_insect",
-        "unicopia:food_types/raw_meat",
-        "unicopia:food_types/raw_fish",
-        "unicopia:food_types/rotten_meat"
-      ],
-      "hunger": 0,
-      "saturation": 0
-    },
-    {
-      "tags": [ "unicopia:food_types/pinecone" ],
-      "hunger": 0.9,
-      "saturation": 0.9
-    }
-  ],
-  "effects": []
-}
diff --git a/src/main/resources/data/unicopia/loot_tables/blocks/apple_pie.json b/src/main/resources/data/unicopia/loot_tables/blocks/apple_pie.json
deleted file mode 100644
index 263cdd20..00000000
--- a/src/main/resources/data/unicopia/loot_tables/blocks/apple_pie.json
+++ /dev/null
@@ -1,47 +0,0 @@
-{
-  "type": "minecraft:block",
-  "functions": [
-    {
-      "function": "minecraft:explosion_decay"
-    }
-  ],
-  "pools": [
-    {
-      "bonus_rolls": 0.0,
-      "conditions": [
-        {
-          "condition": "minecraft:all_of",
-          "terms": [
-            {
-              "block": "unicopia:apple_pie",
-              "condition": "minecraft:block_state_property",
-              "properties": {
-                "stomped": true
-              }
-            },
-            {
-              "condition": "minecraft:match_tool",
-              "predicate": {
-                "enchantments": [
-                  {
-                    "enchantment": "minecraft:silk_touch",
-                    "levels": {
-                      "min": 1
-                    }
-                  }
-                ]
-              }
-            }
-          ]
-        }
-      ],
-      "entries": [
-        {
-          "type": "minecraft:item",
-          "name": "unicopia:apple_pie_hoof"
-        }
-      ],
-      "rolls": 1.0
-    }
-  ]
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/loot_tables/blocks/bananas.json b/src/main/resources/data/unicopia/loot_tables/blocks/bananas.json
deleted file mode 100644
index 7e5ce591..00000000
--- a/src/main/resources/data/unicopia/loot_tables/blocks/bananas.json
+++ /dev/null
@@ -1,40 +0,0 @@
-{
-  "type": "minecraft:block",
-  "pools": [
-    {
-      "rolls": 1.0,
-      "bonus_rolls": 0.0,
-      "entries": [
-        {
-          "type": "minecraft:item",
-          "functions": [
-            {
-              "add": false,
-              "count": {
-                "type": "minecraft:uniform",
-                "max": 12.0,
-                "min": 6.0
-              },
-              "function": "minecraft:set_count"
-            },
-            {
-              "enchantment": "minecraft:fortune",
-              "formula": "minecraft:binomial_with_bonus_count",
-              "function": "minecraft:apply_bonus",
-              "parameters": {
-                "extra": 3,
-                "probability": 0.5714286
-              }
-            }
-          ],
-          "name": "unicopia:banana"
-        }
-      ],
-      "conditions": [
-        {
-          "condition": "minecraft:survives_explosion"
-        }
-      ]
-    }
-  ]
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/loot_tables/blocks/chiselled_chitin_hull.json b/src/main/resources/data/unicopia/loot_tables/blocks/chiselled_chitin_hull.json
deleted file mode 100644
index 5af0f74d..00000000
--- a/src/main/resources/data/unicopia/loot_tables/blocks/chiselled_chitin_hull.json
+++ /dev/null
@@ -1,49 +0,0 @@
-{
-  "type": "minecraft:block",
-  "pools": [
-    {
-      "rolls": 1.0,
-      "bonus_rolls": 0.0,
-      "entries": [
-        {
-          "type": "minecraft:item",
-          "name": "unicopia:chitin",
-          "functions": [
-            {
-              "add": false,
-              "count": 2,
-              "function": "minecraft:set_count"
-            }
-          ]
-        }
-      ],
-      "conditions": [
-        {
-          "condition": "minecraft:survives_explosion"
-        }
-      ]
-    },
-    {
-      "rolls": 1.0,
-      "bonus_rolls": 0.0,
-      "entries": [
-        {
-          "type": "minecraft:item",
-          "name": "unicopia:chiselled_chitin",
-          "functions": [
-            {
-              "add": false,
-              "count": 2,
-              "function": "minecraft:set_count"
-            }
-          ]
-        }
-      ],
-      "conditions": [
-        {
-          "condition": "minecraft:survives_explosion"
-        }
-      ]
-    }
-  ]
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/loot_tables/blocks/clam_shell.json b/src/main/resources/data/unicopia/loot_tables/blocks/clam_shell.json
deleted file mode 100644
index f21c580e..00000000
--- a/src/main/resources/data/unicopia/loot_tables/blocks/clam_shell.json
+++ /dev/null
@@ -1,96 +0,0 @@
-{
-  "type": "minecraft:block",
-  "pools": [
-    {
-      "rolls": 1.0,
-      "bonus_rolls": 0.0,
-      "entries": [
-        {
-          "type": "minecraft:item",
-          "name": "unicopia:clam_shell",
-          "conditions": [
-            {
-              "block": "unicopia:clam_shell",
-              "condition": "minecraft:block_state_property",
-              "properties": {
-                "count": "1"
-              }
-            }
-          ],
-          "functions": [
-            {
-              "add": false,
-              "count": 1,
-              "function": "minecraft:set_count"
-            }
-          ]
-        },
-        {
-          "type": "minecraft:item",
-          "name": "unicopia:clam_shell",
-          "conditions": [
-            {
-              "block": "unicopia:clam_shell",
-              "condition": "minecraft:block_state_property",
-              "properties": {
-                "count": "2"
-              }
-            }
-          ],
-          "functions": [
-            {
-              "add": false,
-              "count": 2,
-              "function": "minecraft:set_count"
-            }
-          ]
-        },
-        {
-          "type": "minecraft:item",
-          "name": "unicopia:clam_shell",
-          "conditions": [
-            {
-              "block": "unicopia:clam_shell",
-              "condition": "minecraft:block_state_property",
-              "properties": {
-                "count": "3"
-              }
-            }
-          ],
-          "functions": [
-            {
-              "add": false,
-              "count": 3,
-              "function": "minecraft:set_count"
-            }
-          ]
-        },
-        {
-          "type": "minecraft:item",
-          "name": "unicopia:clam_shell",
-          "conditions": [
-            {
-              "block": "unicopia:clam_shell",
-              "condition": "minecraft:block_state_property",
-              "properties": {
-                "count": "4"
-              }
-            }
-          ],
-          "functions": [
-            {
-              "add": false,
-              "count": 4,
-              "function": "minecraft:set_count"
-            }
-          ]
-        }
-      ],
-      "conditions": [
-        {
-          "condition": "minecraft:survives_explosion"
-        }
-      ]
-    }
-  ]
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/loot_tables/blocks/cloud_slab.json b/src/main/resources/data/unicopia/loot_tables/blocks/cloud_slab.json
deleted file mode 100644
index 6926e7fe..00000000
--- a/src/main/resources/data/unicopia/loot_tables/blocks/cloud_slab.json
+++ /dev/null
@@ -1,41 +0,0 @@
-{
-  "type": "minecraft:block",
-  "pools": [
-    {
-      "rolls": 1.0,
-      "bonus_rolls": 0.0,
-      "entries": [
-        {
-          "type": "minecraft:item",
-          "name": "unicopia:cloud_lump",
-          "functions": [
-            {
-              "add": false,
-              "count": 2,
-              "function": "minecraft:set_count"
-            },
-            {
-              "add": false,
-              "count": 4,
-              "function": "minecraft:set_count",
-              "conditions": [
-                {
-                  "block": "unicopia:cloud_slab",
-                  "condition": "minecraft:block_state_property",
-                  "properties": {
-                    "type": "double"
-                  }
-                }
-              ]
-            }
-          ]
-        }
-      ],
-      "conditions": [
-        {
-          "condition": "minecraft:survives_explosion"
-        }
-      ]
-    }
-  ]
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/loot_tables/blocks/dense_cloud_slab.json b/src/main/resources/data/unicopia/loot_tables/blocks/dense_cloud_slab.json
deleted file mode 100644
index e9d1f0e2..00000000
--- a/src/main/resources/data/unicopia/loot_tables/blocks/dense_cloud_slab.json
+++ /dev/null
@@ -1,41 +0,0 @@
-{
-  "type": "minecraft:block",
-  "pools": [
-    {
-      "rolls": 1.0,
-      "bonus_rolls": 0.0,
-      "entries": [
-        {
-          "type": "minecraft:item",
-          "name": "unicopia:cloud_lump",
-          "functions": [
-            {
-              "add": false,
-              "count": 4,
-              "function": "minecraft:set_count"
-            },
-            {
-              "add": false,
-              "count": 8,
-              "function": "minecraft:set_count",
-              "conditions": [
-                {
-                  "block": "unicopia:dense_cloud_slab",
-                  "condition": "minecraft:block_state_property",
-                  "properties": {
-                    "type": "double"
-                  }
-                }
-              ]
-            }
-          ]
-        }
-      ],
-      "conditions": [
-        {
-          "condition": "minecraft:survives_explosion"
-        }
-      ]
-    }
-  ]
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/loot_tables/blocks/etched_cloud_slab.json b/src/main/resources/data/unicopia/loot_tables/blocks/etched_cloud_slab.json
deleted file mode 100644
index 4465e094..00000000
--- a/src/main/resources/data/unicopia/loot_tables/blocks/etched_cloud_slab.json
+++ /dev/null
@@ -1,41 +0,0 @@
-{
-  "type": "minecraft:block",
-  "pools": [
-    {
-      "rolls": 1.0,
-      "bonus_rolls": 0.0,
-      "entries": [
-        {
-          "type": "minecraft:item",
-          "name": "unicopia:cloud_lump",
-          "functions": [
-            {
-              "add": false,
-              "count": 4,
-              "function": "minecraft:set_count"
-            },
-            {
-              "add": false,
-              "count": 8,
-              "function": "minecraft:set_count",
-              "conditions": [
-                {
-                  "block": "unicopia:etched_cloud_slab",
-                  "condition": "minecraft:block_state_property",
-                  "properties": {
-                    "type": "double"
-                  }
-                }
-              ]
-            }
-          ]
-        }
-      ],
-      "conditions": [
-        {
-          "condition": "minecraft:survives_explosion"
-        }
-      ]
-    }
-  ]
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/loot_tables/blocks/gold_root.json b/src/main/resources/data/unicopia/loot_tables/blocks/gold_root.json
deleted file mode 100644
index 6bfe9e77..00000000
--- a/src/main/resources/data/unicopia/loot_tables/blocks/gold_root.json
+++ /dev/null
@@ -1,51 +0,0 @@
-{
-  "type": "minecraft:block",
-  "functions": [
-    {
-      "function": "minecraft:explosion_decay"
-    }
-  ],
-  "pools": [
-    {
-      "bonus_rolls": 0.0,
-      "entries": [
-        {
-          "type": "minecraft:item",
-          "name": "minecraft:golden_carrot"
-        }
-      ],
-      "rolls": 1.0
-    },
-    {
-      "bonus_rolls": 0.0,
-      "conditions": [
-        {
-          "block": "unicopia:gold_root",
-          "condition": "minecraft:block_state_property",
-          "properties": {
-            "age": "7"
-          }
-        }
-      ],
-      "entries": [
-        {
-          "type": "minecraft:item",
-          "functions": [
-            {
-              "enchantment": "minecraft:fortune",
-              "formula": "minecraft:binomial_with_bonus_count",
-              "function": "minecraft:apply_bonus",
-              "parameters": {
-                "extra": 3,
-                "probability": 0.5714286
-              }
-            }
-          ],
-          "name": "minecraft:golden_carrot"
-        }
-      ],
-      "rolls": 1.0
-    }
-  ],
-  "random_sequence": "minecraft:blocks/carrots"
-}
diff --git a/src/main/resources/data/unicopia/loot_tables/blocks/golden_apple.json b/src/main/resources/data/unicopia/loot_tables/blocks/golden_apple.json
deleted file mode 100644
index 7bd87a25..00000000
--- a/src/main/resources/data/unicopia/loot_tables/blocks/golden_apple.json
+++ /dev/null
@@ -1,49 +0,0 @@
-{
-  "type": "minecraft:block",
-  "pools": [
-    {
-      "rolls": 1.0,
-      "bonus_rolls": 0.0,
-      "entries": [
-        {
-          "type": "minecraft:item",
-          "name": "minecraft:golden_apple"
-        }
-      ],
-      "conditions": [
-        {
-          "condition": "minecraft:survives_explosion"
-        },
-        {
-          "block": "unicopia:golden_apple",
-          "condition": "minecraft:block_state_property",
-          "properties": {
-            "enchanted": "false"
-          }
-        }
-      ]
-    },
-    {
-      "rolls": 1.0,
-      "bonus_rolls": 0.0,
-      "entries": [
-        {
-          "type": "minecraft:item",
-          "name": "minecraft:enchanted_golden_apple"
-        }
-      ],
-      "conditions": [
-        {
-          "condition": "minecraft:survives_explosion"
-        },
-        {
-          "block": "unicopia:golden_apple",
-          "condition": "minecraft:block_state_property",
-          "properties": {
-            "enchanted": "true"
-          }
-        }
-      ]
-    }
-  ]
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/loot_tables/blocks/hay_block.json b/src/main/resources/data/unicopia/loot_tables/blocks/hay_block.json
deleted file mode 100644
index 1101857f..00000000
--- a/src/main/resources/data/unicopia/loot_tables/blocks/hay_block.json
+++ /dev/null
@@ -1,157 +0,0 @@
-{
-  "type": "minecraft:block",
-  "pools": [
-    {
-      "bonus_rolls": 0.0,
-      "conditions": [
-        {
-          "block": "unicopia:hay_block",
-          "condition": "minecraft:block_state_property",
-          "properties": {
-            "top_north_east": "true"
-          }
-        }
-      ],
-      "entries": [
-        {
-          "type": "minecraft:item",
-          "name": "minecraft:wheat"
-        }
-      ],
-      "rolls": 1.0
-    },
-    {
-      "bonus_rolls": 0.0,
-      "conditions": [
-        {
-          "block": "unicopia:hay_block",
-          "condition": "minecraft:block_state_property",
-          "properties": {
-            "top_north_west": "true"
-          }
-        }
-      ],
-      "entries": [
-        {
-          "type": "minecraft:item",
-          "name": "minecraft:wheat"
-        }
-      ],
-      "rolls": 1.0
-    },
-    {
-      "bonus_rolls": 0.0,
-      "conditions": [
-        {
-          "block": "unicopia:hay_block",
-          "condition": "minecraft:block_state_property",
-          "properties": {
-            "top_south_east": "true"
-          }
-        }
-      ],
-      "entries": [
-        {
-          "type": "minecraft:item",
-          "name": "minecraft:wheat"
-        }
-      ],
-      "rolls": 1.0
-    },
-    {
-      "bonus_rolls": 0.0,
-      "conditions": [
-        {
-          "block": "unicopia:hay_block",
-          "condition": "minecraft:block_state_property",
-          "properties": {
-            "top_south_west": "true"
-          }
-        }
-      ],
-      "entries": [
-        {
-          "type": "minecraft:item",
-          "name": "minecraft:wheat"
-        }
-      ],
-      "rolls": 1.0
-    },
-    {
-      "bonus_rolls": 0.0,
-      "conditions": [
-        {
-          "block": "unicopia:hay_block",
-          "condition": "minecraft:block_state_property",
-          "properties": {
-            "bottom_north_east": "true"
-          }
-        }
-      ],
-      "entries": [
-        {
-          "type": "minecraft:item",
-          "name": "minecraft:wheat"
-        }
-      ],
-      "rolls": 1.0
-    },
-    {
-      "bonus_rolls": 0.0,
-      "conditions": [
-        {
-          "block": "unicopia:hay_block",
-          "condition": "minecraft:block_state_property",
-          "properties": {
-            "bottom_north_west": "true"
-          }
-        }
-      ],
-      "entries": [
-        {
-          "type": "minecraft:item",
-          "name": "minecraft:wheat"
-        }
-      ],
-      "rolls": 1.0
-    },
-    {
-      "bonus_rolls": 0.0,
-      "conditions": [
-        {
-          "block": "unicopia:hay_block",
-          "condition": "minecraft:block_state_property",
-          "properties": {
-            "bottom_south_east": "true"
-          }
-        }
-      ],
-      "entries": [
-        {
-          "type": "minecraft:item",
-          "name": "minecraft:wheat"
-        }
-      ],
-      "rolls": 1.0
-    },
-    {
-      "bonus_rolls": 0.0,
-      "conditions": [
-        {
-          "block": "unicopia:hay_block",
-          "condition": "minecraft:block_state_property",
-          "properties": {
-            "bottom_south_west": "true"
-          }
-        }
-      ],
-      "entries": [
-        {
-          "type": "minecraft:item",
-          "name": "minecraft:wheat"
-        }
-      ],
-      "rolls": 1.0
-    }
-  ]
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/loot_tables/blocks/mysterious_egg.json b/src/main/resources/data/unicopia/loot_tables/blocks/mysterious_egg.json
deleted file mode 100644
index 915f5152..00000000
--- a/src/main/resources/data/unicopia/loot_tables/blocks/mysterious_egg.json
+++ /dev/null
@@ -1,64 +0,0 @@
-{
-  "type": "minecraft:block",
-  "pools": [
-    {
-      "rolls": 1.0,
-      "bonus_rolls": 0.0,
-      "entries": [
-        {
-          "type": "minecraft:item",
-          "name": "unicopia:mysterious_egg",
-          "functions": [
-            {
-              "add": false,
-              "count": 1,
-              "function": "minecraft:set_count",
-              "conditions": [
-                {
-                  "block": "unicopia:mysterious_egg",
-                  "condition": "minecraft:block_state_property",
-                  "properties": {
-                    "count": "1"
-                  }
-                }
-              ]
-            },
-            {
-              "add": false,
-              "count": 2,
-              "function": "minecraft:set_count",
-              "conditions": [
-                {
-                  "block": "unicopia:mysterious_egg",
-                  "condition": "minecraft:block_state_property",
-                  "properties": {
-                    "count": "2"
-                  }
-                }
-              ]
-            },
-            {
-              "add": false,
-              "count": 3,
-              "function": "minecraft:set_count",
-              "conditions": [
-                {
-                  "block": "unicopia:mysterious_egg",
-                  "condition": "minecraft:block_state_property",
-                  "properties": {
-                    "count": "3"
-                  }
-                }
-              ]
-            }
-          ]
-        }
-      ],
-      "conditions": [
-        {
-          "condition": "minecraft:survives_explosion"
-        }
-      ]
-    }
-  ]
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/loot_tables/blocks/oats.json b/src/main/resources/data/unicopia/loot_tables/blocks/oats.json
deleted file mode 100644
index 17b0d17a..00000000
--- a/src/main/resources/data/unicopia/loot_tables/blocks/oats.json
+++ /dev/null
@@ -1,55 +0,0 @@
-{
-  "type": "minecraft:block",
-  "functions": [
-    {
-      "function": "minecraft:explosion_decay"
-    }
-  ],
-  "pools": [
-    {
-      "bonus_rolls": 0.0,
-      "entries": [
-        {
-          "type": "minecraft:alternatives",
-          "children": [
-            {
-              "type": "minecraft:item",
-              "name": "unicopia:oat_seeds"
-            }
-          ]
-        }
-      ],
-      "rolls": 1.0
-    },
-    {
-      "bonus_rolls": 0.0,
-      "conditions": [
-        {
-          "block": "unicopia:oats",
-          "condition": "minecraft:block_state_property",
-          "properties": {
-            "age": "11"
-          }
-        }
-      ],
-      "entries": [
-        {
-          "type": "minecraft:item",
-          "functions": [
-            {
-              "enchantment": "minecraft:fortune",
-              "formula": "minecraft:binomial_with_bonus_count",
-              "function": "minecraft:apply_bonus",
-              "parameters": {
-                "extra": 3,
-                "probability": 0.5714286
-              }
-            }
-          ],
-          "name": "unicopia:oat_seeds"
-        }
-      ],
-      "rolls": 1.0
-    }
-  ]
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/loot_tables/blocks/oats_crown.json b/src/main/resources/data/unicopia/loot_tables/blocks/oats_crown.json
deleted file mode 100644
index fe5807ed..00000000
--- a/src/main/resources/data/unicopia/loot_tables/blocks/oats_crown.json
+++ /dev/null
@@ -1,29 +0,0 @@
-{
-  "type": "minecraft:block",
-  "functions": [
-    {
-      "function": "minecraft:explosion_decay"
-    }
-  ],
-  "pools": [
-    {
-      "bonus_rolls": 0.0,
-      "entries": [
-        {
-          "type": "minecraft:item",
-          "conditions": [
-            {
-              "block": "unicopia:oats_crown",
-              "condition": "minecraft:block_state_property",
-              "properties": {
-                "age": "1"
-              }
-            }
-          ],
-          "name": "unicopia:oats"
-        }
-      ],
-      "rolls": 1.0
-    }
-  ]
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/loot_tables/blocks/oats_stem.json b/src/main/resources/data/unicopia/loot_tables/blocks/oats_stem.json
deleted file mode 100644
index 72ea00c4..00000000
--- a/src/main/resources/data/unicopia/loot_tables/blocks/oats_stem.json
+++ /dev/null
@@ -1,29 +0,0 @@
-{
-  "type": "minecraft:block",
-  "functions": [
-    {
-      "function": "minecraft:explosion_decay"
-    }
-  ],
-  "pools": [
-    {
-      "bonus_rolls": 0.0,
-      "entries": [
-        {
-          "type": "minecraft:item",
-          "conditions": [
-            {
-              "block": "unicopia:oats_stem",
-              "condition": "minecraft:block_state_property",
-              "properties": {
-                "age": "6"
-              }
-            }
-          ],
-          "name": "unicopia:oats"
-        }
-      ],
-      "rolls": 1.0
-    }
-  ]
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/loot_tables/blocks/pineapple.json b/src/main/resources/data/unicopia/loot_tables/blocks/pineapple.json
deleted file mode 100644
index aced6181..00000000
--- a/src/main/resources/data/unicopia/loot_tables/blocks/pineapple.json
+++ /dev/null
@@ -1,35 +0,0 @@
-{
-  "type": "minecraft:block",
-  "pools": [
-    {
-      "rolls": 1.0,
-      "bonus_rolls": 0.0,
-      "entries": [
-        {
-          "type": "minecraft:alternatives",
-          "children": [
-            {
-              "type": "minecraft:item",
-              "conditions": [
-                {
-                  "condition": "minecraft:block_state_property",
-                  "block": "unicopia:pineapple",
-                  "properties": {
-                    "age": "7",
-                    "half": "top"
-                  }
-                }
-              ],
-              "name": "unicopia:pineapple"
-            }
-          ]
-        }
-      ]
-    }
-  ],
-  "functions": [
-    {
-      "function": "minecraft:explosion_decay"
-    }
-  ]
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/loot_tables/blocks/plunder_vine.json b/src/main/resources/data/unicopia/loot_tables/blocks/plunder_vine.json
deleted file mode 100644
index 857d1f4c..00000000
--- a/src/main/resources/data/unicopia/loot_tables/blocks/plunder_vine.json
+++ /dev/null
@@ -1,42 +0,0 @@
-{
-  "type": "minecraft:block",
-  "functions": [
-    {
-      "function": "minecraft:explosion_decay"
-    }
-  ],
-  "pools": [
-    {
-      "bonus_rolls": 0.0,
-      "entries": [
-        {
-          "type": "minecraft:item",
-          "name": "minecraft:stick"
-        },
-        {
-          "type": "minecraft:item",
-          "name": "minecraft:dead_bush"
-        }
-      ],
-      "rolls": 4.0
-    },
-        {
-      "bonus_rolls": 0.0,
-      "entries": [
-        {
-          "type": "minecraft:item",
-          "name": "minecraft:stick"
-        },
-        {
-          "type": "minecraft:item",
-          "name": "minecraft:dead_bush"
-        },
-        {
-          "type": "minecraft:item",
-          "name": "unicopia:gryphon_feather"
-        }
-      ],
-      "rolls": 1.0
-    }
-  ]
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/loot_tables/blocks/rice_block.json b/src/main/resources/data/unicopia/loot_tables/blocks/rice_block.json
deleted file mode 100644
index e79c51d7..00000000
--- a/src/main/resources/data/unicopia/loot_tables/blocks/rice_block.json
+++ /dev/null
@@ -1,165 +0,0 @@
-{
-  "type": "minecraft:block",
-  "fabric:load_conditions": [
-    {
-      "condition": "fabric:all_mods_loaded",
-      "values": [
-        "farmersdelight"
-      ]
-    }
-  ],
-  "pools": [
-    {
-      "bonus_rolls": 0.0,
-      "conditions": [
-        {
-          "block": "unicopia:rice_block",
-          "condition": "minecraft:block_state_property",
-          "properties": {
-            "top_north_east": "true"
-          }
-        }
-      ],
-      "entries": [
-        {
-          "type": "minecraft:item",
-          "name": "farmersdelight:rice_panicle"
-        }
-      ],
-      "rolls": 1.0
-    },
-    {
-      "bonus_rolls": 0.0,
-      "conditions": [
-        {
-          "block": "unicopia:rice_block",
-          "condition": "minecraft:block_state_property",
-          "properties": {
-            "top_north_west": "true"
-          }
-        }
-      ],
-      "entries": [
-        {
-          "type": "minecraft:item",
-          "name": "farmersdelight:rice_panicle"
-        }
-      ],
-      "rolls": 1.0
-    },
-    {
-      "bonus_rolls": 0.0,
-      "conditions": [
-        {
-          "block": "unicopia:rice_block",
-          "condition": "minecraft:block_state_property",
-          "properties": {
-            "top_south_east": "true"
-          }
-        }
-      ],
-      "entries": [
-        {
-          "type": "minecraft:item",
-          "name": "farmersdelight:rice_panicle"
-        }
-      ],
-      "rolls": 1.0
-    },
-    {
-      "bonus_rolls": 0.0,
-      "conditions": [
-        {
-          "block": "unicopia:rice_block",
-          "condition": "minecraft:block_state_property",
-          "properties": {
-            "top_south_west": "true"
-          }
-        }
-      ],
-      "entries": [
-        {
-          "type": "minecraft:item",
-          "name": "farmersdelight:rice_panicle"
-        }
-      ],
-      "rolls": 1.0
-    },
-    {
-      "bonus_rolls": 0.0,
-      "conditions": [
-        {
-          "block": "unicopia:rice_block",
-          "condition": "minecraft:block_state_property",
-          "properties": {
-            "bottom_north_east": "true"
-          }
-        }
-      ],
-      "entries": [
-        {
-          "type": "minecraft:item",
-          "name": "farmersdelight:rice_panicle"
-        }
-      ],
-      "rolls": 1.0
-    },
-    {
-      "bonus_rolls": 0.0,
-      "conditions": [
-        {
-          "block": "unicopia:rice_block",
-          "condition": "minecraft:block_state_property",
-          "properties": {
-            "bottom_north_west": "true"
-          }
-        }
-      ],
-      "entries": [
-        {
-          "type": "minecraft:item",
-          "name": "farmersdelight:rice_panicle"
-        }
-      ],
-      "rolls": 1.0
-    },
-    {
-      "bonus_rolls": 0.0,
-      "conditions": [
-        {
-          "block": "unicopia:rice_block",
-          "condition": "minecraft:block_state_property",
-          "properties": {
-            "bottom_south_east": "true"
-          }
-        }
-      ],
-      "entries": [
-        {
-          "type": "minecraft:item",
-          "name": "farmersdelight:rice_panicle"
-        }
-      ],
-      "rolls": 1.0
-    },
-    {
-      "bonus_rolls": 0.0,
-      "conditions": [
-        {
-          "block": "unicopia:rice_block",
-          "condition": "minecraft:block_state_property",
-          "properties": {
-            "bottom_south_west": "true"
-          }
-        }
-      ],
-      "entries": [
-        {
-          "type": "minecraft:item",
-          "name": "farmersdelight:rice_panicle"
-        }
-      ],
-      "rolls": 1.0
-    }
-  ]
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/loot_tables/blocks/rocks.json b/src/main/resources/data/unicopia/loot_tables/blocks/rocks.json
deleted file mode 100644
index 83eda199..00000000
--- a/src/main/resources/data/unicopia/loot_tables/blocks/rocks.json
+++ /dev/null
@@ -1,85 +0,0 @@
-{
-  "type": "minecraft:block",
-  "pools": [
-    {
-      "rolls": 1.0,
-      "bonus_rolls": 0.0,
-      "entries": [
-        {
-          "type": "minecraft:alternatives",
-          "children": [
-            {
-              "type": "minecraft:item",
-              "conditions": [
-                {
-                  "condition": "minecraft:block_state_property",
-                  "block": "unicopia:rocks",
-                  "properties": {
-                    "age": "7"
-                  }
-                },
-	            {
-	              "condition": "minecraft:random_chance",
-	              "chance": 0.25
-	            }
-              ],
-              "name": "unicopia:weird_rock"
-            },
-            {
-              "type": "minecraft:item",
-              "conditions": [
-                {
-                  "condition": "minecraft:block_state_property",
-                  "block": "unicopia:rocks",
-                  "properties": {
-                    "age": "7"
-                  }
-                }
-              ],
-              "name": "unicopia:rock"
-            },
-            {
-              "type": "minecraft:item",
-              "name": "unicopia:pebbles"
-            }
-          ]
-        }
-      ]
-    },
-    {
-      "rolls": 1.0,
-      "bonus_rolls": 0.0,
-      "entries": [
-        {
-          "type": "minecraft:item",
-          "functions": [
-            {
-              "function": "minecraft:apply_bonus",
-              "enchantment": "minecraft:fortune",
-              "formula": "minecraft:binomial_with_bonus_count",
-              "parameters": {
-                "extra": 3,
-                "probability": 0.5714286
-              }
-            }
-          ],
-          "name": "unicopia:pebbles"
-        }
-      ],
-      "conditions": [
-        {
-          "condition": "minecraft:block_state_property",
-          "block": "unicopia:rocks",
-          "properties": {
-            "age": "7"
-          }
-        }
-      ]
-    }
-  ],
-  "functions": [
-    {
-      "function": "minecraft:explosion_decay"
-    }
-  ]
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/loot_tables/blocks/scallop_shell.json b/src/main/resources/data/unicopia/loot_tables/blocks/scallop_shell.json
deleted file mode 100644
index c1e002b1..00000000
--- a/src/main/resources/data/unicopia/loot_tables/blocks/scallop_shell.json
+++ /dev/null
@@ -1,96 +0,0 @@
-{
-  "type": "minecraft:block",
-  "pools": [
-    {
-      "rolls": 1.0,
-      "bonus_rolls": 0.0,
-      "entries": [
-        {
-          "type": "minecraft:item",
-          "name": "unicopia:scallop_shell",
-          "conditions": [
-            {
-              "block": "unicopia:scallop_shell",
-              "condition": "minecraft:block_state_property",
-              "properties": {
-                "count": "1"
-              }
-            }
-          ],
-          "functions": [
-            {
-              "add": false,
-              "count": 1,
-              "function": "minecraft:set_count"
-            }
-          ]
-        },
-        {
-          "type": "minecraft:item",
-          "name": "unicopia:scallop_shell",
-          "conditions": [
-            {
-              "block": "unicopia:scallop_shell",
-              "condition": "minecraft:block_state_property",
-              "properties": {
-                "count": "2"
-              }
-            }
-          ],
-          "functions": [
-            {
-              "add": false,
-              "count": 2,
-              "function": "minecraft:set_count"
-            }
-          ]
-        },
-        {
-          "type": "minecraft:item",
-          "name": "unicopia:scallop_shell",
-          "conditions": [
-            {
-              "block": "unicopia:scallop_shell",
-              "condition": "minecraft:block_state_property",
-              "properties": {
-                "count": "3"
-              }
-            }
-          ],
-          "functions": [
-            {
-              "add": false,
-              "count": 3,
-              "function": "minecraft:set_count"
-            }
-          ]
-        },
-        {
-          "type": "minecraft:item",
-          "name": "unicopia:scallop_shell",
-          "conditions": [
-            {
-              "block": "unicopia:scallop_shell",
-              "condition": "minecraft:block_state_property",
-              "properties": {
-                "count": "4"
-              }
-            }
-          ],
-          "functions": [
-            {
-              "add": false,
-              "count": 4,
-              "function": "minecraft:set_count"
-            }
-          ]
-        }
-      ],
-      "conditions": [
-        {
-          "condition": "minecraft:survives_explosion"
-        }
-      ]
-    }
-  ]
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/loot_tables/blocks/slime_pustule.json b/src/main/resources/data/unicopia/loot_tables/blocks/slime_pustule.json
deleted file mode 100644
index 3945bf2f..00000000
--- a/src/main/resources/data/unicopia/loot_tables/blocks/slime_pustule.json
+++ /dev/null
@@ -1,55 +0,0 @@
-{
-  "type": "minecraft:block",
-  "pools": [
-    {
-      "rolls": 1.0,
-      "bonus_rolls": 0.0,
-      "entries": [
-        {
-          "type": "minecraft:item",
-          "name": "unicopia:slime_pustule"
-        }
-      ],
-      "conditions": [
-        {
-          "condition": "minecraft:all_of",
-          "terms": [
-            {
-              "block": "unicopia:slime_pustule",
-              "condition": "minecraft:block_state_property",
-              "properties": {
-                "shape": "pod"
-              }
-            },
-            {
-              "condition": "minecraft:any_of",
-              "terms": [
-                {
-                  "condition": "minecraft:match_tool",
-                  "predicate": {
-                    "items": [
-                      "minecraft:shears"
-                    ]
-                  }
-                },
-                {
-                  "condition": "minecraft:match_tool",
-                  "predicate": {
-                    "enchantments": [
-                      {
-                        "enchantment": "minecraft:silk_touch",
-                        "levels": {
-                          "min": 1
-                        }
-                      }
-                    ]
-                  }
-                }
-              ]
-            }
-          ]
-        }
-      ]
-    }
-  ]
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/loot_tables/blocks/soggy_cloud_slab.json b/src/main/resources/data/unicopia/loot_tables/blocks/soggy_cloud_slab.json
deleted file mode 100644
index b805f097..00000000
--- a/src/main/resources/data/unicopia/loot_tables/blocks/soggy_cloud_slab.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
-  "type": "minecraft:block",
-  "pools": [
-    {
-      "rolls": 1.0,
-      "bonus_rolls": 0.0,
-      "entries": [
-        {
-          "type": "minecraft:item",
-          "name": "unicopia:cloud",
-          "functions": [
-            {
-              "add": false,
-              "count": 3,
-              "function": "minecraft:set_count"
-            }
-          ]
-        }
-      ],
-      "conditions": [
-        {
-          "condition": "minecraft:survives_explosion"
-        }
-      ]
-    }
-  ]
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/loot_tables/blocks/straw_block.json b/src/main/resources/data/unicopia/loot_tables/blocks/straw_block.json
deleted file mode 100644
index ca46ba50..00000000
--- a/src/main/resources/data/unicopia/loot_tables/blocks/straw_block.json
+++ /dev/null
@@ -1,165 +0,0 @@
-{
-  "type": "minecraft:block",
-  "fabric:load_conditions": [
-    {
-      "condition": "fabric:all_mods_loaded",
-      "values": [
-        "farmersdelight"
-      ]
-    }
-  ],
-  "pools": [
-    {
-      "bonus_rolls": 0.0,
-      "conditions": [
-        {
-          "block": "unicopia:straw_block",
-          "condition": "minecraft:block_state_property",
-          "properties": {
-            "top_north_east": "true"
-          }
-        }
-      ],
-      "entries": [
-        {
-          "type": "minecraft:item",
-          "name": "farmersdelight:straw"
-        }
-      ],
-      "rolls": 1.0
-    },
-    {
-      "bonus_rolls": 0.0,
-      "conditions": [
-        {
-          "block": "unicopia:straw_block",
-          "condition": "minecraft:block_state_property",
-          "properties": {
-            "top_north_west": "true"
-          }
-        }
-      ],
-      "entries": [
-        {
-          "type": "minecraft:item",
-          "name": "farmersdelight:straw"
-        }
-      ],
-      "rolls": 1.0
-    },
-    {
-      "bonus_rolls": 0.0,
-      "conditions": [
-        {
-          "block": "unicopia:straw_block",
-          "condition": "minecraft:block_state_property",
-          "properties": {
-            "top_south_east": "true"
-          }
-        }
-      ],
-      "entries": [
-        {
-          "type": "minecraft:item",
-          "name": "farmersdelight:straw"
-        }
-      ],
-      "rolls": 1.0
-    },
-    {
-      "bonus_rolls": 0.0,
-      "conditions": [
-        {
-          "block": "unicopia:straw_block",
-          "condition": "minecraft:block_state_property",
-          "properties": {
-            "top_south_west": "true"
-          }
-        }
-      ],
-      "entries": [
-        {
-          "type": "minecraft:item",
-          "name": "farmersdelight:straw"
-        }
-      ],
-      "rolls": 1.0
-    },
-    {
-      "bonus_rolls": 0.0,
-      "conditions": [
-        {
-          "block": "unicopia:straw_block",
-          "condition": "minecraft:block_state_property",
-          "properties": {
-            "bottom_north_east": "true"
-          }
-        }
-      ],
-      "entries": [
-        {
-          "type": "minecraft:item",
-          "name": "farmersdelight:straw"
-        }
-      ],
-      "rolls": 1.0
-    },
-    {
-      "bonus_rolls": 0.0,
-      "conditions": [
-        {
-          "block": "unicopia:straw_block",
-          "condition": "minecraft:block_state_property",
-          "properties": {
-            "bottom_north_west": "true"
-          }
-        }
-      ],
-      "entries": [
-        {
-          "type": "minecraft:item",
-          "name": "farmersdelight:straw"
-        }
-      ],
-      "rolls": 1.0
-    },
-    {
-      "bonus_rolls": 0.0,
-      "conditions": [
-        {
-          "block": "unicopia:straw_block",
-          "condition": "minecraft:block_state_property",
-          "properties": {
-            "bottom_south_east": "true"
-          }
-        }
-      ],
-      "entries": [
-        {
-          "type": "minecraft:item",
-          "name": "farmersdelight:straw"
-        }
-      ],
-      "rolls": 1.0
-    },
-    {
-      "bonus_rolls": 0.0,
-      "conditions": [
-        {
-          "block": "unicopia:straw_block",
-          "condition": "minecraft:block_state_property",
-          "properties": {
-            "bottom_south_west": "true"
-          }
-        }
-      ],
-      "entries": [
-        {
-          "type": "minecraft:item",
-          "name": "farmersdelight:straw"
-        }
-      ],
-      "rolls": 1.0
-    }
-  ]
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/loot_tables/blocks/turret_shell.json b/src/main/resources/data/unicopia/loot_tables/blocks/turret_shell.json
deleted file mode 100644
index b300a2d4..00000000
--- a/src/main/resources/data/unicopia/loot_tables/blocks/turret_shell.json
+++ /dev/null
@@ -1,96 +0,0 @@
-{
-  "type": "minecraft:block",
-  "pools": [
-    {
-      "rolls": 1.0,
-      "bonus_rolls": 0.0,
-      "entries": [
-        {
-          "type": "minecraft:item",
-          "name": "unicopia:turret_shell",
-          "conditions": [
-            {
-              "block": "unicopia:turret_shell",
-              "condition": "minecraft:block_state_property",
-              "properties": {
-                "count": "1"
-              }
-            }
-          ],
-          "functions": [
-            {
-              "add": false,
-              "count": 1,
-              "function": "minecraft:set_count"
-            }
-          ]
-        },
-        {
-          "type": "minecraft:item",
-          "name": "unicopia:turret_shell",
-          "conditions": [
-            {
-              "block": "unicopia:turret_shell",
-              "condition": "minecraft:block_state_property",
-              "properties": {
-                "count": "2"
-              }
-            }
-          ],
-          "functions": [
-            {
-              "add": false,
-              "count": 2,
-              "function": "minecraft:set_count"
-            }
-          ]
-        },
-        {
-          "type": "minecraft:item",
-          "name": "unicopia:turret_shell",
-          "conditions": [
-            {
-              "block": "unicopia:turret_shell",
-              "condition": "minecraft:block_state_property",
-              "properties": {
-                "count": "3"
-              }
-            }
-          ],
-          "functions": [
-            {
-              "add": false,
-              "count": 3,
-              "function": "minecraft:set_count"
-            }
-          ]
-        },
-        {
-          "type": "minecraft:item",
-          "name": "unicopia:turret_shell",
-          "conditions": [
-            {
-              "block": "unicopia:turret_shell",
-              "condition": "minecraft:block_state_property",
-              "properties": {
-                "count": "4"
-              }
-            }
-          ],
-          "functions": [
-            {
-              "add": false,
-              "count": 4,
-              "function": "minecraft:set_count"
-            }
-          ]
-        }
-      ],
-      "conditions": [
-        {
-          "condition": "minecraft:survives_explosion"
-        }
-      ]
-    }
-  ]
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/loot_tables/chests/changeling_hive_trap.json b/src/main/resources/data/unicopia/loot_tables/chests/changeling_hive_trap.json
deleted file mode 100644
index 2dac1a86..00000000
--- a/src/main/resources/data/unicopia/loot_tables/chests/changeling_hive_trap.json
+++ /dev/null
@@ -1,204 +0,0 @@
-{
-  "type": "minecraft:chest",
-  "pools": [
-    {
-      "bonus_rolls": 0.0,
-      "entries": [
-        {
-          "type": "minecraft:item",
-          "name": "minecraft:tipped_arrow",
-          "functions": [
-            { "function": "minecraft:set_potion", "id": "unicopia:short_morph_earth" },
-            {
-              "function": "minecraft:set_count",
-              "count": {
-                "min": 3.0,
-                "max": 9.0,
-                "type": "minecraft:uniform"
-              }
-            }
-          ],
-          "weight": 3
-        },
-        {
-          "type": "minecraft:item",
-          "name": "minecraft:tipped_arrow",
-          "functions": [
-            { "function": "minecraft:set_potion", "id": "unicopia:short_morph_unicorn" },
-            {
-              "function": "minecraft:set_count",
-              "count": {
-                "min": 3.0,
-                "max": 9.0,
-                "type": "minecraft:uniform"
-              }
-            }
-          ],
-          "weight": 1
-        },
-        {
-          "type": "minecraft:item",
-          "name": "minecraft:tipped_arrow",
-          "functions": [
-            { "function": "minecraft:set_potion", "id": "unicopia:short_morph_pegasus" },
-            {
-              "function": "minecraft:set_count",
-              "count": {
-                "min": 3.0,
-                "max": 9.0,
-                "type": "minecraft:uniform"
-              }
-            }
-          ],
-          "weight": 1
-        },
-        {
-          "type": "minecraft:item",
-          "name": "minecraft:tipped_arrow",
-          "functions": [
-            { "function": "minecraft:set_potion", "id": "unicopia:short_morph_bat" },
-            {
-              "function": "minecraft:set_count",
-              "count": {
-                "min": 3.0,
-                "max": 9.0,
-                "type": "minecraft:uniform"
-              }
-            }
-          ],
-          "weight": 1
-        },
-        {
-          "type": "minecraft:item",
-          "name": "minecraft:tipped_arrow",
-          "functions": [
-            { "function": "minecraft:set_potion", "id": "unicopia:short_morph_kirin" },
-            {
-              "function": "minecraft:set_count",
-              "count": {
-                "min": 3.0,
-                "max": 9.0,
-                "type": "minecraft:uniform"
-              }
-            }
-          ],
-          "weight": 1
-        },
-        {
-          "type": "minecraft:item",
-          "name": "minecraft:tipped_arrow",
-          "functions": [
-            { "function": "minecraft:set_potion", "id": "unicopia:short_morph_hippogriff" },
-            {
-              "function": "minecraft:set_count",
-              "count": {
-                "min": 3.0,
-                "max": 9.0,
-                "type": "minecraft:uniform"
-              }
-            }
-          ],
-          "weight": 1
-        },
-        
-        {
-          "type": "minecraft:item",
-          "name": "minecraft:tipped_arrow",
-          "functions": [
-            { "function": "minecraft:set_potion", "id": "unicopia:long_morph_earth" },
-            {
-              "function": "minecraft:set_count",
-              "count": {
-                "min": 3.0,
-                "max": 9.0,
-                "type": "minecraft:uniform"
-              }
-            }
-          ],
-          "weight": 5
-        },
-        {
-          "type": "minecraft:item",
-          "name": "minecraft:tipped_arrow",
-          "functions": [
-            { "function": "minecraft:set_potion", "id": "unicopia:long_morph_unicorn" },
-            {
-              "function": "minecraft:set_count",
-              "count": {
-                "min": 3.0,
-                "max": 9.0,
-                "type": "minecraft:uniform"
-              }
-            }
-          ],
-          "weight": 2
-        },
-        {
-          "type": "minecraft:item",
-          "name": "minecraft:tipped_arrow",
-          "functions": [
-            { "function": "minecraft:set_potion", "id": "unicopia:long_morph_pegasus" },
-            {
-              "function": "minecraft:set_count",
-              "count": {
-                "min": 3.0,
-                "max": 9.0,
-                "type": "minecraft:uniform"
-              }
-            }
-          ],
-          "weight": 2
-        },
-        {
-          "type": "minecraft:item",
-          "name": "minecraft:tipped_arrow",
-          "functions": [
-            { "function": "minecraft:set_potion", "id": "unicopia:long_morph_bat" },
-            {
-              "function": "minecraft:set_count",
-              "count": {
-                "min": 3.0,
-                "max": 9.0,
-                "type": "minecraft:uniform"
-              }
-            }
-          ],
-          "weight": 2
-        },
-        {
-          "type": "minecraft:item",
-          "name": "minecraft:tipped_arrow",
-          "functions": [
-            { "function": "minecraft:set_potion", "id": "unicopia:long_morph_kirin" },
-            {
-              "function": "minecraft:set_count",
-              "count": {
-                "min": 3.0,
-                "max": 9.0,
-                "type": "minecraft:uniform"
-              }
-            }
-          ],
-          "weight": 2
-        },
-        {
-          "type": "minecraft:item",
-          "name": "minecraft:tipped_arrow",
-          "functions": [
-            { "function": "minecraft:set_potion", "id": "unicopia:long_morph_hippogriff" },
-            {
-              "function": "minecraft:set_count",
-              "count": {
-                "min": 3.0,
-                "max": 9.0,
-                "type": "minecraft:uniform"
-              }
-            }
-          ],
-          "weight": 2
-        }
-      ],
-      "rolls": 6.0
-    }
-  ]
-}
diff --git a/src/main/resources/data/unicopia/loot_tables/entities/butterfly.json b/src/main/resources/data/unicopia/loot_tables/entities/butterfly.json
deleted file mode 100644
index 9992d4bd..00000000
--- a/src/main/resources/data/unicopia/loot_tables/entities/butterfly.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
-  "type": "minecraft:entity",
-  "pools": [
-    {
-      "rolls": 1,
-      "bonus_rolls": 0,
-      "entries": [
-        {
-          "type": "minecraft:item",
-          "functions": [
-            {
-              "function": "minecraft:looting_enchant",
-              "count": {
-                "type": "minecraft:uniform",
-                "min": 0.0,
-                "max": 1.0
-              }
-            }
-          ],
-          "name": "unicopia:butterfly"
-        }
-      ]
-    }
-  ]
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/loot_tables/entities/loot_bug.json b/src/main/resources/data/unicopia/loot_tables/entities/loot_bug.json
deleted file mode 100644
index 7e8ec0ae..00000000
--- a/src/main/resources/data/unicopia/loot_tables/entities/loot_bug.json
+++ /dev/null
@@ -1,87 +0,0 @@
-{
-  "type": "minecraft:entity",
-  "pools": [
-    {
-      "rolls": 11,
-      "bonus_rolls": 0,
-      "entries": [
-        {
-          "type": "minecraft:item",
-          "functions": [
-            {
-              "add": false,
-              "count": {
-                "type": "minecraft:uniform",
-                "max": 12.0,
-                "min": 6.0
-              },
-              "function": "minecraft:set_count"
-            },
-            {
-              "function": "minecraft:looting_enchant",
-              "count": {
-                "type": "minecraft:uniform",
-                "min": 0.0,
-                "max": 3.0
-              }
-            }
-          ],
-          "name": "minecraft:gold_nugget"
-        },
-        {
-          "type": "minecraft:item",
-          "functions": [
-            {
-              "add": false,
-              "count": {
-                "type": "minecraft:uniform",
-                "max": 12.0,
-                "min": 6.0
-              },
-              "function": "minecraft:set_count"
-            },
-            {
-              "function": "minecraft:looting_enchant",
-              "count": {
-                "type": "minecraft:uniform",
-                "min": 0.0,
-                "max": 3.0
-              }
-            }
-          ],
-          "name": "minecraft:iron_nugget"
-        }
-      ]
-    },
-    {
-      "rolls": 1,
-      "bonus_rolls": 0,
-      "entries": [
-        {
-          "type": "minecraft:tag",
-          "functions": [
-            {
-              "add": false,
-              "count": {
-                "type": "minecraft:uniform",
-                "max": 3.0,
-                "min": 1.0
-              },
-              "function": "minecraft:set_count"
-            },
-            {
-              "function": "minecraft:looting_enchant",
-              "count": {
-                "type": "minecraft:uniform",
-                "min": 0.0,
-                "max": 6.0
-              }
-            }
-          ],
-          "name": "unicopia:loot_bug_high_value_drops",
-          "expand": true
-        }
-      ]
-    }
-  ]
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/loot_tables/entities/storm_cloud.json b/src/main/resources/data/unicopia/loot_tables/entities/storm_cloud.json
deleted file mode 100644
index 8d599d1a..00000000
--- a/src/main/resources/data/unicopia/loot_tables/entities/storm_cloud.json
+++ /dev/null
@@ -1,34 +0,0 @@
-{
-  "type": "minecraft:entity",
-  "pools": [
-    {
-      "rolls": 1,
-      "bonus_rolls": 0,
-      "entries": [
-        {
-          "type": "minecraft:item",
-          "functions": [
-            {
-              "add": false,
-              "count": {
-                "type": "minecraft:uniform",
-                "max": 12.0,
-                "min": 6.0
-              },
-              "function": "minecraft:set_count"
-            },
-            {
-              "function": "minecraft:looting_enchant",
-              "count": {
-                "type": "minecraft:uniform",
-                "min": 0.0,
-                "max": 1.0
-              }
-            }
-          ],
-          "name": "unicopia:cloud_lump"
-        }
-      ]
-    }
-  ]
-}
\ No newline at end of file
diff --git a/src/main/resources/data/unicopia/tags/damage_type/breaks_sunglasses.json b/src/main/resources/data/unicopia/tags/damage_type/breaks_sunglasses.json
deleted file mode 100644
index 3c832cc1..00000000
--- a/src/main/resources/data/unicopia/tags/damage_type/breaks_sunglasses.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "unicopia:bat_screech",
-    "unicopia:rainboom"
-  ]
-}
diff --git a/src/main/resources/data/unicopia/tags/damage_type/from_horseshoes.json b/src/main/resources/data/unicopia/tags/damage_type/from_horseshoes.json
deleted file mode 100644
index 276d2073..00000000
--- a/src/main/resources/data/unicopia/tags/damage_type/from_horseshoes.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "unicopia:horseshoe"
-  ]
-}
diff --git a/src/main/resources/data/unicopia/tags/damage_type/from_rocks.json b/src/main/resources/data/unicopia/tags/damage_type/from_rocks.json
deleted file mode 100644
index 9ab866dd..00000000
--- a/src/main/resources/data/unicopia/tags/damage_type/from_rocks.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "unicopia:rock"
-  ]
-}
diff --git a/src/main/resources/data/unicopia/tags/damage_type/spellbook_immune_to.json b/src/main/resources/data/unicopia/tags/damage_type/spellbook_immune_to.json
deleted file mode 100644
index f270bd7e..00000000
--- a/src/main/resources/data/unicopia/tags/damage_type/spellbook_immune_to.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "#minecraft:is_fall",
-    "#minecraft:is_freezing",
-    "#minecraft:is_lightning",
-    "#minecraft:is_projectile",
-    "unicopia:zap",
-    "unicopia:love_draining",
-    "unicopia:life_draining",
-    "unicopia:rainboom",
-    "unicopia:sun",
-    "unicopia:sunlight",
-    "unicopia:smash"
-  ]
-}
diff --git a/src/main/resources/data/unicopia/tags/items/food_types/baked_goods.json b/src/main/resources/data/unicopia/tags/items/food_types/baked_goods.json
deleted file mode 100644
index e9ac11e8..00000000
--- a/src/main/resources/data/unicopia/tags/items/food_types/baked_goods.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "minecraft:bread",
-    "minecraft:cookie",
-    "unicopia:muffin",
-    "unicopia:scone",
-    "#c:grain",
-    "unicopia:cooked_zap_apple",
-    "minecraft:pumpkin_pie",
-    "#unicopia:pies",
-    "unicopia:apple_pie_slice",
-    "unicopia:toast",
-    "unicopia:burned_toast",
-    "unicopia:jam_toast",
-    "unicopia:imported_oats",
-    "unicopia:oatmeal",
-    "unicopia:hay_fries",
-    "unicopia:crispy_hay_fries",
-    "unicopia:horse_shoe_fries",
-    "unicopia:oatmeal_cookie",
-    "unicopia:chocolate_oatmeal_cookie",
-    "unicopia:pinecone_cookie",
-    "unicopia:bowl_of_nuts",
-    { "id": "farmersdelight:wheat_dough", "required": false },
-    { "id": "farmersdelight:raw_pasta", "required": false },
-    { "id": "farmersdelight:pie_crust", "required": false },
-    { "id": "farmersdelight:sweet_berry_cookie", "required": false },
-    { "id": "farmersdelight:honey_cookie", "required": false },
-    { "id": "farmersdelight:egg_sandwich", "required": false }
-  ]
-}
diff --git a/src/main/resources/data/unicopia/tags/items/food_types/bat_ponys_delight.json b/src/main/resources/data/unicopia/tags/items/food_types/bat_ponys_delight.json
deleted file mode 100644
index 8309c0f0..00000000
--- a/src/main/resources/data/unicopia/tags/items/food_types/bat_ponys_delight.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "unicopia:mango",
-    { "id": "#c:mango", "required": false },
-    { "id": "#c:mangoes", "required": false }
-  ]
-}
diff --git a/src/main/resources/data/unicopia/tags/items/food_types/candy.json b/src/main/resources/data/unicopia/tags/items/food_types/candy.json
deleted file mode 100644
index 8a152f67..00000000
--- a/src/main/resources/data/unicopia/tags/items/food_types/candy.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "unicopia:rock_candy",
-    "unicopia:candied_apple",
-    "minecraft:sugar",
-    { "id": "bakersdelight:sweet_berry_cheesecake_slice", "required": false },
-    { "id": "bakersdelight:cake_slice", "required": false }
-  ]
-}
diff --git a/src/main/resources/data/unicopia/tags/items/food_types/cooked_fish.json b/src/main/resources/data/unicopia/tags/items/food_types/cooked_fish.json
deleted file mode 100644
index 216c3f5d..00000000
--- a/src/main/resources/data/unicopia/tags/items/food_types/cooked_fish.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "#c:cooked_fish",
-    { "id": "farmersdelight:fish_stew", "required": false },
-    { "id": "farmersdelight:baked_cod_stew", "required": false },
-    { "id": "farmersdelight:grilled_salmon", "required": false }
-  ]
-}
diff --git a/src/main/resources/data/unicopia/tags/items/food_types/cooked_insect.json b/src/main/resources/data/unicopia/tags/items/food_types/cooked_insect.json
deleted file mode 100644
index 8e23aa37..00000000
--- a/src/main/resources/data/unicopia/tags/items/food_types/cooked_insect.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "#c:cooked_insects"
-  ]
-}
diff --git a/src/main/resources/data/unicopia/tags/items/food_types/cooked_meat.json b/src/main/resources/data/unicopia/tags/items/food_types/cooked_meat.json
deleted file mode 100644
index 9860573f..00000000
--- a/src/main/resources/data/unicopia/tags/items/food_types/cooked_meat.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "#c:cooked_meats",
-    { "id": "farmersdelight:chicken_soup", "required": false },
-    { "id": "farmersdelight:bacon_and_eggs", "required": false },
-    { "id": "farmersdelight:pasta_with_meatballs", "required": false },
-    { "id": "farmersdelight:beef_stew", "required": false },
-    { "id": "farmersdelight:bone_broth", "required": false },
-    { "id": "farmersdelight:mutton_wrap", "required": false },
-    { "id": "farmersdelight:bacon_sandwich", "required": false },
-    { "id": "farmersdelight:hamburger", "required": false },
-    { "id": "farmersdelight:chicken_sandwich", "required": false },
-    { "id": "farmersdelight:barbecue_stick", "required": false },
-    { "id": "farmersdelight:smoked_ham", "required": false },
-    { "id": "farmersdelight:honey_glazed_ham", "required": false },
-    { "id": "farmersdelight:honey_glazed_ham_block", "required": false },
-    { "id": "farmersdelight:roast_chicken", "required": false },
-    { "id": "farmersdelight:roast_chicken_block", "required": false },
-    { "id": "farmersdelight:steak_and_potatoes", "required": false },
-    { "id": "farmersdelight:roasted_mutton_chops", "required": false },
-    { "id": "farmersdelight:pasta_with_mutton_chop", "required": false }
-  ]
-}
diff --git a/src/main/resources/data/unicopia/tags/items/food_types/cooked_sea_vegitable.json b/src/main/resources/data/unicopia/tags/items/food_types/cooked_sea_vegitable.json
deleted file mode 100644
index 30ffdfce..00000000
--- a/src/main/resources/data/unicopia/tags/items/food_types/cooked_sea_vegitable.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "minecraft:dried_kelp_block",
-    "minecraft:glow_lichen",
-    "#c:coral_blocks"
-  ]
-}
diff --git a/src/main/resources/data/unicopia/tags/items/food_types/desserts.json b/src/main/resources/data/unicopia/tags/items/food_types/desserts.json
deleted file mode 100644
index c88f3f26..00000000
--- a/src/main/resources/data/unicopia/tags/items/food_types/desserts.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "minecraft:cake",
-    { "id": "farmersdelight:sweet_berry_cheesecake", "required": false },
-    { "id": "farmersdelight:sweet_berry_cheesecake_slice", "required": false },
-    { "id": "farmersdelight:chocolate_pie_slice", "required": false },
-    { "id": "farmersdelight:cake_slice", "required": false },
-    { "id": "farmersdelight:apple_pie_slice", "required": false },
-    { "id": "farmersdelight:glow_berry_custard", "required": false }
-  ]
-}
diff --git a/src/main/resources/data/unicopia/tags/items/food_types/forage_blinding.json b/src/main/resources/data/unicopia/tags/items/food_types/forage_blinding.json
deleted file mode 100644
index 2734f9e9..00000000
--- a/src/main/resources/data/unicopia/tags/items/food_types/forage_blinding.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "minecraft:oxeye_daisy"
-  ]
-}
diff --git a/src/main/resources/data/unicopia/tags/items/food_types/forage_dangerous.json b/src/main/resources/data/unicopia/tags/items/food_types/forage_dangerous.json
deleted file mode 100644
index 40636af9..00000000
--- a/src/main/resources/data/unicopia/tags/items/food_types/forage_dangerous.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "minecraft:poppy",
-    "minecraft:lily_of_the_valley"
-  ]
-}
diff --git a/src/main/resources/data/unicopia/tags/items/food_types/forage_edible.json b/src/main/resources/data/unicopia/tags/items/food_types/forage_edible.json
deleted file mode 100644
index ee20b95a..00000000
--- a/src/main/resources/data/unicopia/tags/items/food_types/forage_edible.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "minecraft:blue_orchid",
-    "minecraft:red_tulip",
-    "minecraft:orange_tulip",
-    "minecraft:pink_tulip",
-    "minecraft:cornflower",
-    "minecraft:peony",
-    "minecraft:sunflower",
-    "minecraft:dandelion",
-    "minecraft:lilac",
-    "minecraft:tall_grass",
-    "minecraft:wheat",
-    "minecraft:dead_bush",
-    "minecraft:pink_petals",
-    "#c:foraging/edibles"
-  ]
-}
diff --git a/src/main/resources/data/unicopia/tags/items/food_types/forage_edible_filling.json b/src/main/resources/data/unicopia/tags/items/food_types/forage_edible_filling.json
deleted file mode 100644
index c3245df5..00000000
--- a/src/main/resources/data/unicopia/tags/items/food_types/forage_edible_filling.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "minecraft:hay_block",
-    "#c:foraging/edibles_filling"
-  ]
-}
diff --git a/src/main/resources/data/unicopia/tags/items/food_types/forage_nauseating.json b/src/main/resources/data/unicopia/tags/items/food_types/forage_nauseating.json
deleted file mode 100644
index 9b5ae248..00000000
--- a/src/main/resources/data/unicopia/tags/items/food_types/forage_nauseating.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "minecraft:grass",
-    "unicopia:cider",
-    { "id": "farmersdelight:rotten_tomato", "required": false }
-  ]
-}
diff --git a/src/main/resources/data/unicopia/tags/items/food_types/forage_prickly.json b/src/main/resources/data/unicopia/tags/items/food_types/forage_prickly.json
deleted file mode 100644
index 3fbb59d5..00000000
--- a/src/main/resources/data/unicopia/tags/items/food_types/forage_prickly.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "minecraft:rose_bush",
-    "#minecraft:saplings"
-  ]
-}
diff --git a/src/main/resources/data/unicopia/tags/items/food_types/forage_radioactive.json b/src/main/resources/data/unicopia/tags/items/food_types/forage_radioactive.json
deleted file mode 100644
index f274ebe5..00000000
--- a/src/main/resources/data/unicopia/tags/items/food_types/forage_radioactive.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "minecraft:azure_bluet",
-    "minecraft:torchflower"
-  ]
-}
diff --git a/src/main/resources/data/unicopia/tags/items/food_types/forage_risky.json b/src/main/resources/data/unicopia/tags/items/food_types/forage_risky.json
deleted file mode 100644
index 533231e1..00000000
--- a/src/main/resources/data/unicopia/tags/items/food_types/forage_risky.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "minecraft:allium",
-    "minecraft:white_tulip",
-    "unicopia:burned_juice",
-    "#c:foraging/risky"
-  ]
-}
diff --git a/src/main/resources/data/unicopia/tags/items/food_types/forage_severely_nauseating.json b/src/main/resources/data/unicopia/tags/items/food_types/forage_severely_nauseating.json
deleted file mode 100644
index ae67591c..00000000
--- a/src/main/resources/data/unicopia/tags/items/food_types/forage_severely_nauseating.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "minecraft:pitcher_plant"
-  ]
-}
diff --git a/src/main/resources/data/unicopia/tags/items/food_types/forage_severely_prickly.json b/src/main/resources/data/unicopia/tags/items/food_types/forage_severely_prickly.json
deleted file mode 100644
index 4ff8aebc..00000000
--- a/src/main/resources/data/unicopia/tags/items/food_types/forage_severely_prickly.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "minecraft:large_fern"
-  ]
-}
diff --git a/src/main/resources/data/unicopia/tags/items/food_types/forage_strengthening.json b/src/main/resources/data/unicopia/tags/items/food_types/forage_strengthening.json
deleted file mode 100644
index 97038fab..00000000
--- a/src/main/resources/data/unicopia/tags/items/food_types/forage_strengthening.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "minecraft:fern"
-  ]
-}
diff --git a/src/main/resources/data/unicopia/tags/items/food_types/fruit.json b/src/main/resources/data/unicopia/tags/items/food_types/fruit.json
deleted file mode 100644
index 39c40cdc..00000000
--- a/src/main/resources/data/unicopia/tags/items/food_types/fruit.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "#c:fruits",
-    "unicopia:zap_apple",
-    "unicopia:zap_bulb",
-    "unicopia:rotten_apple",
-    "minecraft:melon_slice",
-    "minecraft:sweet_berries",
-    "minecraft:glow_berries",
-    "minecraft:chorus_fruit",
-    "unicopia:juice",
-    { "id": "farmersdelight:pumpkin_slice", "required": false },
-    { "id": "farmersdelight:tomato", "required": false },
-    { "id": "farmersdelight:melon_juice", "required": false },
-    { "id": "farmersdelight:fruit_salad", "required": false },
-    { "id": "#garnished:berries", "required": false }
-  ]
-}
diff --git a/src/main/resources/data/unicopia/tags/items/food_types/love.json b/src/main/resources/data/unicopia/tags/items/food_types/love.json
deleted file mode 100644
index 72d0be9d..00000000
--- a/src/main/resources/data/unicopia/tags/items/food_types/love.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "#c:love"
-  ]
-}
diff --git a/src/main/resources/data/unicopia/tags/items/food_types/nuts_and_seeds.json b/src/main/resources/data/unicopia/tags/items/food_types/nuts_and_seeds.json
deleted file mode 100644
index 937e7578..00000000
--- a/src/main/resources/data/unicopia/tags/items/food_types/nuts_and_seeds.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "#c:seeds",
-    "#c:acorns",
-    "#c:nuts",
-    { "id": "#garnished:nuts", "required": false },
-    { "id": "#garnished:nut_mix", "required": false },
-    { "id": "#garnished:neverable_delecacies", "required": false }
-  ]
-}
diff --git a/src/main/resources/data/unicopia/tags/items/food_types/pinecone.json b/src/main/resources/data/unicopia/tags/items/food_types/pinecone.json
deleted file mode 100644
index 9ad60d14..00000000
--- a/src/main/resources/data/unicopia/tags/items/food_types/pinecone.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "#c:pinecones"
-  ]
-}
diff --git a/src/main/resources/data/unicopia/tags/items/food_types/raw_fish.json b/src/main/resources/data/unicopia/tags/items/food_types/raw_fish.json
deleted file mode 100644
index 1fb0b027..00000000
--- a/src/main/resources/data/unicopia/tags/items/food_types/raw_fish.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "#c:raw_fish",
-    { "id": "farmersdelight:cod_roll", "required": false },
-    { "id": "farmersdelight:salmon_roll", "required": false },
-    { "id": "farmersdelight:salmon_slice", "required": false },
-    { "id": "farmersdelight:cod_slice", "required": false }
-  ]
-}
diff --git a/src/main/resources/data/unicopia/tags/items/food_types/raw_insect.json b/src/main/resources/data/unicopia/tags/items/food_types/raw_insect.json
deleted file mode 100644
index 24b2cff4..00000000
--- a/src/main/resources/data/unicopia/tags/items/food_types/raw_insect.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "#c:raw_insects"
-  ]
-}
diff --git a/src/main/resources/data/unicopia/tags/items/food_types/raw_meat.json b/src/main/resources/data/unicopia/tags/items/food_types/raw_meat.json
deleted file mode 100644
index dcf23921..00000000
--- a/src/main/resources/data/unicopia/tags/items/food_types/raw_meat.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "#c:raw_meats",
-    { "id": "farmersdelight:ham", "required": false }
-  ]
-}
diff --git a/src/main/resources/data/unicopia/tags/items/food_types/raw_sea_vegitable.json b/src/main/resources/data/unicopia/tags/items/food_types/raw_sea_vegitable.json
deleted file mode 100644
index c570e4a4..00000000
--- a/src/main/resources/data/unicopia/tags/items/food_types/raw_sea_vegitable.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "minecraft:kelp",
-    "minecraft:dried_kelp",
-    "minecraft:seagrass",
-    "minecraft:sea_pickle",
-    "#c:corals",
-    "#c:coral_fans",
-    { "id": "farmersdelight:melon_popsicle", "required": false },
-    { "id": "farmersdelight:kelp_roll", "required": false },
-    { "id": "farmersdelight:kelp_roll_slice", "required": false }
-  ]
-}
diff --git a/src/main/resources/data/unicopia/tags/items/food_types/rocks.json b/src/main/resources/data/unicopia/tags/items/food_types/rocks.json
deleted file mode 100644
index 229f317a..00000000
--- a/src/main/resources/data/unicopia/tags/items/food_types/rocks.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "unicopia:rock_stew"
-  ]
-}
diff --git a/src/main/resources/data/unicopia/tags/items/food_types/rotten_meat.json b/src/main/resources/data/unicopia/tags/items/food_types/rotten_meat.json
deleted file mode 100644
index 4dee31d1..00000000
--- a/src/main/resources/data/unicopia/tags/items/food_types/rotten_meat.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "#c:rotten_meats"
-  ]
-}
diff --git a/src/main/resources/data/unicopia/tags/items/food_types/shells.json b/src/main/resources/data/unicopia/tags/items/food_types/shells.json
deleted file mode 100644
index d62b7052..00000000
--- a/src/main/resources/data/unicopia/tags/items/food_types/shells.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "minecraft:nautilus_shell",
-    "unicopia:clam_shell",
-    "unicopia:scallop_shell",
-    "unicopia:turret_shell",
-    "minecraft:seagrass",
-    "minecraft:sea_pickle"
-  ]
-}
diff --git a/src/main/resources/data/unicopia/tags/items/food_types/shelly.json b/src/main/resources/data/unicopia/tags/items/food_types/shelly.json
deleted file mode 100644
index f8790589..00000000
--- a/src/main/resources/data/unicopia/tags/items/food_types/shelly.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-  "replace": false,
-  "values": [
-    "unicopia:shelly"
-  ]
-}
diff --git a/src/main/resources/data/unicopia/tags/items/groups/bat_pony.json b/src/main/resources/data/unicopia/tags/items/groups/bat_pony.json
index 8c547253..d8ace57f 100644
--- a/src/main/resources/data/unicopia/tags/items/groups/bat_pony.json
+++ b/src/main/resources/data/unicopia/tags/items/groups/bat_pony.json
@@ -1,7 +1,7 @@
 {
   "replace": false,
   "values": [
-    "#unicopia:food_types/raw_insect",
+    "#c:raw_insect",
     "#unicopia:polearms",
     "unicopia:mango_leaves",
     "unicopia:mango_sapling",
diff --git a/src/main/resources/data/unicopia/tags/items/groups/changeling.json b/src/main/resources/data/unicopia/tags/items/groups/changeling.json
index 3cc31831..8f87e169 100644
--- a/src/main/resources/data/unicopia/tags/items/groups/changeling.json
+++ b/src/main/resources/data/unicopia/tags/items/groups/changeling.json
@@ -10,12 +10,13 @@
     "unicopia:chiselled_chitin_hull",
     "unicopia:chitin_spikes",
     "unicopia:mysterious_egg",
+    "unicopia:green_fried_egg",
     "unicopia:hive",
     "unicopia:dark_oak_stable_door",
-    "#unicopia:food_types/cooked_meat",
-    "#unicopia:food_types/raw_meat",
-    "#unicopia:food_types/raw_insect",
-    "#unicopia:food_types/rotten_meat",
-    "#unicopia:food_types/love"
+    "#c:cooked_meat",
+    "#c:raw_meat",
+    "#c:raw_insect",
+    "#c:rotten_meat",
+    "#unicopia:container_with_love"
   ]
 }
diff --git a/src/main/resources/data/unicopia/tags/items/groups/earth_pony.json b/src/main/resources/data/unicopia/tags/items/groups/earth_pony.json
index 51b9f951..c75fb733 100644
--- a/src/main/resources/data/unicopia/tags/items/groups/earth_pony.json
+++ b/src/main/resources/data/unicopia/tags/items/groups/earth_pony.json
@@ -52,6 +52,7 @@
     "unicopia:imported_oats",
     "unicopia:oatmeal",
     "unicopia:oatmeal_cookie",
+    "unicopia:chocolate_oatmeal_cookie",
     "unicopia:daffodil_daisy_sandwich",
     "unicopia:hay_burger",
     "unicopia:hay_fries",
@@ -61,6 +62,7 @@
     "unicopia:baited_fishing_rod",
     "unicopia:worm_block",
     "unicopia:muffin",
+    "unicopia:scone",
     "unicopia:acorn",
     "unicopia:pinecone",
     "unicopia:pinecone_cookie",
diff --git a/src/main/resources/data/unicopia/tags/items/groups/foraging.json b/src/main/resources/data/unicopia/tags/items/groups/foraging.json
index f50de618..92eb5eee 100644
--- a/src/main/resources/data/unicopia/tags/items/groups/foraging.json
+++ b/src/main/resources/data/unicopia/tags/items/groups/foraging.json
@@ -1,16 +1,16 @@
 {
   "replace": false,
   "values": [
-    "#unicopia:food_types/forage_dangerous",
-    "#unicopia:food_types/forage_edible_filling",
-    "#unicopia:food_types/forage_edible",
-    "#unicopia:food_types/forage_nauseating",
-    "#unicopia:food_types/forage_blinding",
-    "#unicopia:food_types/forage_prickly",
-    "#unicopia:food_types/forage_radioactive",
-    "#unicopia:food_types/forage_risky",
-    "#unicopia:food_types/forage_severely_nauseating",
-    "#unicopia:food_types/forage_severely_prickly",
-    "#unicopia:food_types/forage_strengthening"
+    "#unicopia:forage/dangerous",
+    "#unicopia:forage/filling",
+    "#unicopia:forage/safe",
+    "#unicopia:forage/nauseating",
+    "#unicopia:forage/blinding",
+    "#unicopia:forage/prickly",
+    "#unicopia:forage/glowing",
+    "#unicopia:forage/risky",
+    "#unicopia:forage/severe/nauseating",
+    "#unicopia:forage/severe/prickly",
+    "#unicopia:forage/strenghtening"
   ]
 }
diff --git a/src/main/resources/data/unicopia/tags/items/groups/pegasus.json b/src/main/resources/data/unicopia/tags/items/groups/pegasus.json
index b76a934d..269e51b9 100644
--- a/src/main/resources/data/unicopia/tags/items/groups/pegasus.json
+++ b/src/main/resources/data/unicopia/tags/items/groups/pegasus.json
@@ -24,8 +24,9 @@
     "unicopia:cloud_door",
     "unicopia:cloud_bed",
     "#unicopia:bed_sheets",
-    "#unicopia:food_types/raw_fish",
-    "#unicopia:food_types/cooked_fish",
+    "#c:raw_fish",
+    "#c:cooked_fish",
+    "#c:rotten_fish",
     "unicopia:rain_cloud_jar",
     "unicopia:storm_cloud_jar",
     "unicopia:lightning_jar",
diff --git a/src/main/resources/data/unicopia/tags/items/groups/sea_pony.json b/src/main/resources/data/unicopia/tags/items/groups/sea_pony.json
index a9259060..9aeefc68 100644
--- a/src/main/resources/data/unicopia/tags/items/groups/sea_pony.json
+++ b/src/main/resources/data/unicopia/tags/items/groups/sea_pony.json
@@ -2,10 +2,9 @@
   "replace": false,
   "values": [
     "unicopia:pearl_necklace",
-    "minecraft:nautilus_shell",
-    "#unicopia:food_types/shells",
-    "#unicopia:food_types/shelly",
-    "#unicopia:food_types/raw_sea_vegitable",
-    "#unicopia:food_types/cooked_sea_vegitable"
+    "#unicopia:shells",
+    "#unicopia:special_shells",
+    "#unicopia:food_types/low_quality_sea_vegetables",
+    "#unicopia:food_types/high_quality_sea_vegetables"
   ]
 }
diff --git a/src/main/resources/data/unicopia/traits/love.json b/src/main/resources/data/unicopia/traits/love.json
index 534e5a40..af8df4e3 100644
--- a/src/main/resources/data/unicopia/traits/love.json
+++ b/src/main/resources/data/unicopia/traits/love.json
@@ -2,7 +2,7 @@
   "replace": false,
   "traits": "happiness:10 kindness:10",
   "items": [
-    "#c:love",
+    "#unicopia:container_with_love",
     "#unicopia:clouds"
   ]
 }
\ No newline at end of file
diff --git a/src/main/resources/unicopia.mixin.json b/src/main/resources/unicopia.mixin.json
index 0a82eae8..855a75b7 100644
--- a/src/main/resources/unicopia.mixin.json
+++ b/src/main/resources/unicopia.mixin.json
@@ -19,6 +19,7 @@
     "MixinEnchantmentHelper",
     "MixinFallLocation",
     "MixinEntity",
+    "MixinEntityBucketItem",
     "MixinEntityView",
     "MixinEntityShapeContext",
     "MixinFallingBlock",