Move all remaining recipes to datagen.

Summary of changes:
 - Changed cutting recipe for etched clouds to require normal clouds
 - Added cutting recipe for cloud planks
 - Made the unstable cloud recipe shapeless
 - Unstable cloud recipe now outputs 8 blocks
 - Added recipes for stripped zap wood and waxed stripped zap wood
 - Made chitin<->carapace recipe reversible
 - Made gravel <-> pebbles recipe reversable
 - The sus gravel -> pebbles recipe is among us now
 - Changed chitin spikes recipe to give 8 instead of 1
 - Changed diamond to shard recipe to give 6 instead of 3
 - Added recipe to get 3 shards from amethyst shards
 - Made golden oak seeds obtainable by crafting a golden apple
 - Removed the complex cider recipe
 - The simple cider recipe now requires requires apple to craft
 - Increased experience gained from cooking zap apples
 - Made the zap apple jam jar recipe shapeless
 - Made the jam toast recipe shapeless
 - Added trick recipes for golden apple, mango, pineapple, and horseshoe fries
 - Added white bed sheets, and added a recipe to dye white bed sheets any color and pattern
 - Added recipes to change any bedsheet into any color or pattern using the right wool
This commit is contained in:
Sollace 2024-03-22 17:55:21 +00:00
parent a3c1248e9f
commit 07c8170652
No known key found for this signature in database
GPG key ID: E52FACE7B5C773DB
68 changed files with 745 additions and 614 deletions

View file

@ -17,6 +17,7 @@ import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.client.gui.ItemTraitsTooltipRenderer;
@ -256,6 +257,12 @@ public final class SpellTraits implements Iterable<Map.Entry<Trait, Float>> {
return fromEntries(streamFromJson(traits));
}
public static JsonElement toJson(SpellTraits traits) {
JsonObject json = new JsonObject();
traits.forEach(entry -> json.addProperty(entry.getKey().getId().toString(), entry.getValue()));
return json;
}
public static Optional<SpellTraits> fromPacketOrEmpty(PacketByteBuf buf) {
return buf.readOptional(SpellTraits::fromPacket).filter(SpellTraits::isPresent);
}

View file

