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/BCLib.java b/src/main/java/ru/bclib/BCLib.java index 1d918a36..94d02160 100644 --- a/src/main/java/ru/bclib/BCLib.java +++ b/src/main/java/ru/bclib/BCLib.java @@ -6,7 +6,7 @@ import net.fabricmc.loader.api.FabricLoader; import net.minecraft.resources.ResourceLocation; import ru.bclib.util.Logger; import ru.bclib.world.surface.BCLSurfaceBuilders; -import ru.bclib.api.BCLibTags; +import ru.bclib.api.TagAPI; public class BCLib implements ModInitializer { public static final String MOD_ID = "bclib"; @@ -15,7 +15,7 @@ public class BCLib implements ModInitializer { @Override public void onInitialize() { BCLSurfaceBuilders.register(); - BCLibTags.init(); + TagAPI.init(); } public static boolean isDevEnvironment() { diff --git a/src/main/java/ru/bclib/api/BCLibTags.java b/src/main/java/ru/bclib/api/TagAPI.java similarity index 97% rename from src/main/java/ru/bclib/api/BCLibTags.java rename to src/main/java/ru/bclib/api/TagAPI.java index d27e5676..8a4accba 100644 --- a/src/main/java/ru/bclib/api/BCLibTags.java +++ b/src/main/java/ru/bclib/api/TagAPI.java @@ -16,7 +16,7 @@ import net.minecraft.world.level.block.Blocks; import ru.bclib.BCLib; import ru.bclib.util.TagHelper; -public class BCLibTags { +public class TagAPI { // Block Tags public static final Tag.Named BOOKSHELVES = makeCommonBlockTag("bookshelves"); public static final Tag.Named GEN_TERRAIN = makeBlockTag(BCLib.MOD_ID, "gen_terrain"); diff --git a/src/main/java/ru/bclib/mixin/client/EnchantingTableBlockMixin.java b/src/main/java/ru/bclib/mixin/client/EnchantingTableBlockMixin.java new file mode 100644 index 00000000..a78291c5 --- /dev/null +++ b/src/main/java/ru/bclib/mixin/client/EnchantingTableBlockMixin.java @@ -0,0 +1,46 @@ +package ru.bclib.mixin.client; + +import java.util.Random; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.EnchantmentTableBlock; +import net.minecraft.world.level.block.state.BlockState; +import ru.bclib.api.TagAPI; + +@Mixin(EnchantmentTableBlock.class) +public abstract class EnchantingTableBlockMixin extends Block { + public EnchantingTableBlockMixin(Properties settings) { + super(settings); + } + + @Inject(method = "animateTick", at = @At(value = "TAIL")) + private void be_onRandomDisplayTick(BlockState state, Level world, BlockPos pos, Random random, CallbackInfo info) { + for (int px = -2; px <= 2; ++px) { + for (int pz = -2; pz <= 2; ++pz) { + if (px > -2 && px < 2 && pz == -1) { + pz = 2; + } + if (random.nextInt(16) == 0) { + for (int py = 0; py <= 1; ++py) { + BlockPos blockPos = pos.offset(px, py, pz); + if (world.getBlockState(blockPos).is(TagAPI.BOOKSHELVES)) { + if (!world.isEmptyBlock(pos.offset(px / 2, 0, pz / 2))) { + break; + } + world.addParticle(ParticleTypes.ENCHANT, pos.getX() + 0.5, pos.getY() + 2.0, pos.getZ() + 0.5, px + random.nextFloat() - 0.5, py - random.nextFloat() - 1.0, pz + random.nextFloat() - 0.5); + } + } + } + } + } + + } +} diff --git a/src/main/java/ru/bclib/mixin/common/BoneMealItemMixin.java b/src/main/java/ru/bclib/mixin/common/BoneMealItemMixin.java index 01df4312..dc2bec59 100644 --- a/src/main/java/ru/bclib/mixin/common/BoneMealItemMixin.java +++ b/src/main/java/ru/bclib/mixin/common/BoneMealItemMixin.java @@ -16,7 +16,7 @@ import net.minecraft.world.level.biome.Biome.BiomeCategory; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.BlockState; -import ru.bclib.api.BCLibTags; +import ru.bclib.api.TagAPI; import ru.bclib.api.BiomeAPI; import ru.bclib.api.BonemealAPI; import ru.bclib.util.BlocksHelper; @@ -34,7 +34,7 @@ public class BoneMealItemMixin { BlockPos offseted = blockPos.relative(context.getClickedFace()); boolean endBiome = world.getBiome(offseted).getBiomeCategory() == BiomeCategory.THEEND; - if (world.getBlockState(blockPos).is(BCLibTags.END_GROUND)) { + if (world.getBlockState(blockPos).is(TagAPI.END_GROUND)) { boolean consume = false; if (world.getBlockState(blockPos).is(Blocks.END_STONE)) { BlockState nylium = bclib_getNylium(world, blockPos); 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/EnchantmentMenuMixin.java b/src/main/java/ru/bclib/mixin/common/EnchantmentMenuMixin.java new file mode 100644 index 00000000..d0af1dd8 --- /dev/null +++ b/src/main/java/ru/bclib/mixin/common/EnchantmentMenuMixin.java @@ -0,0 +1,140 @@ +package ru.bclib.mixin.common; + +import java.util.List; +import java.util.Random; + +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +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 net.minecraft.core.Registry; +import net.minecraft.world.Container; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.inventory.ContainerLevelAccess; +import net.minecraft.world.inventory.DataSlot; +import net.minecraft.world.inventory.EnchantmentMenu; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.enchantment.EnchantmentHelper; +import net.minecraft.world.item.enchantment.EnchantmentInstance; +import ru.bclib.api.TagAPI; + +@Mixin(EnchantmentMenu.class) +public abstract class EnchantmentMenuMixin extends AbstractContainerMenu { + @Final + @Shadow + private Container enchantSlots; + + @Final + @Shadow + private ContainerLevelAccess access; + + @Final + @Shadow + private Random random; + + @Final + @Shadow + private DataSlot enchantmentSeed; + + @Shadow + @Final + public int[] costs; + + @Shadow + @Final + public int[] enchantClue; + + @Shadow + @Final + public int[] levelClue; + + protected EnchantmentMenuMixin(MenuType type, int syncId) { + super(type, syncId); + } + + @Inject(method = "slotsChanged", at = @At("HEAD"), cancellable = true) + private void be_slotsChanged(Container inventory, CallbackInfo info) { + if (inventory == this.enchantSlots) { + ItemStack itemStack = inventory.getItem(0); + if (!itemStack.isEmpty() && itemStack.isEnchantable()) { + this.access.execute((world, blockPos) -> { + int i = 0; + + int j; + for (j = -1; j <= 1; ++j) { + for (int k = -1; k <= 1; ++k) { + if ((j != 0 || k != 0) && world.isEmptyBlock(blockPos.offset(k, 0, j)) && world.isEmptyBlock(blockPos.offset(k, 1, j))) { + if (world.getBlockState(blockPos.offset(k * 2, 0, j * 2)).is(TagAPI.BOOKSHELVES)) { + ++i; + } + + if (world.getBlockState(blockPos.offset(k * 2, 1, j * 2)).is(TagAPI.BOOKSHELVES)) { + ++i; + } + + if (k != 0 && j != 0) { + if (world.getBlockState(blockPos.offset(k * 2, 0, j)).is(TagAPI.BOOKSHELVES)) { + ++i; + } + + if (world.getBlockState(blockPos.offset(k * 2, 1, j)).is(TagAPI.BOOKSHELVES)) { + ++i; + } + + if (world.getBlockState(blockPos.offset(k, 0, j * 2)).is(TagAPI.BOOKSHELVES)) { + ++i; + } + + if (world.getBlockState(blockPos.offset(k, 1, j * 2)).is(TagAPI.BOOKSHELVES)) { + ++i; + } + } + } + } + } + + random.setSeed(enchantmentSeed.get()); + + for (j = 0; j < 3; ++j) { + costs[j] = EnchantmentHelper.getEnchantmentCost(this.random, j, i, itemStack); + enchantClue[j] = -1; + levelClue[j] = -1; + if (costs[j] < j + 1) { + costs[j] = 0; + } + } + + for (j = 0; j < 3; ++j) { + if (this.costs[j] > 0) { + List list = this.getEnchantmentList(itemStack, j, this.costs[j]); + if (list != null && !list.isEmpty()) { + EnchantmentInstance enchantmentLevelEntry = (EnchantmentInstance) list.get(this.random.nextInt(list.size())); + enchantClue[j] = Registry.ENCHANTMENT.getId(enchantmentLevelEntry.enchantment); + levelClue[j] = enchantmentLevelEntry.level; + } + } + } + + broadcastChanges(); + }); + } + else { + for (int i = 0; i < 3; ++i) { + costs[i] = 0; + enchantClue[i] = -1; + levelClue[i] = -1; + } + } + info.cancel(); + } + } + + @Shadow + private List getEnchantmentList(ItemStack stack, int slot, int level) { + return null; + } +} 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..66c4ae28 --- /dev/null +++ b/src/main/java/ru/bclib/recipes/FurnaceRecipe.java @@ -0,0 +1,102 @@ +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; +import ru.bclib.config.PathConfig; + +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 checkConfig(PathConfig config) { + exist = config.getBoolean("furnace", id.getPath(), true); + return this; + } + + 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..06a15b2b --- /dev/null +++ b/src/main/java/ru/bclib/recipes/GridRecipe.java @@ -0,0 +1,126 @@ +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; +import ru.bclib.config.PathConfig; + +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 checkConfig(PathConfig config) { + exist = config.getBoolean("grid", id.getPath(), true); + return this; + } + + 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..45947b4c --- /dev/null +++ b/src/main/java/ru/bclib/recipes/SmithingTableRecipe.java @@ -0,0 +1,106 @@ +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; +import ru.bclib.config.PathConfig; + +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 boolean exist; + + private SmithingTableRecipe() {} + + public SmithingTableRecipe checkConfig(PathConfig config) { + exist = config.getBoolean("smithing", id.getPath(), true); + return this; + } + + 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 (!exist) { + return; + } + + 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/java/ru/bclib/util/StructureHelper.java b/src/main/java/ru/bclib/util/StructureHelper.java index f0cc810a..205676bc 100644 --- a/src/main/java/ru/bclib/util/StructureHelper.java +++ b/src/main/java/ru/bclib/util/StructureHelper.java @@ -27,7 +27,7 @@ import net.minecraft.world.level.levelgen.structure.BoundingBox; import net.minecraft.world.level.levelgen.structure.templatesystem.StructurePlaceSettings; import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate; import net.minecraft.world.level.material.Material; -import ru.bclib.api.BCLibTags; +import ru.bclib.api.TagAPI; public class StructureHelper { private static final Direction[] DIR = BlocksHelper.makeHorizontal(); @@ -264,7 +264,7 @@ public class StructureHelper { private static boolean isTerrainNear(WorldGenLevel world, BlockPos pos) { for (Direction dir: BlocksHelper.DIRECTIONS) { - if (world.getBlockState(pos.relative(dir)).is(BCLibTags.GEN_TERRAIN)) { + if (world.getBlockState(pos.relative(dir)).is(TagAPI.GEN_TERRAIN)) { return true; } } @@ -344,7 +344,7 @@ public class StructureHelper { private static boolean ignore(BlockState state) { return state.getMaterial().isReplaceable() || !state.getFluidState().isEmpty() || - state.is(BCLibTags.END_GROUND) || + state.is(TagAPI.END_GROUND) || state.is(BlockTags.LOGS) || state.is(BlockTags.LEAVES) || state.getMaterial().equals(Material.PLANT) || @@ -362,7 +362,7 @@ public class StructureHelper { for (int y = bounds.y1; y >= bounds.y0; y--) { mut.setY(y); BlockState state = world.getBlockState(mut); - if (state.is(BCLibTags.END_GROUND) && !world.getBlockState(mut.above()).getMaterial().isSolidBlocking()) { + if (state.is(TagAPI.END_GROUND) && !world.getBlockState(mut.above()).getMaterial().isSolidBlocking()) { BlocksHelper.setWithoutUpdate(world, mut, top); } } diff --git a/src/main/java/ru/bclib/world/features/NBTStructureFeature.java b/src/main/java/ru/bclib/world/features/NBTStructureFeature.java index 7422e599..27bf3d1d 100644 --- a/src/main/java/ru/bclib/world/features/NBTStructureFeature.java +++ b/src/main/java/ru/bclib/world/features/NBTStructureFeature.java @@ -22,7 +22,7 @@ import net.minecraft.world.level.levelgen.structure.BoundingBox; import net.minecraft.world.level.levelgen.structure.templatesystem.StructurePlaceSettings; import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate; import net.minecraft.world.level.levelgen.surfacebuilders.SurfaceBuilderConfiguration; -import ru.bclib.api.BCLibTags; +import ru.bclib.api.TagAPI; import ru.bclib.api.BiomeAPI; import ru.bclib.util.BlocksHelper; import ru.bclib.world.processors.DestructionStructureProcessor; @@ -124,11 +124,11 @@ public abstract class NBTStructureFeature extends DefaultFeature { mut.setZ(z); mut.setY(surfMax); BlockState state = world.getBlockState(mut); - if (!state.is(BCLibTags.GEN_TERRAIN) && state.isFaceSturdy(world, mut, Direction.DOWN)) { + if (!state.is(TagAPI.GEN_TERRAIN) && state.isFaceSturdy(world, mut, Direction.DOWN)) { for (int i = 0; i < 10; i++) { mut.setY(mut.getY() - 1); BlockState stateSt = world.getBlockState(mut); - if (!stateSt.is(BCLibTags.GEN_TERRAIN)) { + if (!stateSt.is(TagAPI.GEN_TERRAIN)) { if (merge == TerrainMerge.SURFACE) { SurfaceBuilderConfiguration config = world.getBiome(mut).getGenerationSettings().getSurfaceBuilderConfig(); boolean isTop = mut.getY() == surfMax && state.getMaterial().isSolidBlocking(); @@ -140,7 +140,7 @@ public abstract class NBTStructureFeature extends DefaultFeature { } } else { - if (stateSt.is(BCLibTags.END_GROUND) && state.getMaterial().isSolidBlocking()) { + if (stateSt.is(TagAPI.END_GROUND) && state.getMaterial().isSolidBlocking()) { if (merge == TerrainMerge.SURFACE) { SurfaceBuilderConfiguration config = world.getBiome(mut).getGenerationSettings() .getSurfaceBuilderConfig(); diff --git a/src/main/resources/bclib.mixins.client.json b/src/main/resources/bclib.mixins.client.json index 9e2748ea..d063027b 100644 --- a/src/main/resources/bclib.mixins.client.json +++ b/src/main/resources/bclib.mixins.client.json @@ -4,7 +4,8 @@ "package": "ru.bclib.mixin.client", "compatibilityLevel": "JAVA_8", "client": [ - "ModelBakeryMixin" + "EnchantingTableBlockMixin", + "ModelBakeryMixin" ], "injectors": { "defaultRequire": 1 diff --git a/src/main/resources/bclib.mixins.common.json b/src/main/resources/bclib.mixins.common.json index 2d182b8c..e90d188a 100644 --- a/src/main/resources/bclib.mixins.common.json +++ b/src/main/resources/bclib.mixins.common.json @@ -4,6 +4,11 @@ "package": "ru.bclib.mixin.common", "compatibilityLevel": "JAVA_8", "mixins": [ + "ComposterBlockAccessor", + "PotionBrewingAccessor", + "RecipeManagerAccessor", + "EnchantmentMenuMixin", + "RecipeManagerMixin", "BoneMealItemMixin", "TagLoaderMixin" ],