Accessors, recipe builders

This commit is contained in:
paulevsGitch 2021-05-26 16:26:48 +03:00
parent cab98a75c2
commit 834389712b
10 changed files with 524 additions and 1 deletions

View file

@ -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

View file

@ -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");
}
}

View file

@ -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");
}
}

View file

@ -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<RecipeType<?>, Map<ResourceLocation, Recipe<?>>> be_getRecipes();
@Accessor("recipes")
void be_setRecipes(Map<RecipeType<?>, Map<ResourceLocation, Recipe<?>>> recipes);
}

View file

@ -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<RecipeType<?>, Map<ResourceLocation, Recipe<?>>> recipes;
@Inject(method = "apply", at = @At(value = "RETURN"))
private void be_apply(Map<ResourceLocation, JsonElement> map, ResourceManager resourceManager, ProfilerFiller profiler, CallbackInfo info) {
recipes = BCLRecipeManager.getMap(recipes);
}
@Shadow
private <C extends Container, T extends Recipe<C>> Map<ResourceLocation, Recipe<C>> byType(RecipeType<T> 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 <C extends Container, T extends Recipe<C>> Optional<T> getRecipeFor(RecipeType<T> type, C inventory, Level world) {
Collection<Recipe<C>> values = byType(type).values();
List<Recipe<C>> list = new ArrayList<Recipe<C>>(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();
}
}

View file

@ -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<RecipeType<?>, Map<ResourceLocation, Recipe<?>>> RECIPES = Maps.newHashMap();
public static void addRecipe(RecipeType<?> type, Recipe<?> recipe) {
Map<ResourceLocation, Recipe<?>> list = RECIPES.get(type);
if (list == null) {
list = Maps.newHashMap();
RECIPES.put(type, list);
}
list.put(recipe.getId(), recipe);
}
@SuppressWarnings("unchecked")
public static <T extends Recipe<?>> T getRecipe(RecipeType<T> type, ResourceLocation id) {
if (RECIPES.containsKey(type)) {
return (T) RECIPES.get(type).get(id);
}
return null;
}
public static Map<RecipeType<?>, Map<ResourceLocation, Recipe<?>>> getMap(Map<RecipeType<?>, Map<ResourceLocation, Recipe<?>>> recipes) {
Map<RecipeType<?>, Map<ResourceLocation, Recipe<?>>> result = Maps.newHashMap();
for (RecipeType<?> type : recipes.keySet()) {
Map<ResourceLocation, Recipe<?>> typeList = Maps.newHashMap();
typeList.putAll(recipes.get(type));
result.put(type, typeList);
}
for (RecipeType<?> type : RECIPES.keySet()) {
Map<ResourceLocation, Recipe<?>> list = RECIPES.get(type);
if (list != null) {
Map<ResourceLocation, Recipe<?>> typeList = result.get(type);
if (typeList == null) {
typeList = Maps.newHashMap();
result.put(type, typeList);
}
for (Entry<ResourceLocation, Recipe<?>> entry : list.entrySet()) {
ResourceLocation id = entry.getKey();
if (!typeList.containsKey(id))
typeList.put(id, entry.getValue());
}
}
}
return result;
}
public static <S extends RecipeSerializer<T>, T extends Recipe<?>> S registerSerializer(String modID, String id, S serializer) {
return Registry.register(Registry.RECIPE_SERIALIZER, modID + ":" + id, serializer);
}
public static <T extends Recipe<?>> RecipeType<T> registerType(String modID, String type) {
ResourceLocation recipeTypeId = new ResourceLocation(modID, type);
return Registry.register(Registry.RECIPE_TYPE, recipeTypeId, new RecipeType<T>() {
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;
}
}

View file

@ -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);
}
}
}

View file

@ -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<Character, Ingredient> 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<Item> 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<Ingredient> getMaterials(int width, int height) {
NonNullList<Ingredient> 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<Ingredient> 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);
}
}
}

View file

@ -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<UpgradeRecipe> 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<Item> 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<Item> 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));
}
}

View file

@ -4,6 +4,10 @@
"package": "ru.bclib.mixin.common",
"compatibilityLevel": "JAVA_8",
"mixins": [
"ComposterBlockAccessor",
"PotionBrewingAccessor",
"RecipeManagerAccessor",
"RecipeManagerMixin",
"BoneMealItemMixin",
"TagLoaderMixin"
],