@ -61,6 +61,13 @@ public enum Trait implements CommandArgumentEnum<Trait> {
private static final Map<String, Trait> REGISTRY = Arrays.stream(values()).collect(Collectors.toMap(Trait::name, Function.identity()));
private static final Map<Identifier, Trait> IDS = Arrays.stream(values()).collect(Collectors.toMap(Trait::getId, Function.identity()));
public static final com.mojang.serialization.Codec<Trait> CODEC = StringIdentifiable.createCodec(Trait::values, n -> Unicopia.id(n.toLowerCase(Locale.ROOT)).toString());
public static final com.mojang.serialization.Codec<Set<Trait>> SET_CODEC = CODEC.listOf().xmap(
l -> l.stream().distinct().collect(Collectors.toSet()),
s -> s.stream().toList()
);
private final Identifier id;
private final Identifier sprite;
private final TraitGroup group;

View file

@ -1,5 +1,6 @@
package com.minelittlepony.unicopia.ability.magic.spell.trait;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@ -10,6 +11,7 @@ import java.util.stream.Stream;
import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.advancement.UCriteria;
import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.network.Channel;
import com.minelittlepony.unicopia.network.MsgMarkTraitRead;
@ -76,8 +78,11 @@ public class TraitDiscovery implements NbtSerialisable, Copyable<TraitDiscovery>
});
unreadTraits.addAll(newTraits);
pony.setDirty();
if (!newTraits.isEmpty() && !pony.asWorld().isClient) {
Channel.UNLOCK_TRAITS.sendToPlayer(new MsgUnlockTraits(newTraits), (ServerPlayerEntity)pony.asEntity());
if (!newTraits.isEmpty()) {
if (!pony.asWorld().isClient) {
Channel.UNLOCK_TRAITS.sendToPlayer(new MsgUnlockTraits(newTraits), (ServerPlayerEntity)pony.asEntity());
}
UCriteria.TRAIT_DISCOVERED.trigger(pony.asEntity());
}
}
@ -103,6 +108,10 @@ public class TraitDiscovery implements NbtSerialisable, Copyable<TraitDiscovery>
return traits.contains(trait);
}
public boolean isKnown(Collection<Trait> traits) {
return traits.containsAll(traits);
}
@Environment(EnvType.CLIENT)
public void appendTooltip(ItemStack stack, @Nullable World world, List<Text> tooltip) {
SpellTraits.getEmbeddedTraits(stack)

View file

@ -0,0 +1,63 @@
package com.minelittlepony.unicopia.advancement;
import java.util.Set;
import com.google.gson.JsonObject;
import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
import com.minelittlepony.unicopia.entity.player.Pony;
import com.mojang.serialization.JsonOps;
import net.minecraft.advancement.criterion.AbstractCriterion;
import net.minecraft.advancement.criterion.AbstractCriterionConditions;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.predicate.entity.AdvancementEntityPredicateDeserializer;
import net.minecraft.predicate.entity.AdvancementEntityPredicateSerializer;
import net.minecraft.predicate.entity.LootContextPredicate;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.util.Identifier;
import net.minecraft.util.JsonHelper;
public class TraitDiscoveredCriterion extends AbstractCriterion<TraitDiscoveredCriterion.Conditions> {
private static final Identifier ID = Unicopia.id("trait_discovered");
@Override
public Identifier getId() {
return ID;
}
@Override
protected Conditions conditionsFromJson(JsonObject json, LootContextPredicate playerPredicate, AdvancementEntityPredicateDeserializer deserializer) {
return new Conditions(playerPredicate, Trait.SET_CODEC.decode(JsonOps.INSTANCE, JsonHelper.getArray(json, "traits")).result().get().getFirst());
}
public static Conditions create(Set<Trait> traits) {
return new Conditions(LootContextPredicate.EMPTY, traits);
}
public void trigger(PlayerEntity player) {
if (player instanceof ServerPlayerEntity) {
trigger((ServerPlayerEntity)player, c -> c.test((ServerPlayerEntity)player));
}
}
public static class Conditions extends AbstractCriterionConditions {
private final Set<Trait> traits;
public Conditions(LootContextPredicate playerPredicate, Set<Trait> traits) {
super(ID, playerPredicate);
this.traits = traits;
}
public boolean test(ServerPlayerEntity player) {
return Pony.of(player).getDiscoveries().isKnown(traits);
}
@Override
public JsonObject toJson(AdvancementEntityPredicateSerializer serializer) {
JsonObject json = super.toJson(serializer);
json.add("traits", Trait.SET_CODEC.encodeStart(JsonOps.INSTANCE, traits).result().get());
return json;
}
}
}

View file

@ -6,6 +6,7 @@ public interface UCriteria {
CustomEventCriterion CUSTOM_EVENT = Criteria.register(new CustomEventCriterion());
RaceChangeCriterion PLAYER_CHANGE_RACE = Criteria.register(new RaceChangeCriterion());
SendViaDragonBreathScrollCriterion SEND_DRAGON_BREATH = Criteria.register(new SendViaDragonBreathScrollCriterion());
TraitDiscoveredCriterion TRAIT_DISCOVERED = Criteria.register(new TraitDiscoveredCriterion());
CustomEventCriterion.Trigger LOOK_INTO_SUN = CUSTOM_EVENT.createTrigger("look_into_sun");
CustomEventCriterion.Trigger WEAR_SHADES = CUSTOM_EVENT.createTrigger("wear_shades");

View file

@ -7,10 +7,10 @@ import com.minelittlepony.unicopia.datagen.providers.SeasonsGrowthRatesProvider;
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.URecipeProvider;
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.recipe.URecipeProvider;
import com.minelittlepony.unicopia.server.world.UWorldGen;
import net.fabricmc.fabric.api.datagen.v1.DataGeneratorEntrypoint;

View file

@ -1,4 +1,4 @@
package com.minelittlepony.unicopia.datagen.providers;
package com.minelittlepony.unicopia.datagen.providers.recipe;
import java.util.Arrays;
import java.util.HashMap;

View file

@ -0,0 +1,55 @@
package com.minelittlepony.unicopia.datagen.providers.recipe;
import java.util.function.Consumer;
import com.google.gson.JsonObject;
import com.minelittlepony.unicopia.Unicopia;
import net.minecraft.data.server.recipe.RecipeJsonProvider;
import net.minecraft.item.ItemConvertible;
import net.minecraft.recipe.Ingredient;
import net.minecraft.recipe.RecipeSerializer;
import net.minecraft.util.Identifier;
public class ComplexSpellcraftingRecipeJsonBuilder {
private final RecipeSerializer<?> serializer;
private final ItemConvertible material;
public ComplexSpellcraftingRecipeJsonBuilder(RecipeSerializer<?> serializer, ItemConvertible material) {
this.serializer = serializer;
this.material = material;
}
public static ComplexSpellcraftingRecipeJsonBuilder create(RecipeSerializer<?> serializer, ItemConvertible material) {
return new ComplexSpellcraftingRecipeJsonBuilder(serializer, material);
}
public void offerTo(Consumer<RecipeJsonProvider> exporter, final String recipeId) {
exporter.accept(new RecipeJsonProvider() {
@Override
public void serialize(JsonObject json) {
json.add("material", Ingredient.ofItems(material).toJson());
}
@Override
public Identifier getRecipeId() {
return Unicopia.id(recipeId);
}
@Override
public RecipeSerializer<?> getSerializer() {
return serializer;
}
@Override
public JsonObject toAdvancementJson() {
return null;
}
@Override
public Identifier getAdvancementId() {
return new Identifier("");
}
});
}
}

View file

@ -1,17 +1,24 @@
package com.minelittlepony.unicopia.datagen;
package com.minelittlepony.unicopia.datagen.providers.recipe;
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.mojang.datafixers.util.Either;
import net.fabricmc.fabric.api.tag.convention.v1.ConventionalItemTags;
import net.minecraft.advancement.criterion.InventoryChangedCriterion;
import net.minecraft.data.server.recipe.RecipeProvider;
import net.minecraft.data.server.recipe.ShapedRecipeJsonBuilder;
import net.minecraft.data.server.recipe.SingleItemRecipeJsonBuilder;
import net.minecraft.data.server.recipe.VanillaRecipeProvider;
import net.minecraft.item.Item;
import net.minecraft.item.ItemConvertible;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.predicate.item.ItemPredicate;
import net.minecraft.recipe.Ingredient;
import net.minecraft.recipe.book.RecipeCategory;
import net.minecraft.registry.Registries;
import net.minecraft.registry.tag.ItemTags;
import net.minecraft.registry.tag.TagKey;
@ -62,4 +69,22 @@ public interface CraftingMaterialHelper {
static String hasTag(TagKey<Item> tag) {
return "has_" + tag.id();
}
static InventoryChangedCriterion.Conditions conditionsFromSpell(ItemConvertible gem, SpellType<?> spell) {
NbtCompound nbt = new NbtCompound();
nbt.putString("spell", spell.getId().toString());
return RecipeProvider.conditionsFromItemPredicates(ItemPredicate.Builder.create()
.items(gem)
.nbt(nbt)
.build()
);
}
static String hasSpell(SpellType<?> spell) {
return "has_" + spell.getId() + "_gemstone";
}
static SingleItemRecipeJsonBuilder createCloudShaping(Ingredient input, RecipeCategory category, ItemConvertible output, int count) {
return new SingleItemRecipeJsonBuilder(category, URecipes.CLOUD_SHAPING_SERIALIZER, input, output, count);
}
}

View file

@ -0,0 +1,131 @@
package com.minelittlepony.unicopia.datagen.providers.recipe;
import java.util.Objects;
import java.util.function.Consumer;
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.mojang.serialization.JsonOps;
import net.minecraft.advancement.Advancement;
import net.minecraft.advancement.AdvancementRewards;
import net.minecraft.advancement.CriterionMerger;
import net.minecraft.advancement.criterion.CriterionConditions;
import net.minecraft.advancement.criterion.RecipeUnlockedCriterion;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.data.server.recipe.CraftingRecipeJsonBuilder;
import net.minecraft.data.server.recipe.RecipeJsonProvider;
import net.minecraft.recipe.RecipeSerializer;
import net.minecraft.recipe.book.RecipeCategory;
import net.minecraft.registry.Registries;
import net.minecraft.util.Identifier;
public class GrowingRecipeJsonBuilder {
private final Advancement.Builder advancementBuilder = Advancement.Builder.createUntelemetered();
@Nullable
private String group;
private final RecipeCategory category;
private final BlockState output;
private Block target;
private BlockState fuel;
public static GrowingRecipeJsonBuilder create(RecipeCategory category, BlockState output) {
return new GrowingRecipeJsonBuilder(category, output);
}
protected GrowingRecipeJsonBuilder(RecipeCategory category, BlockState output) {
this.category = category;
this.output = output;
}
public GrowingRecipeJsonBuilder target(Block target) {
this.target = target;
return this;
}
public GrowingRecipeJsonBuilder fuel(BlockState fuel) {
this.fuel = fuel;
return this;
}
public GrowingRecipeJsonBuilder criterion(String name, CriterionConditions condition) {
advancementBuilder.criterion(name, condition);
return this;
}
public GrowingRecipeJsonBuilder group(String group) {
this.group = group;
return this;
}
public void offerTo(Consumer<RecipeJsonProvider> exporter, Identifier id) {
Preconditions.checkState(!advancementBuilder.getCriteria().isEmpty(), "No way of obtaining recipe " + id);
advancementBuilder
.parent(CraftingRecipeJsonBuilder.ROOT)
.criterion("has_the_recipe", RecipeUnlockedCriterion.create(id))
.rewards(AdvancementRewards.Builder.recipe(id))
.criteriaMerger(CriterionMerger.OR);
exporter.accept(new JsonProvider(id, id.withPrefixedPath("recipes/" + category.getName() + "/"), group, target, fuel));
}
public void offerTo(Consumer<RecipeJsonProvider> exporter) {
offerTo(exporter, Registries.BLOCK.getId(output.getBlock()));
}
public void offerTo(Consumer<RecipeJsonProvider> exporter, String recipePath) {
Identifier recipeId = new Identifier(recipePath);
Identifier id = Registries.BLOCK.getId(output.getBlock());
if (recipeId.equals(id)) {
throw new IllegalStateException("Recipe " + recipePath + " should remove its 'save' argument as it is equal to default one");
}
offerTo(exporter, recipeId);
}
private class JsonProvider implements RecipeJsonProvider {
private final Identifier recipeId;
private final Identifier advancementId;
private final String group;
private final Block target;
private final BlockState fuel;
JsonProvider(Identifier recipeId, Identifier advancementId, String group, Block target, BlockState fuel) {
this.recipeId = recipeId;
this.advancementId = advancementId;
this.group = group;
this.target = Objects.requireNonNull(target, "Target");
this.fuel = Objects.requireNonNull(fuel, "Fuel");
}
@Override
public void serialize(JsonObject json) {
json.addProperty("group", group);
json.addProperty("target", Registries.BLOCK.getId(target).toString());
json.add("consume", BlockState.CODEC.encodeStart(JsonOps.INSTANCE, fuel).result().get());
json.add("output", BlockState.CODEC.encodeStart(JsonOps.INSTANCE, output).result().get());
}
@Override
public Identifier getRecipeId() {
return recipeId;
}
@Override
public RecipeSerializer<?> getSerializer() {
return URecipes.TRANSFORM_CROP_SERIALIZER;
}
@Override
public JsonObject toAdvancementJson() {
return advancementBuilder.toJson();
}
@Override
public Identifier getAdvancementId() {
return advancementId;
}
}
}

View file

@ -0,0 +1,163 @@
package com.minelittlepony.unicopia.datagen.providers.recipe;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.include.com.google.common.base.Preconditions;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
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 net.minecraft.advancement.Advancement;
import net.minecraft.advancement.AdvancementRewards;
import net.minecraft.advancement.CriterionMerger;
import net.minecraft.advancement.criterion.CriterionConditions;
import net.minecraft.advancement.criterion.RecipeUnlockedCriterion;
import net.minecraft.data.server.recipe.CraftingRecipeJsonBuilder;
import net.minecraft.data.server.recipe.RecipeJsonProvider;
import net.minecraft.item.ItemConvertible;
import net.minecraft.recipe.RecipeSerializer;
import net.minecraft.recipe.book.RecipeCategory;
import net.minecraft.util.Identifier;
public class SpellcraftingRecipeJsonBuilder {
private final Advancement.Builder advancementBuilder = Advancement.Builder.createUntelemetered();
@Nullable
private String group;
private final RecipeCategory category;
private EnchantedIngredient base = new EnchantedIngredient(UItems.GEMSTONE, SpellType.EMPTY_KEY);
private final EnchantedIngredient output;
private final List<EnchantedIngredient> ingredients = new ArrayList<>();
private SpellTraits traits = SpellTraits.EMPTY;
public static SpellcraftingRecipeJsonBuilder create(RecipeCategory category, ItemConvertible gem, SpellType<?> spell) {
return new SpellcraftingRecipeJsonBuilder(category, new EnchantedIngredient(gem, spell));
}
protected SpellcraftingRecipeJsonBuilder(RecipeCategory category, EnchantedIngredient output) {
this.category = category;
this.output = output;
}
public SpellcraftingRecipeJsonBuilder base(ItemConvertible gem, SpellType<?> spell) {
base = new EnchantedIngredient(gem, spell);
return this;
}
public SpellcraftingRecipeJsonBuilder input(ItemConvertible gem, SpellType<?> spell) {
ingredients.add(new EnchantedIngredient(gem, spell));
return this;
}
public SpellcraftingRecipeJsonBuilder traits(SpellTraits.Builder traits) {
this.traits = traits.build();
return this;
}
public SpellcraftingRecipeJsonBuilder criterion(String name, CriterionConditions condition) {
advancementBuilder.criterion(name, condition);
return this;
}
public SpellcraftingRecipeJsonBuilder group(String group) {
this.group = group;
return this;
}
public void offerTo(Consumer<RecipeJsonProvider> exporter, Identifier id) {
if (!traits.isEmpty()) {
advancementBuilder.criterion("has_traits", TraitDiscoveredCriterion.create(traits.stream().map(Map.Entry::getKey).collect(Collectors.toUnmodifiableSet())));
}
Preconditions.checkState(!advancementBuilder.getCriteria().isEmpty(), "No way of obtaining recipe " + id);
advancementBuilder
.parent(CraftingRecipeJsonBuilder.ROOT)
.criterion("has_the_recipe", RecipeUnlockedCriterion.create(id))
.rewards(AdvancementRewards.Builder.recipe(id))
.criteriaMerger(CriterionMerger.OR);
exporter.accept(new JsonProvider(id, id.withPrefixedPath("recipes/" + category.getName() + "/"), group, ingredients, traits));
}
public void offerTo(Consumer<RecipeJsonProvider> exporter) {
offerTo(exporter, output.spell().getId());
}
public void offerTo(Consumer<RecipeJsonProvider> exporter, String recipePath) {
Identifier recipeId = new Identifier(recipePath);
if (recipeId.equals(output.spell().getId())) {
throw new IllegalStateException("Recipe " + recipePath + " should remove its 'save' argument as it is equal to default one");
}
offerTo(exporter, recipeId);
}
record EnchantedIngredient (ItemConvertible gem, SpellType<?> spell) {
JsonObject toJson(JsonObject json) {
json.addProperty("item", CraftingRecipeJsonBuilder.getItemId(gem).toString());
if (!spell.isEmpty()) {
json.addProperty("spell", spell.getId().toString());
}
return json;
}
}
private class JsonProvider implements RecipeJsonProvider {
private final Identifier recipeId;
private final Identifier advancementId;
private final String group;
private final List<EnchantedIngredient> ingredients;
private final SpellTraits traits;
JsonProvider(Identifier recipeId, Identifier advancementId, String group, List<EnchantedIngredient> ingredients, SpellTraits traits) {
this.recipeId = recipeId;
this.advancementId = advancementId;
this.group = group;
this.ingredients = new ArrayList<>(ingredients);
this.traits = traits;
}
@Override
public void serialize(JsonObject json) {
json.addProperty("group", group);
json.add("material", base.toJson(new JsonObject()));
json.add("result", output.toJson(new JsonObject()));
JsonArray ingredientsJson = new JsonArray();
ingredients.forEach(ingredient -> {
ingredientsJson.add(ingredient.toJson(new JsonObject()));
});
json.add("ingredients", ingredientsJson);
JsonObject traitsJson = new JsonObject();
traits.forEach(entry -> {
traitsJson.addProperty(entry.getKey().getId().toString(), entry.getValue());
});
json.add("traits", traitsJson);
}
@Override
public Identifier getRecipeId() {
return recipeId;
}
@Override
public RecipeSerializer<?> getSerializer() {
return URecipes.TRAIT_REQUIREMENT;
}
@Override
public JsonObject toAdvancementJson() {
return advancementBuilder.toJson();
}
@Override
public Identifier getAdvancementId() {
return advancementId;
}
}
}

View file

@ -0,0 +1,129 @@
package com.minelittlepony.unicopia.datagen.providers.recipe;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.include.com.google.common.base.Preconditions;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import net.minecraft.advancement.Advancement;
import net.minecraft.advancement.AdvancementRewards;
import net.minecraft.advancement.CriterionMerger;
import net.minecraft.advancement.criterion.CriterionConditions;
import net.minecraft.advancement.criterion.RecipeUnlockedCriterion;
import net.minecraft.data.server.recipe.CraftingRecipeJsonBuilder;
import net.minecraft.data.server.recipe.RecipeJsonBuilder;
import net.minecraft.data.server.recipe.RecipeJsonProvider;
import net.minecraft.item.Item;
import net.minecraft.item.ItemConvertible;
import net.minecraft.recipe.Ingredient;
import net.minecraft.recipe.RecipeSerializer;
import net.minecraft.recipe.book.CraftingRecipeCategory;
import net.minecraft.recipe.book.RecipeCategory;
import net.minecraft.registry.Registries;
import net.minecraft.util.Identifier;
public class TrickCraftingRecipeJsonBuilder extends RecipeJsonBuilder implements CraftingRecipeJsonBuilder {
private final Advancement.Builder advancementBuilder = Advancement.Builder.createUntelemetered();
@Nullable
private String group;
private final RecipeCategory category;
private final Item output;
private final List<Ingredient> inputs = new ArrayList<>();
public TrickCraftingRecipeJsonBuilder(RecipeCategory category, ItemConvertible output) {
this.category = category;
this.output = output.asItem();
}
public static TrickCraftingRecipeJsonBuilder create(RecipeCategory category, ItemConvertible output) {
return new TrickCraftingRecipeJsonBuilder(category, output);
}
@Override
public Item getOutputItem() {
return output;
}
public TrickCraftingRecipeJsonBuilder input(ItemConvertible input) {
inputs.add(Ingredient.ofItems(input));
return this;
}
@Override
public TrickCraftingRecipeJsonBuilder criterion(String name, CriterionConditions condition) {
advancementBuilder.criterion(name, condition);
return this;
}
@Override
public TrickCraftingRecipeJsonBuilder group(String group) {
this.group = group;
return this;
}
@Override
public void offerTo(Consumer<RecipeJsonProvider> exporter, Identifier id) {
Preconditions.checkState(!advancementBuilder.getCriteria().isEmpty(), "No way of obtaining recipe " + id);
advancementBuilder
.parent(CraftingRecipeJsonBuilder.ROOT)
.criterion("has_the_recipe", RecipeUnlockedCriterion.create(id))
.rewards(AdvancementRewards.Builder.recipe(id))
.criteriaMerger(CriterionMerger.OR);
exporter.accept(new JsonProvider(id, id.withPrefixedPath("recipes/" + category.getName() + "/"), group == null ? "" : group, inputs));
}
private class JsonProvider extends RecipeJsonBuilder.CraftingRecipeJsonProvider {
private final Identifier recipeId;
private final String group;
private final List<Ingredient> inputs;
private final Identifier advancementId;
protected JsonProvider(Identifier recipeId, Identifier advancementId, String group, List<Ingredient> inputs) {
super(CraftingRecipeCategory.MISC);
this.recipeId = recipeId;
this.advancementId = advancementId;
this.group = group;
this.inputs = new ArrayList<>(inputs);
}
@Override
public void serialize(JsonObject json) {
super.serialize(json);
if (!group.isEmpty()) {
json.addProperty("group", group);
}
JsonArray jsonArray = new JsonArray();
for (Ingredient ingredient : inputs) {
jsonArray.add(ingredient.toJson());
}
json.add("ingredients", jsonArray);
json.addProperty("appearance", Registries.ITEM.getId(output).toString());
}
@Override
public RecipeSerializer<?> getSerializer() {
return RecipeSerializer.SHAPELESS;
}
@Override
public Identifier getRecipeId() {
return this.recipeId;
}
@Override
@Nullable
public JsonObject toAdvancementJson() {
return advancementBuilder.toJson();
}
@Override
@Nullable
public Identifier getAdvancementId() {
return advancementId;
}
}
}

View file

@ -1,4 +1,4 @@
package com.minelittlepony.unicopia.datagen.providers;
package com.minelittlepony.unicopia.datagen.providers.recipe;
import java.util.Arrays;
import java.util.List;
@ -8,13 +8,16 @@ import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.UConventionalTags;
import com.minelittlepony.unicopia.UTags;
import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
import com.minelittlepony.unicopia.block.UBlocks;
import com.minelittlepony.unicopia.datagen.CraftingMaterialHelper;
import com.minelittlepony.unicopia.datagen.ItemFamilies;
import com.minelittlepony.unicopia.datagen.UBlockFamilies;
import com.minelittlepony.unicopia.datagen.providers.BedSheetPatternRecipeBuilder.PatternTemplate;
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.server.world.UTreeGen;
import com.mojang.datafixers.util.Either;
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
@ -25,6 +28,7 @@ import net.minecraft.block.Block;
import net.minecraft.block.Blocks;
import net.minecraft.data.server.recipe.ComplexRecipeJsonBuilder;
import net.minecraft.data.server.recipe.RecipeJsonProvider;
import net.minecraft.data.server.recipe.RecipeProvider;
import net.minecraft.data.server.recipe.ShapedRecipeJsonBuilder;
import net.minecraft.data.server.recipe.ShapelessRecipeJsonBuilder;
import net.minecraft.item.Item;
@ -54,6 +58,7 @@ public class URecipeProvider extends FabricRecipeProvider {
offerCloudRecipes(exporter);
offerFoodRecipes(exporter);
offerGemstoneAndMagicRecipes(exporter);
offerMagicSpellRecipes(exporter);
offerSeaponyRecipes(exporter);
offerEarthPonyRecipes(exporter);
@ -102,11 +107,33 @@ public class URecipeProvider extends FabricRecipeProvider {
offer2x2CompactingRecipe(exporter, RecipeCategory.DECORATIONS, UBlocks.SHAPING_BENCH, UBlocks.DENSE_CLOUD);
generateFamily(exporter, UBlockFamilies.CLOUD_BRICKS);
offerCloudShapingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, UBlocks.CARVED_CLOUD, UBlocks.CLOUD);
offerCloudShapingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, UBlocks.ETCHED_CLOUD, UBlocks.CLOUD);
offerCloudShapingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, UBlocks.CLOUD_BRICKS, UBlocks.CLOUD);
offerCloudShapingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, UBlocks.CLOUD_PLANKS, UBlocks.CLOUD);
offerCloudShapingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, UBlocks.CLOUD_PILLAR, UBlocks.CLOUD);
// TODO: Cut Cloud, Smooth Cloud, Polished Cloud, Raked Cloud
offerCloudShapingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, UBlocks.CLOUD_SLAB, UBlocks.CLOUD, 2);
offerCloudShapingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, UBlocks.CLOUD_STAIRS, UBlocks.CLOUD);
offerCloudShapingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, UBlocks.CLOUD_BRICK_SLAB, UBlocks.CLOUD_BRICKS, 2);
offerCloudShapingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, UBlocks.CLOUD_BRICK_STAIRS, UBlocks.CLOUD_BRICKS);
offerCloudShapingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, UBlocks.CLOUD_PLANK_SLAB, UBlocks.CLOUD_PLANKS, 2);
offerCloudShapingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, UBlocks.CLOUD_PLANK_STAIRS, UBlocks.CLOUD_PLANKS);
offerCloudShapingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, UBlocks.DENSE_CLOUD_SLAB, UBlocks.DENSE_CLOUD, 2);
offerCloudShapingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, UBlocks.DENSE_CLOUD_STAIRS, UBlocks.DENSE_CLOUD);
offerCloudShapingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, UBlocks.ETCHED_CLOUD_SLAB, UBlocks.ETCHED_CLOUD, 2);
offerCloudShapingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, UBlocks.ETCHED_CLOUD_STAIRS, UBlocks.ETCHED_CLOUD);
offerCompactingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, UBlocks.DENSE_CLOUD, UBlocks.CLOUD, 4);
generateFamily(exporter, UBlockFamilies.DENSE_CLOUD);
offer2x3Recipe(exporter, UBlocks.CLOUD_DOOR, UBlocks.DENSE_CLOUD, "door");
// XXX: Make the unstable cloud recipe shapeless and change output to 8 (to align with making jam toast)
ShapelessRecipeJsonBuilder.create(RecipeCategory.REDSTONE, UBlocks.UNSTABLE_CLOUD, 8)
.input(UBlocks.CLOUD, 8)
.input(Ingredient.ofItems(UItems.LIGHTNING_JAR, UItems.ZAP_APPLE_JAM_JAR))
@ -129,7 +156,6 @@ public class URecipeProvider extends FabricRecipeProvider {
generateFamily(exporter, UBlockFamilies.ZAP);
offerPlanksRecipe(exporter, UBlocks.ZAP_PLANKS, UTags.Items.ZAP_LOGS, 4);
offerBarkBlockRecipe(exporter, UBlocks.ZAP_WOOD, UBlocks.ZAP_LOG);
// XXX: fixed not being able to craft stripped zap wood and waxed stripped zap wood
offerBarkBlockRecipe(exporter, UBlocks.STRIPPED_ZAP_WOOD, UBlocks.STRIPPED_ZAP_LOG);
// waxed zap wood
@ -147,12 +173,10 @@ public class URecipeProvider extends FabricRecipeProvider {
}
private void offerChitinBlocksRecipes(Consumer<RecipeJsonProvider> exporter) {
// XXX: Changed chitin recipe to be reversible
offerReversibleCompactingRecipes(exporter, RecipeCategory.BUILDING_BLOCKS, UItems.CARAPACE, RecipeCategory.BUILDING_BLOCKS, UBlocks.CHITIN);
generateFamily(exporter, UBlockFamilies.CHISELED_CHITIN);
offerHiveRecipe(exporter, UBlocks.HIVE, UBlocks.CHITIN, UBlocks.MYSTERIOUS_EGG);
offerHullRecipe(exporter, UBlocks.CHISELLED_CHITIN_HULL, UBlocks.CHISELLED_CHITIN, UBlocks.CHITIN);
// XXX: Changed spikes recipe to give 8 instead of 1
offerSpikesRecipe(exporter, UBlocks.CHITIN_SPIKES, UBlocks.CHITIN);
// TODO: polished chitin
@ -164,9 +188,7 @@ public class URecipeProvider extends FabricRecipeProvider {
}
private void offerGemstoneAndMagicRecipes(Consumer<RecipeJsonProvider> exporter) {
// XXX: Change diamond to shard recipe to give 6 instead of 3
offerShapelessRecipe(exporter, UItems.CRYSTAL_SHARD, Items.DIAMOND, "crystal_shard", 6);
// XXX: Added recipe to get shards from amethyst shards
offerShapelessRecipe(exporter, UItems.CRYSTAL_SHARD, Items.AMETHYST_SHARD, "crystal_shard", 3);
offer2x2CompactingRecipe(exporter, RecipeCategory.MISC, UItems.GEMSTONE, UItems.CRYSTAL_SHARD);
ShapelessRecipeJsonBuilder.create(RecipeCategory.MISC, UItems.SPELLBOOK)
@ -206,14 +228,6 @@ public class URecipeProvider extends FabricRecipeProvider {
.pattern("*#*")
.offerTo(exporter);
// unicorn amulet
/*ShapelessRecipeJsonBuilder.create(RecipeCategory.TOOLS, UItems.UNICORN_AMULET)
.input(UItems.PEGASUS_AMULET)
.input(UItems.CRYSTAL_HEART)
.input(UItems.GROGARS_BELL)
.input(Items.TOTEM_OF_UNDYING)
.offerTo(exporter);*/
// friendship bracelet
ShapedRecipeJsonBuilder.create(RecipeCategory.TOOLS, UItems.FRIENDSHIP_BRACELET)
.input('*', Items.STRING)
@ -235,12 +249,65 @@ public class URecipeProvider extends FabricRecipeProvider {
offerShapelessRecipe(exporter, Items.STICK, UItems.MEADOWBROOKS_STAFF, "stick", 2);
}
private void offerMagicSpellRecipes(Consumer<RecipeJsonProvider> exporter) {
offerSpell(exporter, UItems.GEMSTONE, SpellType.DISPLACEMENT, new SpellTraits.Builder().with(Trait.KNOWLEDGE, 10).with(Trait.CHAOS, 10));
offerSpell(exporter, UItems.GEMSTONE, SpellType.FROST, new SpellTraits.Builder().with(Trait.ICE, 10));
offerSpell(exporter, UItems.GEMSTONE, SpellType.SCORCH, new SpellTraits.Builder().with(Trait.FIRE, 10));
offerSpell(exporter, UItems.GEMSTONE, SpellType.SHIELD, new SpellTraits.Builder().with(Trait.STRENGTH, 10).with(Trait.FOCUS, 6).with(Trait.POWER, 10));
offerSpell(exporter, UItems.GEMSTONE, SpellType.TRANSFORMATION, new SpellTraits.Builder().with(Trait.KNOWLEDGE, 10).with(Trait.LIFE, 10).with(Trait.CHAOS, 4));
offerSpellFromSpell(exporter, UItems.GEMSTONE, SpellType.ARCANE_PROTECTION, SpellType.SHIELD, new SpellTraits.Builder().with(Trait.STRENGTH, 10).with(Trait.KNOWLEDGE, 18).with(Trait.DARKNESS, 1));
offerSpellFromSpell(exporter, UItems.GEMSTONE, SpellType.BUBBLE, SpellType.CATAPULT, new SpellTraits.Builder().with(Trait.WATER, 9).with(Trait.AIR, 9));
offerSpellFromSpell(exporter, UItems.GEMSTONE, SpellType.CATAPULT, SpellType.FLAME, new SpellTraits.Builder().with(Trait.FOCUS, 9).with(Trait.AIR, 9));
offerSpellFromSpell(exporter, UItems.GEMSTONE, SpellType.CHILLING_BREATH, SpellType.FROST, new SpellTraits.Builder().with(Trait.ICE, 5).with(Trait.KNOWLEDGE, 10));
offerSpellFromSpell(exporter, UItems.GEMSTONE, SpellType.DARK_VORTEX, SpellType.VORTEX, new SpellTraits.Builder().with(Trait.STRENGTH, 10).with(Trait.KNOWLEDGE, 8).with(Trait.DARKNESS, 9).with(Trait.CHAOS, 8));
offerSpellFromSpell(exporter, UItems.GEMSTONE, SpellType.FEATHER_FALL, SpellType.SHIELD, new SpellTraits.Builder().with(Trait.KNOWLEDGE, 20).with(Trait.LIFE, 10).with(Trait.CHAOS, 4).with(Trait.GENEROSITY, 10));
offerSpellFromSpell(exporter, UItems.GEMSTONE, SpellType.FIRE_BOLT, SpellType.FLAME, new SpellTraits.Builder().with(Trait.FOCUS, 9).with(Trait.FIRE, 30));
offerSpellFromSpell(exporter, UItems.GEMSTONE, SpellType.FLAME, SpellType.SCORCH, new SpellTraits.Builder().with(Trait.FIRE, 15));
offerSpellFromSpell(exporter, UItems.GEMSTONE, SpellType.INFERNAL, SpellType.FLAME, new SpellTraits.Builder().with(Trait.FIRE, 50).with(Trait.DARKNESS, 10));
offerSpellFromSpell(exporter, UItems.GEMSTONE, SpellType.LIGHT, SpellType.FIRE_BOLT, new SpellTraits.Builder().with(Trait.ICE, 30).with(Trait.LIFE, 30).with(Trait.FOCUS, 10));
offerSpellFromSpell(exporter, UItems.GEMSTONE, SpellType.MIMIC, SpellType.TRANSFORMATION, new SpellTraits.Builder().with(Trait.KNOWLEDGE, 19).with(Trait.LIFE, 10).with(Trait.CHAOS, 4));
offerSpellFromSpell(exporter, UItems.GEMSTONE, SpellType.MIND_SWAP, SpellType.MIMIC, new SpellTraits.Builder().with(Trait.KNOWLEDGE, 19).with(Trait.LIFE, 10).with(Trait.CHAOS, 40));
offerSpellFromSpell(exporter, UItems.GEMSTONE, SpellType.NECROMANCY, SpellType.SIPHONING, new SpellTraits.Builder().with(Trait.STRENGTH, 10).with(Trait.KNOWLEDGE, 8).with(Trait.DARKNESS, 19).with(Trait.CHAOS, 8).with(Trait.BLOOD, 10).with(Trait.POISON, 9));
offerSpellFromSpell(exporter, UItems.GEMSTONE, SpellType.REVEALING, SpellType.SHIELD, new SpellTraits.Builder().with(Trait.KNOWLEDGE, 18).with(Trait.LIFE, 1).with(Trait.ORDER, 4));
offerSpellFromSpell(exporter, UItems.GEMSTONE, SpellType.SIPHONING, SpellType.INFERNAL, new SpellTraits.Builder().with(Trait.BLOOD, 8).with(Trait.POISON, 10));
offerSpellFromSpell(exporter, UItems.GEMSTONE, SpellType.VORTEX, SpellType.SHIELD, new SpellTraits.Builder().with(Trait.STRENGTH, 10).with(Trait.KNOWLEDGE, 8).with(Trait.AIR, 9));
offerSpellFromTwoSpells(exporter, UItems.GEMSTONE, SpellType.DISPEL_EVIL, SpellType.ARCANE_PROTECTION, SpellType.DISPLACEMENT, new SpellTraits.Builder().with(Trait.KINDNESS, 1).with(Trait.POWER, 1));
offerSpellFromTwoSpells(exporter, UItems.GEMSTONE, SpellType.HYDROPHOBIC, SpellType.FROST, SpellType.SHIELD, new SpellTraits.Builder().with(Trait.FOCUS, 6));
offerSpellFromTwoSpells(exporter, UItems.GEMSTONE, SpellType.PORTAL, SpellType.DISPLACEMENT, SpellType.DARK_VORTEX, new SpellTraits.Builder().with(Trait.KNOWLEDGE, 18).with(Trait.CHAOS, 20));
SpellcraftingRecipeJsonBuilder.create(RecipeCategory.MISC, UItems.ALICORN_AMULET, SpellType.EMPTY_KEY)
.base(UItems.GEMSTONE, SpellType.DARK_VORTEX)
.traits(new SpellTraits.Builder().with(Trait.DARKNESS, 30).with(Trait.POWER, 30).with(Trait.BLOOD, 30))
.offerTo(exporter, "alicorn_amulet");
SpellcraftingRecipeJsonBuilder.create(RecipeCategory.MISC, UItems.UNICORN_AMULET, SpellType.EMPTY_KEY)
.base(UItems.BROKEN_ALICORN_AMULET, SpellType.EMPTY_KEY)
.input(UItems.PEGASUS_AMULET, SpellType.EMPTY_KEY)
.input(UItems.CRYSTAL_HEART, SpellType.EMPTY_KEY)
.input(UItems.GROGARS_BELL, SpellType.EMPTY_KEY)
.input(Items.TOTEM_OF_UNDYING, SpellType.EMPTY_KEY)
.traits(new SpellTraits.Builder())
.criterion(hasItem(UItems.BROKEN_ALICORN_AMULET), conditionsFromItem(UItems.BROKEN_ALICORN_AMULET))
.offerTo(exporter, "unicorn_amulet");
SpellcraftingRecipeJsonBuilder.create(RecipeCategory.MISC, UItems.DRAGON_BREATH_SCROLL, SpellType.EMPTY_KEY)
.base(Items.PAPER, SpellType.EMPTY_KEY)
.input(Items.PAPER, SpellType.EMPTY_KEY)
.traits(new SpellTraits.Builder().with(Trait.FIRE, 1))
.offerTo(exporter, "dragon_breath_scroll");
ComplexSpellcraftingRecipeJsonBuilder.create(URecipes.SPELL_DUPLICATING, UItems.BOTCHED_GEM).offerTo(exporter, "spell_duplicating");
ComplexSpellcraftingRecipeJsonBuilder.create(URecipes.TRAIT_COMBINING, UItems.BOTCHED_GEM).offerTo(exporter, "trait_combining_botched_gem");
ComplexSpellcraftingRecipeJsonBuilder.create(URecipes.TRAIT_COMBINING, UItems.GEMSTONE).offerTo(exporter, "trait_combining_gemstone");
}
private void offerFoodRecipes(Consumer<RecipeJsonProvider> exporter) {
offerShapelessRecipe(exporter, UItems.PINEAPPLE_CROWN, UItems.PINEAPPLE, "seeds", 1);
offerShapelessRecipe(exporter, UItems.SWEET_APPLE_SEEDS, UItems.SWEET_APPLE, "seeds", 3);
offerShapelessRecipe(exporter, UItems.SOUR_APPLE_SEEDS, UItems.SOUR_APPLE, "seeds", 3);
offerShapelessRecipe(exporter, UItems.GREEN_APPLE_SEEDS, UItems.GREEN_APPLE, "seeds", 3);
// XXX: Made golden oak seeds obtainable by crafting
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);
@ -258,7 +325,6 @@ public class URecipeProvider extends FabricRecipeProvider {
.group("juice")
.offerTo(exporter);
appendIngredients(ShapelessRecipeJsonBuilder.create(RecipeCategory.FOOD, UItems.MUFFIN), Items.SUGAR, Items.EGG, Items.POTATO, UItems.JUICE, UItems.WHEAT_WORMS).offerTo(exporter);
// XXX: Removed the complex cider recipe
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))
@ -266,7 +332,6 @@ public class URecipeProvider extends FabricRecipeProvider {
.pattern("* *")
.pattern(" # ")
.offerTo(exporter);
// XXX: Changed the simple cider recipe to require apples
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))
.offerTo(exporter);
@ -308,25 +373,42 @@ public class URecipeProvider extends FabricRecipeProvider {
offerSmelting(exporter, List.of(UItems.TOAST), RecipeCategory.FOOD, UItems.BURNED_TOAST, 0.2F, 30, "bread");
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");
// XXX: Increased experience from cooking zap apples
offerSmelting(exporter, List.of(UItems.ZAP_APPLE), RecipeCategory.FOOD, UItems.COOKED_ZAP_APPLE, 1.2F, 430, "zap_apple");
// XXX: Make zap apple jam jar recipe shapeless
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))
.input(UItems.EMPTY_JAR)
.offerTo(exporter);
// XXX: Make jam toast recipe shapeless
ShapelessRecipeJsonBuilder.create(RecipeCategory.FOOD, UItems.JAM_TOAST, 8)
.input(UItems.ZAP_APPLE_JAM_JAR).criterion(hasItem(UItems.ZAP_APPLE_JAM_JAR), conditionsFromItem(UItems.ZAP_APPLE_JAM_JAR))
.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(Items.SUGAR, 4)
.offerTo(exporter);
// trick apples
offerTrickRecipe(exporter, UItems.GREEN_APPLE, Items.GREEN_DYE);
offerTrickRecipe(exporter, Items.APPLE, Items.RED_DYE);
offerTrickRecipe(exporter, UItems.SOUR_APPLE, Items.YELLOW_DYE);
offerTrickRecipe(exporter, UItems.SWEET_APPLE, Items.ORANGE_DYE);
offerTrickRecipe(exporter, UItems.ROTTEN_APPLE, Items.ROTTEN_FLESH);
offerTrickRecipe(exporter, UItems.COOKED_ZAP_APPLE, Items.SPIDER_EYE);
offerTrickRecipe(exporter, Items.GOLDEN_APPLE, Items.GOLD_NUGGET);
offerTrickRecipe(exporter, Items.ENCHANTED_GOLDEN_APPLE, Items.GOLD_INGOT);
offerTrickRecipe(exporter, UItems.MANGO, Items.LIME_DYE);
offerTrickRecipe(exporter, UItems.PINEAPPLE, UItems.PINEAPPLE_CROWN);
offerTrickRecipe(exporter, UItems.HORSE_SHOE_FRIES, UItems.IRON_HORSE_SHOE);
offerTrickRecipe(exporter, UItems.MUFFIN, UItems.ROCK);
}
public static void offerTrickRecipe(Consumer<RecipeJsonProvider> exporter, ItemConvertible output, ItemConvertible input) {
TrickCraftingRecipeJsonBuilder.create(RecipeCategory.FOOD, output)
.input(UItems.ZAP_APPLE).criterion(hasItem(UItems.ZAP_APPLE), conditionsFromItem(UItems.ZAP_APPLE))
.input(input)
.offerTo(exporter, convertBetween(output, input) + "_trick");
}
private void offerSeaponyRecipes(Consumer<RecipeJsonProvider> exporter) {
@ -376,12 +458,15 @@ public class URecipeProvider extends FabricRecipeProvider {
.offerTo(exporter, convertBetween(Items.DIRT, UItems.WHEAT_WORMS));
offer2x2CompactingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, Items.COBBLESTONE, UItems.ROCK);
// XXX: Made gravel <-> pebbles conversion reversable
offerReversibleCompactingRecipesWithReverseRecipeGroup(exporter, RecipeCategory.MISC, UItems.PEBBLES, RecipeCategory.BUILDING_BLOCKS, Blocks.GRAVEL, convertBetween(UItems.PEBBLES, Blocks.GRAVEL), "pebbles");
// XXX: Added sus gravel -> pebbles recipe
offerShapelessRecipe(exporter, UItems.PEBBLES, Blocks.SUSPICIOUS_GRAVEL, "pebbles", 9);
offerSmelting(exporter, List.of(UItems.GOLDEN_OAK_SEEDS, UItems.GOLDEN_FEATHER), RecipeCategory.MISC, Items.GOLD_NUGGET, 3F, 10, "gold_nugget");
offerGrowing(exporter, UBlocks.CURING_JOKE, Blocks.LAPIS_BLOCK, Blocks.CORNFLOWER);
offerGrowing(exporter, UBlocks.GOLD_ROOT, Blocks.RAW_GOLD_BLOCK, Blocks.CARROTS);
offerGrowing(exporter, UTreeGen.GOLDEN_APPLE_TREE.sapling().get(), Blocks.RAW_GOLD_BLOCK, Blocks.OAK_SAPLING);
offerGrowing(exporter, UBlocks.PLUNDER_VINE_BUD, Blocks.NETHERRACK, Blocks.WITHER_ROSE);
offerGrowing(exporter, UTreeGen.ZAP_APPLE_TREE.sapling().get(), UBlocks.CHITIN, Blocks.DARK_OAK_SAPLING);
}
private static ShapelessRecipeJsonBuilder appendIngredients(ShapelessRecipeJsonBuilder builder, ItemConvertible...ingredients) {
@ -522,8 +607,6 @@ public class URecipeProvider extends FabricRecipeProvider {
private void offerBedSheetRecipes(Consumer<RecipeJsonProvider> exporter) {
PatternTemplate.ONE_COLOR.offerWithoutConversion(exporter, UItems.KELP_BED_SHEETS, Items.KELP);
// XXX: Added white bed sheets, and added a recipe to dye white bed sheets any color
// XXX: Added recipes to change any bedsheet into any solid color using the right wool
WOOLS.forEach(wool -> PatternTemplate.ONE_COLOR.offerTo(exporter, CraftingMaterialHelper.getItem(Unicopia.id(Registries.ITEM.getId(wool).getPath().replace("_wool", "_bed_sheets"))), wool));
PatternTemplate.TWO_COLOR.offerTo(exporter, UItems.APPLE_BED_SHEETS, Items.GREEN_WOOL, Items.LIME_WOOL);
@ -565,4 +648,42 @@ public class URecipeProvider extends FabricRecipeProvider {
.group(getItemPath(output))
.offerTo(exporter, convertBetween(output, Items.HONEYCOMB));
}
public static void offerCloudShapingRecipe(Consumer<RecipeJsonProvider> exporter, RecipeCategory category, ItemConvertible output, ItemConvertible input) {
offerCloudShapingRecipe(exporter, category, output, input, 1);
}
public static void offerCloudShapingRecipe(Consumer<RecipeJsonProvider> exporter, RecipeCategory category, ItemConvertible output, ItemConvertible input, int count) {
CraftingMaterialHelper.createCloudShaping(Ingredient.ofItems(input), category, output, count)
.criterion(RecipeProvider.hasItem(input), RecipeProvider.conditionsFromItem(input))
.offerTo(exporter, RecipeProvider.convertBetween(output, input) + "_cloud_shaping");
}
public static void offerGrowing(Consumer<RecipeJsonProvider> exporter, Block output, Block fuel, Block target) {
GrowingRecipeJsonBuilder.create(RecipeCategory.DECORATIONS, output.getDefaultState())
.fuel(fuel.getDefaultState())
.target(target).criterion(hasItem(target), conditionsFromItem(target))
.offerTo(exporter);
}
public void offerSpell(Consumer<RecipeJsonProvider> exporter, ItemConvertible gemstone, SpellType<?> output, SpellTraits.Builder traits) {
SpellcraftingRecipeJsonBuilder.create(RecipeCategory.MISC, gemstone, output)
.traits(traits)
.offerTo(exporter);
}
public void offerSpellFromSpell(Consumer<RecipeJsonProvider> exporter, ItemConvertible gemstone, SpellType<?> output, SpellType<?> input, SpellTraits.Builder traits) {
SpellcraftingRecipeJsonBuilder.create(RecipeCategory.MISC, gemstone, output)
.input(gemstone, input)
.traits(traits)
.offerTo(exporter);
}
public void offerSpellFromTwoSpells(Consumer<RecipeJsonProvider> exporter, ItemConvertible gemstone, SpellType<?> output, SpellType<?> input1, SpellType<?> input2, SpellTraits.Builder traits) {
SpellcraftingRecipeJsonBuilder.create(RecipeCategory.MISC, gemstone, output)
.input(gemstone, input1)
.input(gemstone, input2)
.traits(traits)
.offerTo(exporter);
}
}

View file

@ -1,14 +0,0 @@
{
"type": "unicopia:spellbook/crafting",
"material": {
"item": "unicopia:gemstone",
"spell": "unicopia:dark_vortex"
},
"traits": {
"darkness": 30, "power": 30, "blood": 30
},
"ingredients": [],
"result": {
"item": "unicopia:alicorn_amulet"
}
}

View file

@ -1,6 +0,0 @@
{
"type": "unicopia:cloud_shaping",
"ingredient": { "item": "unicopia:cloud" },
"result": "unicopia:carved_cloud",
"count": 1
}

View file

@ -1,6 +0,0 @@
{
"type": "unicopia:cloud_shaping",
"ingredient": { "item": "unicopia:cloud_bricks" },
"result": "unicopia:cloud_brick_slab",
"count": 2
}

View file

@ -1,6 +0,0 @@
{
"type": "unicopia:cloud_shaping",
"ingredient": { "item": "unicopia:cloud_bricks" },
"result": "unicopia:cloud_brick_stairs",
"count": 1
}

View file

@ -1,6 +0,0 @@
{
"type": "unicopia:cloud_shaping",
"ingredient": { "item": "unicopia:cloud" },
"result": "unicopia:cloud_bricks",
"count": 1
}

View file

@ -1,6 +0,0 @@
{
"type": "unicopia:cloud_shaping",
"ingredient": { "item": "unicopia:cloud" },
"result": "unicopia:cloud_pillar",
"count": 1
}

View file

@ -1,6 +0,0 @@
{
"type": "unicopia:cloud_shaping",
"ingredient": { "item": "unicopia:cloud_planks" },
"result": "unicopia:cloud_plank_slab",
"count": 2
}

View file

@ -1,6 +0,0 @@
{
"type": "unicopia:cloud_shaping",
"ingredient": { "item": "unicopia:cloud_planks" },
"result": "unicopia:cloud_plank_stairs",
"count": 1
}

View file

@ -1,6 +0,0 @@
{
"type": "unicopia:cloud_shaping",
"ingredient": { "item": "unicopia:cloud" },
"result": "unicopia:cloud_planks",
"count": 1
}

View file

@ -1,6 +0,0 @@
{
"type": "unicopia:cloud_shaping",
"ingredient": { "item": "unicopia:cloud" },
"result": "unicopia:cloud_slab",
"count": 2
}

View file

@ -1,6 +0,0 @@
{
"type": "unicopia:cloud_shaping",
"ingredient": { "item": "unicopia:cloud" },
"result": "unicopia:cloud_stairs",
"count": 1
}

View file

@ -1,6 +0,0 @@
{
"type": "unicopia:cloud_shaping",
"ingredient": { "item": "unicopia:dense_cloud" },
"result": "unicopia:dense_cloud_slab",
"count": 2
}

View file

@ -1,6 +0,0 @@
{
"type": "unicopia:cloud_shaping",
"ingredient": { "item": "unicopia:dense_cloud" },
"result": "unicopia:dense_cloud_stairs",
"count": 1
}

View file

@ -1,6 +0,0 @@
{
"type": "unicopia:cloud_shaping",
"ingredient": { "item": "unicopia:dense_cloud" },
"result": "unicopia:etched_cloud",
"count": 1
}

View file

@ -1,6 +0,0 @@
{
"type": "unicopia:cloud_shaping",
"ingredient": { "item": "unicopia:etched_cloud" },
"result": "unicopia:etched_cloud_slab",
"count": 2
}

View file

@ -1,6 +0,0 @@
{
"type": "unicopia:cloud_shaping",
"ingredient": { "item": "unicopia:etched_cloud" },
"result": "unicopia:etched_cloud_stairs",
"count": 1
}

View file

@ -1,15 +0,0 @@
{
"type": "unicopia:spellbook/crafting",
"material": {
"item": "minecraft:paper"
},
"traits": {
"fire": 1
},
"ingredients": [
{ "item": "minecraft:paper" }
],
"result": {
"item": "unicopia:dragon_breath_scroll"
}
}

View file

@ -1,12 +0,0 @@
{
"type": "unicopia:transform_crop",
"target": "minecraft:cornflower",
"consume": {
"Name": "minecraft:lapis_block",
"Properties": {}
},
"output": {
"Name": "unicopia:curing_joke",
"Properties": {}
}
}

View file

@ -1,12 +0,0 @@
{
"type": "unicopia:transform_crop",
"target": "minecraft:carrots",
"consume": {
"Name": "minecraft:raw_gold_block",
"Properties": {}
},
"output": {
"Name": "unicopia:gold_root",
"Properties": {}
}
}

View file

@ -1,12 +0,0 @@
{
"type": "unicopia:transform_crop",
"target": "minecraft:oak_sapling",
"consume": {
"Name": "minecraft:raw_gold_block",
"Properties": {}
},
"output": {
"Name": "unicopia:golden_oak_sapling",
"Properties": {}
}
}

View file

@ -1,12 +0,0 @@
{
"type": "unicopia:transform_crop",
"target": "minecraft:wither_rose",
"consume": {
"Name": "minecraft:netherrack",
"Properties": {}
},
"output": {
"Name": "unicopia:plunder_vine_bud",
"Properties": {}
}
}

View file

@ -1,12 +0,0 @@
{
"type": "unicopia:transform_crop",
"target": "minecraft:dark_oak_sapling",
"consume": {
"Name": "unicopia:chitin",
"Properties": {}
},
"output": {
"Name": "unicopia:zapling",
"Properties": {}
}
}

View file

@ -1,4 +0,0 @@
{
"type": "unicopia:spellbook/duplicating",
"material": { "item": "unicopia:botched_gem" }
}

View file

@ -1,14 +0,0 @@
{
"type": "unicopia:spellbook/crafting",
"material": { "item": "unicopia:gemstone", "spell": "unicopia:none" },
"traits": {
"strength": 10, "knowledge": 18, "darkness": 1
},
"ingredients": [
{ "item": "unicopia:gemstone", "spell": "unicopia:shield" }
],
"result": {
"item": "unicopia:gemstone",
"spell": "unicopia:arcane_protection"
}
}

View file

@ -1,14 +0,0 @@
{
"type": "unicopia:spellbook/crafting",
"material": { "item": "unicopia:gemstone", "spell": "unicopia:none" },
"traits": {
"water": 9, "air": 9
},
"ingredients": [
{ "item": "unicopia:gemstone", "spell": "unicopia:catapult" }
],
"result": {
"item": "unicopia:gemstone",
"spell": "unicopia:bubble"
}
}

View file

@ -1,14 +0,0 @@
{
"type": "unicopia:spellbook/crafting",
"material": { "item": "unicopia:gemstone", "spell": "unicopia:none" },
"traits": {
"focus": 9, "air": 9
},
"ingredients": [
{ "item": "unicopia:gemstone", "spell": "unicopia:flame" }
],
"result": {
"item": "unicopia:gemstone",
"spell": "unicopia:catapult"
}
}

View file

@ -1,15 +0,0 @@
{
"type": "unicopia:spellbook/crafting",
"material": { "item": "unicopia:gemstone", "spell": "unicopia:none" },
"traits": {
"ice": 5,
"knowledge": 10
},
"ingredients": [
{ "item": "unicopia:gemstone", "spell": "unicopia:frost" }
],
"result": {
"item": "unicopia:gemstone",
"spell": "unicopia:chilling_breath"
}
}

View file

@ -1,14 +0,0 @@
{
"type": "unicopia:spellbook/crafting",
"material": { "item": "unicopia:gemstone", "spell": "unicopia:none" },
"traits": {
"strength": 10, "knowledge": 8, "darkness": 9, "chaos": 8
},
"ingredients": [
{ "item": "unicopia:gemstone", "spell": "unicopia:vortex" }
],
"result": {
"item": "unicopia:gemstone",
"spell": "unicopia:dark_vortex"
}
}

View file

@ -1,16 +0,0 @@
{
"type": "unicopia:spellbook/crafting",
"material": { "item": "unicopia:gemstone", "spell": "unicopia:none" },
"traits": {
"kindness": 1,
"power": 1
},
"ingredients": [
{ "item": "unicopia:gemstone", "spell": "unicopia:arcane_protection" },
{ "item": "unicopia:gemstone", "spell": "unicopia:displacement" }
],
"result": {
"item": "unicopia:gemstone",
"spell": "unicopia:dispel_evil"
}
}

View file

@ -1,12 +0,0 @@
{
"type": "unicopia:spellbook/crafting",
"material": { "item": "unicopia:gemstone", "spell": "unicopia:none" },
"traits": {
"knowledge": 18, "chaos": 20
},
"ingredients": [],
"result": {
"item": "unicopia:gemstone",
"spell": "unicopia:displacement"
}
}

View file

@ -1,15 +0,0 @@
{
"type": "unicopia:spellbook/crafting",
"material": { "item": "unicopia:gemstone", "spell": "unicopia:none" },
"traits": {
"knowledge": 20, "life": 10, "chaos": 4,
"generosity": 10
},
"ingredients": [
{ "item": "unicopia:gemstone", "spell": "unicopia:shield" }
],
"result": {
"item": "unicopia:gemstone",
"spell": "unicopia:feather_fall"
}
}

View file

@ -1,14 +0,0 @@
{
"type": "unicopia:spellbook/crafting",
"material": { "item": "unicopia:gemstone", "spell": "unicopia:none" },
"traits": {
"focus": 9, "fire": 30
},
"ingredients": [
{ "item": "unicopia:gemstone", "spell": "unicopia:flame" }
],
"result": {
"item": "unicopia:gemstone",
"spell": "unicopia:fire_bolt"
}
}

View file

@ -1,14 +0,0 @@
{
"type": "unicopia:spellbook/crafting",
"material": { "item": "unicopia:gemstone", "spell": "unicopia:none" },
"traits": {
"fire": 15
},
"ingredients": [
{ "item": "unicopia:gemstone", "spell": "unicopia:scorch" }
],
"result": {
"item": "unicopia:gemstone",
"spell": "unicopia:flame"
}
}

View file

@ -1,12 +0,0 @@
{
"type": "unicopia:spellbook/crafting",
"material": { "item": "unicopia:gemstone", "spell": "unicopia:none" },
"traits": {
"ice": 15
},
"ingredients": [],
"result": {
"item": "unicopia:gemstone",
"spell": "unicopia:frost"
}
}

View file

@ -1,15 +0,0 @@
{
"type": "unicopia:spellbook/crafting",
"material": { "item": "unicopia:gemstone", "spell": "unicopia:none" },
"traits": {
"focus": 6
},
"ingredients": [
{ "item": "unicopia:gemstone", "spell": "unicopia:frost" },
{ "item": "unicopia:gemstone", "spell": "unicopia:shield" }
],
"result": {
"item": "unicopia:gemstone",
"spell": "unicopia:hydrophobic"
}
}

View file

@ -1,14 +0,0 @@
{
"type": "unicopia:spellbook/crafting",
"material": { "item": "unicopia:gemstone", "spell": "unicopia:none" },
"traits": {
"fire": 50, "darkness": 10
},
"ingredients": [
{ "item": "unicopia:gemstone", "spell": "unicopia:flame" }
],
"result": {
"item": "unicopia:gemstone",
"spell": "unicopia:infernal"
}
}

View file

@ -1,14 +0,0 @@
{
"type": "unicopia:spellbook/crafting",
"material": { "item": "unicopia:gemstone", "spell": "unicopia:none" },
"traits": {
"ice": 30, "life": 30, "focus": 10
},
"ingredients": [
{ "item": "unicopia:gemstone", "spell": "unicopia:fire_bolt" }
],
"result": {
"item": "unicopia:gemstone",
"spell": "unicopia:light"
}
}

View file

@ -1,14 +0,0 @@
{
"type": "unicopia:spellbook/crafting",
"material": { "item": "unicopia:gemstone", "spell": "unicopia:none" },
"traits": {
"knowledge": 19, "life": 10, "chaos": 4
},
"ingredients": [
{ "item": "unicopia:gemstone", "spell": "unicopia:transformation" }
],
"result": {
"item": "unicopia:gemstone",
"spell": "unicopia:mimic"
}
}

View file

@ -1,14 +0,0 @@
{
"type": "unicopia:spellbook/crafting",
"material": { "item": "unicopia:gemstone", "spell": "unicopia:none" },
"traits": {
"knowledge": 19, "life": 10, "chaos": 40
},
"ingredients": [
{ "item": "unicopia:gemstone", "spell": "unicopia:mimic" }
],
"result": {
"item": "unicopia:gemstone",
"spell": "unicopia:mind_swap"
}
}

View file

@ -1,15 +0,0 @@
{
"type": "unicopia:spellbook/crafting",
"material": { "item": "unicopia:gemstone", "spell": "unicopia:none" },
"traits": {
"strength": 10, "knowledge": 8, "darkness": 19, "chaos": 8,
"blood": 10, "poison": 9
},
"ingredients": [
{ "item": "unicopia:gemstone", "spell": "unicopia:siphoning" }
],
"result": {
"item": "unicopia:gemstone",
"spell": "unicopia:necromancy"
}
}

View file

@ -1,15 +0,0 @@
{
"type": "unicopia:spellbook/crafting",
"material": { "item": "unicopia:gemstone", "spell": "unicopia:none" },
"traits": {
"knowledge": 18, "chaos": 20
},
"ingredients": [
{ "item": "unicopia:gemstone", "spell": "unicopia:displacement" },
{ "item": "unicopia:gemstone", "spell": "unicopia:dark_vortex" }
],
"result": {
"item": "unicopia:gemstone",
"spell": "unicopia:portal"
}
}

View file

@ -1,14 +0,0 @@
{
"type": "unicopia:spellbook/crafting",
"material": { "item": "unicopia:gemstone", "spell": "unicopia:none" },
"traits": {
"knowledge": 18, "life": 1, "order": 4
},
"ingredients": [
{ "item": "unicopia:gemstone", "spell": "unicopia:shield" }
],
"result": {
"item": "unicopia:gemstone",
"spell": "unicopia:reveal"
}
}

View file

@ -1,12 +0,0 @@
{
"type": "unicopia:spellbook/crafting",
"material": { "item": "unicopia:gemstone", "spell": "unicopia:none" },
"traits": {
"fire": 10
},
"ingredients": [],
"result": {
"item": "unicopia:gemstone",
"spell": "unicopia:scorch"
}
}

View file

@ -1,12 +0,0 @@
{
"type": "unicopia:spellbook/crafting",
"material": { "item": "unicopia:gemstone", "spell": "unicopia:none" },
"traits": {
"strength": 10, "focus": 6, "power": 10
},
"ingredients": [],
"result": {
"item": "unicopia:gemstone",
"spell": "unicopia:shield"
}
}

View file

@ -1,14 +0,0 @@
{
"type": "unicopia:spellbook/crafting",
"material": { "item": "unicopia:gemstone", "spell": "unicopia:none" },
"traits": {
"blood": 8, "poison": 10
},
"ingredients": [
{ "item": "unicopia:gemstone", "spell": "unicopia:infernal" }
],
"result": {
"item": "unicopia:gemstone",
"spell": "unicopia:siphoning"
}
}

View file

@ -1,12 +0,0 @@
{
"type": "unicopia:spellbook/crafting",
"material": { "item": "unicopia:gemstone", "spell": "unicopia:none" },
"traits": {
"knowledge": 18, "life": 10, "chaos": 4
},
"ingredients": [],
"result": {
"item": "unicopia:gemstone",
"spell": "unicopia:transformation"
}
}

View file

@ -1,14 +0,0 @@
{
"type": "unicopia:spellbook/crafting",
"material": { "item": "unicopia:gemstone", "spell": "unicopia:none" },
"traits": {
"strength": 10, "knowledge": 8, "air": 9
},
"ingredients": [
{ "item": "unicopia:gemstone", "spell": "unicopia:shield" }
],
"result": {
"item": "unicopia:gemstone",
"spell": "unicopia:vortex"
}
}

View file

@ -1,4 +0,0 @@
{
"type": "unicopia:spellbook/combining",
"material": { "item": "unicopia:botched_gem" }
}

View file

@ -1,4 +0,0 @@
{
"type": "unicopia:spellbook/combining",
"material": { "item": "unicopia:gemstone" }
}

View file

@ -1,8 +0,0 @@
{
"type": "unicopia:crafting_zap_apple",
"ingredients": [
{ "item": "unicopia:zap_apple" },
{ "item": "minecraft:green_dye" }
],
"appearance": "unicopia:green_apple"
}

View file

@ -1,8 +0,0 @@
{
"type": "unicopia:crafting_zap_apple",
"ingredients": [
{ "item": "unicopia:zap_apple" },
{ "item": "minecraft:red_dye" }
],
"appearance": "minecraft:apple"
}

View file

@ -1,8 +0,0 @@
{
"type": "unicopia:crafting_zap_apple",
"ingredients": [
{ "item": "unicopia:zap_apple" },
{ "item": "minecraft:yellow_dye" }
],
"appearance": "unicopia:sour_apple"
}

View file

@ -1,8 +0,0 @@
{
"type": "unicopia:crafting_zap_apple",
"ingredients": [
{ "item": "unicopia:zap_apple" },
{ "item": "minecraft:orange_dye" }
],
"appearance": "unicopia:sweet_apple"
}

View file

@ -1,8 +0,0 @@
{
"type": "unicopia:crafting_zap_apple",
"ingredients": [
{ "item": "unicopia:zap_apple" },
{ "item": "minecraft:rotten_flesh" }
],
"appearance": "unicopia:cooked_zap_apple"
}

View file

@ -1,16 +0,0 @@
{
"type": "unicopia:spellbook/crafting",
"material": {
"item": "unicopia:broken_alicorn_amulet"
},
"traits": {},
"ingredients": [
{ "item": "unicopia:pegasus_amulet" },
{ "item": "unicopia:crystal_heart" },
{ "item": "unicopia:grogars_bell" },
{ "item": "minecraft:totem_of_undying" }
],
"result": {
"item": "unicopia:unicorn_amulet"
}
}