Created an ExtendedShapedRecipe and Builder.
This commit is contained in:
@ -0,0 +1,88 @@
|
||||
package dev.micle.totemofreviving.item.crafting;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import net.minecraft.inventory.CraftingInventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.crafting.IRecipeSerializer;
|
||||
import net.minecraft.item.crafting.ShapedRecipe;
|
||||
import net.minecraft.network.PacketBuffer;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.registries.ForgeRegistryEntry;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
public abstract class ExtendedShapedRecipe extends ShapedRecipe {
|
||||
private static final IRecipeSerializer<ShapedRecipe> BASE_SERIALIZER = IRecipeSerializer.SHAPED_RECIPE;
|
||||
|
||||
private final ShapedRecipe recipe;
|
||||
|
||||
public ExtendedShapedRecipe(ShapedRecipe recipe) {
|
||||
super(recipe.getId(), recipe.getGroup(), recipe.getRecipeWidth(), recipe.getRecipeHeight(), recipe.getIngredients(), recipe.getResultItem());
|
||||
this.recipe = recipe;
|
||||
}
|
||||
|
||||
public ShapedRecipe getBaseRecipe() {
|
||||
return this.recipe;
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract IRecipeSerializer<?> getSerializer();
|
||||
|
||||
@Override
|
||||
public abstract boolean matches(CraftingInventory inventory, World world);
|
||||
|
||||
@Override
|
||||
public abstract ItemStack assemble(CraftingInventory inventory);
|
||||
|
||||
public static class Serializer<T extends ExtendedShapedRecipe> extends ForgeRegistryEntry<IRecipeSerializer<?>> implements IRecipeSerializer<T> {
|
||||
private final Function<ShapedRecipe, T> recipeFactory;
|
||||
@Nullable private final BiConsumer<JsonObject, T> readJson;
|
||||
@Nullable private final BiConsumer<PacketBuffer, T> readBuffer;
|
||||
@Nullable private final BiConsumer<PacketBuffer, T> writeBuffer;
|
||||
|
||||
public Serializer(Function<ShapedRecipe, T> recipeFactory,
|
||||
@Nullable BiConsumer<JsonObject, T> readJson,
|
||||
@Nullable BiConsumer<PacketBuffer, T> readBuffer,
|
||||
@Nullable BiConsumer<PacketBuffer, T> writeBuffer) {
|
||||
this.recipeFactory = recipeFactory;
|
||||
this.readJson = readJson;
|
||||
this.readBuffer = readBuffer;
|
||||
this.writeBuffer = writeBuffer;
|
||||
}
|
||||
|
||||
public static <S extends ExtendedShapedRecipe> Serializer<S> basic(Function<ShapedRecipe, S> recipeFactory) {
|
||||
return new Serializer<>(recipeFactory, null, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T fromJson(ResourceLocation recipeId, JsonObject json) {
|
||||
ShapedRecipe recipe = BASE_SERIALIZER.fromJson(recipeId, json);
|
||||
T result = this.recipeFactory.apply(recipe);
|
||||
if (this.readJson != null) {
|
||||
this.readJson.accept(json, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T fromNetwork(ResourceLocation recipeId, PacketBuffer buffer) {
|
||||
ShapedRecipe recipe = BASE_SERIALIZER.fromNetwork(recipeId, buffer);
|
||||
T result = this.recipeFactory.apply(recipe);
|
||||
if (this.readBuffer != null) {
|
||||
this.readBuffer.accept(buffer, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toNetwork(PacketBuffer buffer, T recipe) {
|
||||
BASE_SERIALIZER.toNetwork(buffer, recipe.getBaseRecipe());
|
||||
if (this.writeBuffer != null) {
|
||||
this.writeBuffer.accept(buffer, recipe);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,184 @@
|
||||
package dev.micle.totemofreviving.item.crafting;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import net.minecraft.advancements.Advancement;
|
||||
import net.minecraft.advancements.AdvancementRewards;
|
||||
import net.minecraft.advancements.ICriterionInstance;
|
||||
import net.minecraft.advancements.IRequirementsStrategy;
|
||||
import net.minecraft.advancements.criterion.EntityPredicate;
|
||||
import net.minecraft.advancements.criterion.RecipeUnlockedTrigger;
|
||||
import net.minecraft.data.IFinishedRecipe;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.crafting.IRecipeSerializer;
|
||||
import net.minecraft.item.crafting.Ingredient;
|
||||
import net.minecraft.tags.ITag;
|
||||
import net.minecraft.util.IItemProvider;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class ExtendedShapedRecipeBuilder {
|
||||
private final IRecipeSerializer<?> serializer;
|
||||
private final Item result;
|
||||
private final int count;
|
||||
private final List<String> pattern = new ArrayList<>();
|
||||
private final Map<Character, Ingredient> key = new LinkedHashMap<>();
|
||||
private final Advancement.Builder advancementBuilder = Advancement.Builder.advancement();
|
||||
private boolean hasAdvancementCriterion = false;
|
||||
private String group = "";
|
||||
|
||||
private ExtendedShapedRecipeBuilder(IRecipeSerializer<?> serializer, IItemProvider result, int count) {
|
||||
this.serializer = serializer;
|
||||
this.result = result.asItem();
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
public static ExtendedShapedRecipeBuilder shaped(IRecipeSerializer<?> serializer, IItemProvider result) {
|
||||
return shaped(serializer, result, 1);
|
||||
}
|
||||
|
||||
public static ExtendedShapedRecipeBuilder shaped(IRecipeSerializer<?> serializer, IItemProvider result, int count) {
|
||||
return new ExtendedShapedRecipeBuilder(serializer, result, count);
|
||||
}
|
||||
|
||||
public ExtendedShapedRecipeBuilder define(Character symbol, ITag<Item> tagIn) {
|
||||
return this.define(symbol, Ingredient.of(tagIn));
|
||||
}
|
||||
|
||||
public ExtendedShapedRecipeBuilder define(Character symbol, IItemProvider itemIn) {
|
||||
return this.define(symbol, Ingredient.of(itemIn));
|
||||
}
|
||||
|
||||
public ExtendedShapedRecipeBuilder define(Character symbol, Ingredient ingredientIn) {
|
||||
if (this.key.containsKey(symbol)) {
|
||||
throw new IllegalArgumentException("Symbol '" + symbol + "' is already defined!");
|
||||
} else if (symbol == ' ') {
|
||||
throw new IllegalArgumentException("Symbol ' ' (whitespace) is reserved and cannot be defined");
|
||||
} else {
|
||||
this.key.put(symbol, ingredientIn);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public ExtendedShapedRecipeBuilder pattern(String patternIn) {
|
||||
if (!this.pattern.isEmpty() && patternIn.length() != this.pattern.get(0).length()) {
|
||||
throw new IllegalArgumentException("Pattern must be the same width on every line!");
|
||||
} else {
|
||||
this.pattern.add(patternIn);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public ExtendedShapedRecipeBuilder unlockedBy(String name, ICriterionInstance criterionIn) {
|
||||
this.advancementBuilder.addCriterion(name, criterionIn);
|
||||
this.hasAdvancementCriterion = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ExtendedShapedRecipeBuilder group(String groupIn) {
|
||||
this.group = groupIn;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void save(Consumer<IFinishedRecipe> consumer) {
|
||||
save(consumer, this.result.getRegistryName());
|
||||
}
|
||||
|
||||
public void save(Consumer<IFinishedRecipe> consumer, ResourceLocation id) {
|
||||
this.validate(id);
|
||||
if (this.hasAdvancementCriterion && !this.advancementBuilder.getCriteria().isEmpty()) {
|
||||
this.advancementBuilder.parent(new ResourceLocation("recipes/root"))
|
||||
.addCriterion("has_the_recipe", new RecipeUnlockedTrigger.Instance(EntityPredicate.AndPredicate.ANY, id))
|
||||
.rewards(AdvancementRewards.Builder.recipe(id))
|
||||
.requirements(IRequirementsStrategy.OR);
|
||||
}
|
||||
ResourceLocation advancementId = new ResourceLocation(id.getNamespace(), "recipes/" + this.result.getItemCategory().getRecipeFolderName() + "/" + id.getPath());
|
||||
consumer.accept(new Result(id, this, advancementId));
|
||||
}
|
||||
|
||||
private void validate(ResourceLocation id) {
|
||||
if (this.pattern.isEmpty()) {
|
||||
throw new IllegalStateException("No pattern is defined for shaped recipe " + id + "!");
|
||||
} else {
|
||||
Set<Character> set = Sets.newHashSet(this.key.keySet());
|
||||
set.remove(' ');
|
||||
|
||||
for (String s : this.pattern) {
|
||||
for (int i = 0; i < s.length(); ++i) {
|
||||
char c0 = s.charAt(i);
|
||||
if (!this.key.containsKey(c0) && c0 != ' ') {
|
||||
throw new IllegalStateException("Pattern in recipe " + id + " uses undefined symbol '" + c0 + "'");
|
||||
}
|
||||
|
||||
set.remove(c0);
|
||||
}
|
||||
}
|
||||
|
||||
if (!set.isEmpty()) {
|
||||
throw new IllegalStateException("Ingredients are defined but not used in pattern for recipe " + id);
|
||||
} else if (this.pattern.size() == 1 && this.pattern.get(0).length() == 1) {
|
||||
throw new IllegalStateException("Shaped recipe " + id + " only takes in a single item - should it be a shapeless recipe instead?");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class Result implements IFinishedRecipe {
|
||||
private final ResourceLocation id;
|
||||
private final ExtendedShapedRecipeBuilder builder;
|
||||
private final ResourceLocation advancementId;
|
||||
|
||||
public Result(ResourceLocation id, ExtendedShapedRecipeBuilder builder, ResourceLocation advancementId) {
|
||||
this.id = id;
|
||||
this.builder = builder;
|
||||
this.advancementId = advancementId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serializeRecipeData(JsonObject json) {
|
||||
if (!builder.group.isEmpty()) {
|
||||
json.addProperty("group", builder.group);
|
||||
}
|
||||
|
||||
JsonArray pattern = new JsonArray();
|
||||
builder.pattern.forEach(pattern::add);
|
||||
json.add("pattern", pattern);
|
||||
|
||||
JsonObject key = new JsonObject();
|
||||
builder.key.forEach((c, ingredient) -> key.add(String.valueOf(c), ingredient.toJson()));
|
||||
json.add("key", key);
|
||||
|
||||
JsonObject result = new JsonObject();
|
||||
result.addProperty("item", builder.result.getRegistryName().toString());
|
||||
if (builder.count > 1) {
|
||||
result.addProperty("count", builder.count);
|
||||
}
|
||||
json.add("result", result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IRecipeSerializer<?> getType() {
|
||||
return builder.serializer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public JsonObject serializeAdvancement() {
|
||||
return builder.hasAdvancementCriterion ? builder.advancementBuilder.serializeToJson() : null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ResourceLocation getAdvancementId() {
|
||||
return builder.hasAdvancementCriterion ? advancementId : null;
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user