From 834389712b8c9966a60ed9fd392bd1535b6b9f78 Mon Sep 17 00:00:00 2001 From: paulevsGitch Date: Wed, 26 May 2021 16:26:48 +0300 Subject: [PATCH] Accessors, recipe builders --- gradle.properties | 2 +- .../mixin/common/ComposterBlockAccessor.java | 15 +++ .../mixin/common/PotionBrewingAccessor.java | 16 +++ .../mixin/common/RecipeManagerAccessor.java | 20 +++ .../mixin/common/RecipeManagerMixin.java | 64 ++++++++++ .../ru/bclib/recipes/BCLRecipeManager.java | 93 ++++++++++++++ .../java/ru/bclib/recipes/FurnaceRecipe.java | 96 ++++++++++++++ .../java/ru/bclib/recipes/GridRecipe.java | 120 ++++++++++++++++++ .../ru/bclib/recipes/SmithingTableRecipe.java | 95 ++++++++++++++ src/main/resources/bclib.mixins.common.json | 4 + 10 files changed, 524 insertions(+), 1 deletion(-) create mode 100644 src/main/java/ru/bclib/mixin/common/ComposterBlockAccessor.java create mode 100644 src/main/java/ru/bclib/mixin/common/PotionBrewingAccessor.java create mode 100644 src/main/java/ru/bclib/mixin/common/RecipeManagerAccessor.java create mode 100644 src/main/java/ru/bclib/mixin/common/RecipeManagerMixin.java create mode 100644 src/main/java/ru/bclib/recipes/BCLRecipeManager.java create mode 100644 src/main/java/ru/bclib/recipes/FurnaceRecipe.java create mode 100644 src/main/java/ru/bclib/recipes/GridRecipe.java create mode 100644 src/main/java/ru/bclib/recipes/SmithingTableRecipe.java diff --git a/gradle.properties b/gradle.properties index 09498443..40fc81b4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,7 +8,7 @@ yarn_mappings=6 loader_version=0.11.3 # Mod Properties -mod_version = 0.1.1 +mod_version = 0.1.2 maven_group = ru.bclib archives_base_name = bclib diff --git a/src/main/java/ru/bclib/mixin/common/ComposterBlockAccessor.java b/src/main/java/ru/bclib/mixin/common/ComposterBlockAccessor.java new file mode 100644 index 00000000..81a2ba6c --- /dev/null +++ b/src/main/java/ru/bclib/mixin/common/ComposterBlockAccessor.java @@ -0,0 +1,15 @@ +package ru.bclib.mixin.common; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +import net.minecraft.world.level.ItemLike; +import net.minecraft.world.level.block.ComposterBlock; + +@Mixin(ComposterBlock.class) +public interface ComposterBlockAccessor { + @Invoker + static void callAdd(float levelIncreaseChance, ItemLike item) { + throw new AssertionError("@Invoker dummy body called"); + } +} diff --git a/src/main/java/ru/bclib/mixin/common/PotionBrewingAccessor.java b/src/main/java/ru/bclib/mixin/common/PotionBrewingAccessor.java new file mode 100644 index 00000000..b0c8e3f4 --- /dev/null +++ b/src/main/java/ru/bclib/mixin/common/PotionBrewingAccessor.java @@ -0,0 +1,16 @@ +package ru.bclib.mixin.common; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +import net.minecraft.world.item.Item; +import net.minecraft.world.item.alchemy.Potion; +import net.minecraft.world.item.alchemy.PotionBrewing; + +@Mixin(PotionBrewing.class) +public interface PotionBrewingAccessor { + @Invoker + static void callAddMix(Potion input, Item item, Potion output) { + throw new AssertionError("@Invoker dummy body called"); + } +} diff --git a/src/main/java/ru/bclib/mixin/common/RecipeManagerAccessor.java b/src/main/java/ru/bclib/mixin/common/RecipeManagerAccessor.java new file mode 100644 index 00000000..dba423b6 --- /dev/null +++ b/src/main/java/ru/bclib/mixin/common/RecipeManagerAccessor.java @@ -0,0 +1,20 @@ +package ru.bclib.mixin.common; + +import java.util.Map; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.crafting.Recipe; +import net.minecraft.world.item.crafting.RecipeManager; +import net.minecraft.world.item.crafting.RecipeType; + +@Mixin(RecipeManager.class) +public interface RecipeManagerAccessor { + @Accessor("recipes") + Map, Map>> be_getRecipes(); + + @Accessor("recipes") + void be_setRecipes(Map, Map>> recipes); +} \ No newline at end of file diff --git a/src/main/java/ru/bclib/mixin/common/RecipeManagerMixin.java b/src/main/java/ru/bclib/mixin/common/RecipeManagerMixin.java new file mode 100644 index 00000000..5c2092f6 --- /dev/null +++ b/src/main/java/ru/bclib/mixin/common/RecipeManagerMixin.java @@ -0,0 +1,64 @@ +package ru.bclib.mixin.common; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import com.google.gson.JsonElement; + +import net.minecraft.Util; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.resources.ResourceManager; +import net.minecraft.util.profiling.ProfilerFiller; +import net.minecraft.world.Container; +import net.minecraft.world.item.crafting.Recipe; +import net.minecraft.world.item.crafting.RecipeManager; +import net.minecraft.world.item.crafting.RecipeType; +import net.minecraft.world.level.Level; +import ru.bclib.recipes.BCLRecipeManager; + +@Mixin(RecipeManager.class) +public abstract class RecipeManagerMixin { + @Shadow + private Map, Map>> recipes; + + @Inject(method = "apply", at = @At(value = "RETURN")) + private void be_apply(Map map, ResourceManager resourceManager, ProfilerFiller profiler, CallbackInfo info) { + recipes = BCLRecipeManager.getMap(recipes); + } + + @Shadow + private > Map> byType(RecipeType type) { + return null; + } + + /** + * @author paulevs + * @reason Remove conflicts with vanilla tags + * Change recipe order to show mod recipes first, helps when block have vanilla tag + * (example - mod stone with vanilla tags and furnace from that stone) + */ + @Overwrite + public > Optional getRecipeFor(RecipeType type, C inventory, Level world) { + Collection> values = byType(type).values(); + List> list = new ArrayList>(values); + list.sort((v1, v2) -> { + boolean b1 = v1.getId().getNamespace().equals("minecraft"); + boolean b2 = v2.getId().getNamespace().equals("minecraft"); + return b1 ^ b2 ? (b1 ? 1 : -1) : 0; + }); + + return list.stream().flatMap((recipe) -> { + return Util.toStream(type.tryMatch(recipe, world, inventory)); + }).findFirst(); + } +} \ No newline at end of file diff --git a/src/main/java/ru/bclib/recipes/BCLRecipeManager.java b/src/main/java/ru/bclib/recipes/BCLRecipeManager.java new file mode 100644 index 00000000..8e2f6e71 --- /dev/null +++ b/src/main/java/ru/bclib/recipes/BCLRecipeManager.java @@ -0,0 +1,93 @@ +package ru.bclib.recipes; + +import java.util.Map; +import java.util.Map.Entry; + +import com.google.common.collect.Maps; + +import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.crafting.Recipe; +import net.minecraft.world.item.crafting.RecipeSerializer; +import net.minecraft.world.item.crafting.RecipeType; +import net.minecraft.world.level.ItemLike; +import net.minecraft.world.level.block.Block; + +public class BCLRecipeManager { + private static final Map, Map>> RECIPES = Maps.newHashMap(); + + public static void addRecipe(RecipeType type, Recipe recipe) { + Map> list = RECIPES.get(type); + if (list == null) { + list = Maps.newHashMap(); + RECIPES.put(type, list); + } + list.put(recipe.getId(), recipe); + } + + @SuppressWarnings("unchecked") + public static > T getRecipe(RecipeType type, ResourceLocation id) { + if (RECIPES.containsKey(type)) { + return (T) RECIPES.get(type).get(id); + } + return null; + } + + public static Map, Map>> getMap(Map, Map>> recipes) { + Map, Map>> result = Maps.newHashMap(); + + for (RecipeType type : recipes.keySet()) { + Map> typeList = Maps.newHashMap(); + typeList.putAll(recipes.get(type)); + result.put(type, typeList); + } + + for (RecipeType type : RECIPES.keySet()) { + Map> list = RECIPES.get(type); + if (list != null) { + Map> typeList = result.get(type); + if (typeList == null) { + typeList = Maps.newHashMap(); + result.put(type, typeList); + } + for (Entry> entry : list.entrySet()) { + ResourceLocation id = entry.getKey(); + if (!typeList.containsKey(id)) + typeList.put(id, entry.getValue()); + } + } + } + + return result; + } + + public static , T extends Recipe> S registerSerializer(String modID, String id, S serializer) { + return Registry.register(Registry.RECIPE_SERIALIZER, modID + ":" + id, serializer); + } + + public static > RecipeType registerType(String modID, String type) { + ResourceLocation recipeTypeId = new ResourceLocation(modID, type); + return Registry.register(Registry.RECIPE_TYPE, recipeTypeId, new RecipeType() { + public String toString() { + return type; + } + }); + } + + public static boolean exists(ItemLike item) { + if (item instanceof Block) { + return Registry.BLOCK.getKey((Block) item) != Registry.BLOCK.getDefaultKey(); + } else { + return Registry.ITEM.getKey(item.asItem()) != Registry.ITEM.getDefaultKey(); + } + } + + public static boolean exists(ItemLike... items) { + for (ItemLike item : items) { + if (!exists(item)) { + return false; + } + } + return true; + } +} \ No newline at end of file diff --git a/src/main/java/ru/bclib/recipes/FurnaceRecipe.java b/src/main/java/ru/bclib/recipes/FurnaceRecipe.java new file mode 100644 index 00000000..e6f9e596 --- /dev/null +++ b/src/main/java/ru/bclib/recipes/FurnaceRecipe.java @@ -0,0 +1,96 @@ +package ru.bclib.recipes; + +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.BlastingRecipe; +import net.minecraft.world.item.crafting.CampfireCookingRecipe; +import net.minecraft.world.item.crafting.Ingredient; +import net.minecraft.world.item.crafting.RecipeType; +import net.minecraft.world.item.crafting.SmeltingRecipe; +import net.minecraft.world.item.crafting.SmokingRecipe; +import net.minecraft.world.level.ItemLike; +import ru.bclib.BCLib; + +public class FurnaceRecipe { + private static final FurnaceRecipe INSTANCE = new FurnaceRecipe(); + + private ResourceLocation id; + private ItemLike input; + private ItemLike output; + private boolean exist; + private String group; + private int count; + private int time; + private float xp; + + private FurnaceRecipe() {} + + public static FurnaceRecipe make(String modID, String name, ItemLike input, ItemLike output) { + INSTANCE.id = new ResourceLocation(modID, name); + INSTANCE.group = ""; + INSTANCE.input = input; + INSTANCE.output = output; + INSTANCE.count = 1; + INSTANCE.time = 200; + INSTANCE.xp = 0; + INSTANCE.exist = BCLRecipeManager.exists(output) && BCLRecipeManager.exists(input); + return INSTANCE; + } + + public FurnaceRecipe setGroup(String group) { + this.group = group; + return this; + } + + public FurnaceRecipe setOutputCount(int count) { + this.count = count; + return this; + } + + public FurnaceRecipe setXP(float xp) { + this.xp = xp; + return this; + } + + public FurnaceRecipe setCookTime(int time) { + this.time = time; + return this; + } + + public void build() { + build(false, false, false); + } + + public void buildWithBlasting() { + build(true, false, false); + } + + public void buildFoodlike() { + build(false, true, true); + } + + public void build(boolean blasting, boolean campfire, boolean smoker) { + if (exist) { + SmeltingRecipe recipe = new SmeltingRecipe(id, group, Ingredient.of(input), new ItemStack(output, count), xp, time); + BCLRecipeManager.addRecipe(RecipeType.SMELTING, recipe); + + if (blasting) { + BlastingRecipe recipe2 = new BlastingRecipe(id, group, Ingredient.of(input), new ItemStack(output, count), xp, time / 2); + BCLRecipeManager.addRecipe(RecipeType.BLASTING, recipe2); + } + + if (campfire) { + CampfireCookingRecipe recipe2 = new CampfireCookingRecipe(id, group, Ingredient.of(input), new ItemStack(output, count), xp, time * 3); + BCLRecipeManager.addRecipe(RecipeType.CAMPFIRE_COOKING, recipe2); + } + + if (smoker) { + SmokingRecipe recipe2 = new SmokingRecipe(id, group, Ingredient.of(input), new ItemStack(output, count), xp, time / 2); + BCLRecipeManager.addRecipe(RecipeType.SMOKING, recipe2); + } + } + else { + BCLib.LOGGER.debug("Furnace recipe {} couldn't be added", id); + } + } +} diff --git a/src/main/java/ru/bclib/recipes/GridRecipe.java b/src/main/java/ru/bclib/recipes/GridRecipe.java new file mode 100644 index 00000000..ca63ad5d --- /dev/null +++ b/src/main/java/ru/bclib/recipes/GridRecipe.java @@ -0,0 +1,120 @@ +package ru.bclib.recipes; + +import java.util.Arrays; +import java.util.Map; + +import com.google.common.collect.Maps; + +import net.minecraft.core.NonNullList; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.Tag; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.CraftingRecipe; +import net.minecraft.world.item.crafting.Ingredient; +import net.minecraft.world.item.crafting.RecipeType; +import net.minecraft.world.item.crafting.ShapedRecipe; +import net.minecraft.world.item.crafting.ShapelessRecipe; +import net.minecraft.world.level.ItemLike; +import ru.bclib.BCLib; + +public class GridRecipe { + private static final GridRecipe INSTANCE = new GridRecipe(); + + private ResourceLocation id; + private ItemLike output; + + private String group; + private RecipeType type; + private boolean shaped; + private String[] shape; + private Map materialKeys = Maps.newHashMap(); + private int count; + private boolean exist = true; + + private GridRecipe() {} + + public static GridRecipe make(String modID, String name, ItemLike output) { + INSTANCE.id = new ResourceLocation(modID, name); + INSTANCE.output = output; + + INSTANCE.group = ""; + INSTANCE.type = RecipeType.CRAFTING; + INSTANCE.shaped = true; + INSTANCE.shape = new String[] {"#"}; + INSTANCE.materialKeys.clear(); + INSTANCE.count = 1; + + INSTANCE.exist = BCLRecipeManager.exists(output); + + return INSTANCE; + } + + public GridRecipe setGroup(String group) { + this.group = group; + return this; + } + + public GridRecipe setShape(String... shape) { + this.shape = shape; + return this; + } + + public GridRecipe setList(String shape) { + this.shape = new String[] { shape }; + this.shaped = false; + return this; + } + + public GridRecipe addMaterial(char key, Tag value) { + return addMaterial(key, Ingredient.of(value)); + } + + public GridRecipe addMaterial(char key, ItemStack... value) { + return addMaterial(key, Ingredient.of(Arrays.stream(value))); + } + + public GridRecipe addMaterial(char key, ItemLike... values) { + for (ItemLike item: values) { + exist &= BCLRecipeManager.exists(item); + } + return addMaterial(key, Ingredient.of(values)); + } + + private GridRecipe addMaterial(char key, Ingredient value) { + materialKeys.put(key, value); + return this; + } + + public GridRecipe setOutputCount(int count) { + this.count = count; + return this; + } + + private NonNullList getMaterials(int width, int height) { + NonNullList materials = NonNullList.withSize(width * height, Ingredient.EMPTY); + int pos = 0; + for (String line: shape) { + for (int i = 0; i < width; i++) { + char c = line.charAt(i); + Ingredient material = materialKeys.get(c); + materials.set(pos ++, material == null ? Ingredient.EMPTY : material); + } + } + return materials; + } + + public void build() { + if (exist) { + int height = shape.length; + int width = shape[0].length(); + ItemStack result = new ItemStack(output, count); + NonNullList materials = this.getMaterials(width, height); + + CraftingRecipe recipe = shaped ? new ShapedRecipe(id, group, width, height, materials, result) : new ShapelessRecipe(id, group, result, materials); + BCLRecipeManager.addRecipe(type, recipe); + } else { + BCLib.LOGGER.debug("Recipe {} couldn't be added", id); + } + } +} diff --git a/src/main/java/ru/bclib/recipes/SmithingTableRecipe.java b/src/main/java/ru/bclib/recipes/SmithingTableRecipe.java new file mode 100644 index 00000000..006a1724 --- /dev/null +++ b/src/main/java/ru/bclib/recipes/SmithingTableRecipe.java @@ -0,0 +1,95 @@ +package ru.bclib.recipes; + +import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.Tag; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.Ingredient; +import net.minecraft.world.item.crafting.RecipeType; +import net.minecraft.world.item.crafting.UpgradeRecipe; +import net.minecraft.world.level.ItemLike; +import ru.bclib.BCLib; + +public class SmithingTableRecipe { + + private final static SmithingTableRecipe BUILDER = new SmithingTableRecipe(); + private final static RecipeType TYPE = RecipeType.SMITHING; + + public static SmithingTableRecipe create(String modID, String name) { + return create(new ResourceLocation(modID, name)); + } + + public static SmithingTableRecipe create(ResourceLocation id) { + BUILDER.id = id; + BUILDER.base = null; + BUILDER.addition = null; + BUILDER.result = null; + BUILDER.alright = true; + + return BUILDER; + } + + private ResourceLocation id; + private Ingredient base; + private Ingredient addition; + private ItemStack result; + private boolean alright; + + private SmithingTableRecipe() {} + + public SmithingTableRecipe setResult(ItemLike item) { + return this.setResult(item, 1); + } + + public SmithingTableRecipe setResult(ItemLike item, int count) { + this.alright &= BCLRecipeManager.exists(item); + this.result = new ItemStack(item, count); + return this; + } + + public SmithingTableRecipe setBase(ItemLike... items) { + this.alright &= BCLRecipeManager.exists(items); + this.base = Ingredient.of(items); + return this; + } + + public SmithingTableRecipe setBase(Tag tag) { + this.base = (Ingredient.of(tag)); + return this; + } + + public SmithingTableRecipe setAddition(ItemLike... items) { + this.alright &= BCLRecipeManager.exists(items); + this.addition = Ingredient.of(items); + return this; + } + + public SmithingTableRecipe setAddition(Tag tag) { + this.addition = (Ingredient.of(tag)); + return this; + } + + public void build() { + if (base == null) { + BCLib.LOGGER.warning("Base input for Smithing recipe can't be 'null', recipe {} will be ignored!", id); + return; + } + if (addition == null) { + BCLib.LOGGER.warning("Addition input for Smithing recipe can't be 'null', recipe {} will be ignored!", id); + return; + } + if(result == null) { + BCLib.LOGGER.warning("Result for Smithing recipe can't be 'null', recipe {} will be ignored!", id); + return; + } + if (BCLRecipeManager.getRecipe(TYPE, id) != null) { + BCLib.LOGGER.warning("Can't add Smithing recipe! Id {} already exists!", id); + return; + } + if (!alright) { + BCLib.LOGGER.debug("Can't add Smithing recipe {}! Ingeredients or output not exists.", id); + return; + } + BCLRecipeManager.addRecipe(TYPE, new UpgradeRecipe(id, base, addition, result)); + } +} diff --git a/src/main/resources/bclib.mixins.common.json b/src/main/resources/bclib.mixins.common.json index 2d182b8c..874c057c 100644 --- a/src/main/resources/bclib.mixins.common.json +++ b/src/main/resources/bclib.mixins.common.json @@ -4,6 +4,10 @@ "package": "ru.bclib.mixin.common", "compatibilityLevel": "JAVA_8", "mixins": [ + "ComposterBlockAccessor", + "PotionBrewingAccessor", + "RecipeManagerAccessor", + "RecipeManagerMixin", "BoneMealItemMixin", "TagLoaderMixin" ],