diff --git a/build.gradle b/build.gradle index 335c2ffb..e8a4b095 100644 --- a/build.gradle +++ b/build.gradle @@ -127,8 +127,13 @@ repositories { url 'https://jitpack.io' content { includeGroup 'com.github.thedarkcolour' } } - flatDir { - dir 'libs' + maven { + name = "Modrinth" + url = "https://api.modrinth.com/maven" + content { + includeModule("maven.modrinth", "oculus") + includeModule("maven.modrinth", "embeddium") + } } } @@ -151,6 +156,10 @@ dependencies { // ModKit DEV ONLY implementation fg.deobf('com.github.thedarkcolour:ModKit:78f393bfac') + // Oculus + Embeddium OPTIONAL + implementation fg.deobf('maven.modrinth:oculus:1.20.1-1.6.9') + implementation fg.deobf('maven.modrinth:embeddium:0.2.12+mc1.20.1') + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.2' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.2' } diff --git a/changelog.md b/changelog.md index bf1284d9..f7bef2c1 100644 --- a/changelog.md +++ b/changelog.md @@ -4,6 +4,10 @@ - Allow extracting water from wooden crucibles using water bottles. - Watering cans now accelerate crops from Pam's Harvestcraft 2 Crops - Fixed a crash that happened with Ex Deorum barrels and crucibles when logging out of a world. +- Fixed infested leaves showing as invisible when using Oculus Shaders. +- It is now possible to see the melting rates for crucible heat sources in JEI. +- Barrels can now mix fluids with liquids placed on top of the (ex. water on top of a lava barrel creates obsidian) +- Optimized recipe lookups for the sieve. ## Ex Deorum 1.9 - Fixed incompatibility with SkyblockBuilder where player would not receive torch/watering can and Ex Deorum advancements diff --git a/src/generated/resources/.cache/93943142017732f21fbc4fa325d116c728b69767 b/src/generated/resources/.cache/93943142017732f21fbc4fa325d116c728b69767 index 0099633b..b159de50 100644 --- a/src/generated/resources/.cache/93943142017732f21fbc4fa325d116c728b69767 +++ b/src/generated/resources/.cache/93943142017732f21fbc4fa325d116c728b69767 @@ -1,2 +1,2 @@ -// 1.20.1 2023-11-25T22:05:28.9763125 ModKit Language: en_us for mod 'exdeorum' -78936365b3ddf8e22eef4418bb1a98a11abb2c4b assets/exdeorum/lang/en_us.json +// 1.20.1 2023-12-15T22:39:48.8310527 ModKit Language: en_us for mod 'exdeorum' +88329666bba1a5ffe3105b55e2bf2dc58d402008 assets/exdeorum/lang/en_us.json diff --git a/src/generated/resources/.cache/9fb1092f32d4fcbf9e061ffd718d4ec689c6c95e b/src/generated/resources/.cache/9fb1092f32d4fcbf9e061ffd718d4ec689c6c95e index 53968868..3b87db7f 100644 --- a/src/generated/resources/.cache/9fb1092f32d4fcbf9e061ffd718d4ec689c6c95e +++ b/src/generated/resources/.cache/9fb1092f32d4fcbf9e061ffd718d4ec689c6c95e @@ -1,4 +1,4 @@ -// 1.20.1 2023-11-25T20:27:03.8436949 Recipes +// 1.20.1 2023-12-15T22:04:05.0210898 Recipes 5ad481a0c376c1a1785a5d3b992064d0ec0bf3b0 data/exdeorum/advancements/recipes/food/end_cake.json 25dd027e844a72b03c95dbe5e3c3dd8c738ceb00 data/exdeorum/advancements/recipes/misc/acacia_barrel.json 376be94a64c9ca97a9ea2346547b6e617f13a815 data/exdeorum/advancements/recipes/misc/acacia_crucible.json @@ -157,20 +157,18 @@ f17f12ac67e700f7838cb3bab740ec254bbfe13c data/exdeorum/recipes/barrel_compost/tw 653a42a46a6bd977a2eddea7336df4beabbbeecf data/exdeorum/recipes/barrel_compost/vine.json c4ecb4272c220282de403852031b3ca92651d91c data/exdeorum/recipes/barrel_compost/weeping_vines.json 5677e23fdc74130523d602ebf9e557f659af57c5 data/exdeorum/recipes/barrel_compost/wheat.json +d08b7a270dff3f7bb45338798227a69d775e7c32 data/exdeorum/recipes/barrel_fluid_mixing/blackstone.json +1a87de0d21b9677fda38f7a520cbffbdc41d8532 data/exdeorum/recipes/barrel_fluid_mixing/netherrack.json +8b42ca284eaea721e8e7589e5fb0b16ccbe66ee5 data/exdeorum/recipes/barrel_fluid_mixing/obsidian.json +7cfc5db0d6fbb804a7bd1d3bbbbace986d90f3c4 data/exdeorum/recipes/barrel_fluid_mixing/stone.json bdcdeae9d06028ce943d06c367b58677efe03fa8 data/exdeorum/recipes/barrel_mixing/clay.json 72f969f4db1f82a627df573c866a1b291e540a0a data/exdeorum/recipes/barrel_mixing/end_stone.json 37f73e219fda3c6f56bf55f8ec7f97586ecdbae1 data/exdeorum/recipes/barrel_mixing/ice.json 6c31cd3a1b2204561b123875fae0f7aebcdf7b16 data/exdeorum/recipes/barrel_mixing/magma_cream.json -e77fbe2d5aa36f25acad8e5beabe8bffcb5a5099 data/exdeorum/recipes/barrel_mixing/netherrack.json -6c5b774d38127e4d3b9aac7f2206ddf7bfb23de4 data/exdeorum/recipes/barrel_mixing/netherrack_from_porcelain_bucket.json -4903a160d3b4cd35508b2a79107fd3ed05ff0a81 data/exdeorum/recipes/barrel_mixing/obsidian.json -7bdcda3fd6af00a14e3eb54c302c7933bd6206b9 data/exdeorum/recipes/barrel_mixing/obsidian_from_porcelain_bucket.json 1c43bcc290f6dc85e2d292e48d5b43067769c44e data/exdeorum/recipes/barrel_mixing/slime_block.json 675094640c64c34e3812b8a667761c866307c752 data/exdeorum/recipes/barrel_mixing/slime_block_from_porcelain_bucket.json 08689e3ea37eae1dbf2ff54f2910c211f40f9b16 data/exdeorum/recipes/barrel_mixing/soul_sand.json 173f8cfa024c85c843c27a8acc36285e7cd34d03 data/exdeorum/recipes/barrel_mixing/soul_soil.json -f36d0285aee351f12b653d98aaeb390012eea0ed data/exdeorum/recipes/barrel_mixing/stone.json -0b928c9adfdcb12d12254aba04d7a19ef59d3dab data/exdeorum/recipes/barrel_mixing/stone_from_porcelain_bucket.json 7da00b96ebc2fed2bee34e97e4663f701e624e79 data/exdeorum/recipes/basalt.json 86419d8f205f3756c57a5701407b78d21cec595c data/exdeorum/recipes/birch_barrel.json a9b16fe05fac026f5fc6e843165ac6b3c4e49ad9 data/exdeorum/recipes/birch_crucible.json diff --git a/src/generated/resources/assets/exdeorum/lang/en_us.json b/src/generated/resources/assets/exdeorum/lang/en_us.json index acfea613..8ceb64bf 100644 --- a/src/generated/resources/assets/exdeorum/lang/en_us.json +++ b/src/generated/resources/assets/exdeorum/lang/en_us.json @@ -121,6 +121,7 @@ "generator.exdeorum.void_world": "Void World", "gui.exdeorum.category.barrel_compost": "Barrel Compost", "gui.exdeorum.category.barrel_compost.volume": "Compost: %s", + "gui.exdeorum.category.barrel_fluid_mixing": "Barrel Fluid Mixing", "gui.exdeorum.category.barrel_mixing": "Barrel Mixing", "gui.exdeorum.category.crucible_heat_source": "Crucible Heat Sources", "gui.exdeorum.category.crucible_heat_source.multiplier": "Melt Rate: %sx", diff --git a/src/generated/resources/data/exdeorum/recipes/barrel_fluid_mixing/blackstone.json b/src/generated/resources/data/exdeorum/recipes/barrel_fluid_mixing/blackstone.json new file mode 100644 index 00000000..c9dd5057 --- /dev/null +++ b/src/generated/resources/data/exdeorum/recipes/barrel_fluid_mixing/blackstone.json @@ -0,0 +1,7 @@ +{ + "type": "exdeorum:barrel_fluid_mixing", + "additive_fluid": "exdeorum:witch_water", + "base_fluid": "minecraft:lava", + "base_fluid_amount": 1000, + "result": "minecraft:blackstone" +} \ No newline at end of file diff --git a/src/generated/resources/data/exdeorum/recipes/barrel_fluid_mixing/netherrack.json b/src/generated/resources/data/exdeorum/recipes/barrel_fluid_mixing/netherrack.json new file mode 100644 index 00000000..59a2770e --- /dev/null +++ b/src/generated/resources/data/exdeorum/recipes/barrel_fluid_mixing/netherrack.json @@ -0,0 +1,7 @@ +{ + "type": "exdeorum:barrel_fluid_mixing", + "additive_fluid": "minecraft:lava", + "base_fluid": "exdeorum:witch_water", + "base_fluid_amount": 1000, + "result": "minecraft:netherrack" +} \ No newline at end of file diff --git a/src/generated/resources/data/exdeorum/recipes/barrel_fluid_mixing/obsidian.json b/src/generated/resources/data/exdeorum/recipes/barrel_fluid_mixing/obsidian.json new file mode 100644 index 00000000..fdb127e2 --- /dev/null +++ b/src/generated/resources/data/exdeorum/recipes/barrel_fluid_mixing/obsidian.json @@ -0,0 +1,7 @@ +{ + "type": "exdeorum:barrel_fluid_mixing", + "additive_fluid": "minecraft:water", + "base_fluid": "minecraft:lava", + "base_fluid_amount": 1000, + "result": "minecraft:obsidian" +} \ No newline at end of file diff --git a/src/generated/resources/data/exdeorum/recipes/barrel_fluid_mixing/stone.json b/src/generated/resources/data/exdeorum/recipes/barrel_fluid_mixing/stone.json new file mode 100644 index 00000000..d5562c1e --- /dev/null +++ b/src/generated/resources/data/exdeorum/recipes/barrel_fluid_mixing/stone.json @@ -0,0 +1,7 @@ +{ + "type": "exdeorum:barrel_fluid_mixing", + "additive_fluid": "minecraft:lava", + "base_fluid": "minecraft:water", + "base_fluid_amount": 1000, + "result": "minecraft:stone" +} \ No newline at end of file diff --git a/src/generated/resources/data/exdeorum/recipes/barrel_mixing/netherrack.json b/src/generated/resources/data/exdeorum/recipes/barrel_mixing/netherrack.json deleted file mode 100644 index f0860f23..00000000 --- a/src/generated/resources/data/exdeorum/recipes/barrel_mixing/netherrack.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "type": "exdeorum:barrel_mixing", - "fluid": "minecraft:lava", - "fluid_amount": 1000, - "ingredient": { - "item": "exdeorum:witch_water_bucket" - }, - "result": "minecraft:netherrack" -} \ No newline at end of file diff --git a/src/generated/resources/data/exdeorum/recipes/barrel_mixing/netherrack_from_porcelain_bucket.json b/src/generated/resources/data/exdeorum/recipes/barrel_mixing/netherrack_from_porcelain_bucket.json deleted file mode 100644 index 01e2a8eb..00000000 --- a/src/generated/resources/data/exdeorum/recipes/barrel_mixing/netherrack_from_porcelain_bucket.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "type": "exdeorum:barrel_mixing", - "fluid": "minecraft:lava", - "fluid_amount": 1000, - "ingredient": { - "item": "exdeorum:porcelain_witch_water_bucket" - }, - "result": "minecraft:netherrack" -} \ No newline at end of file diff --git a/src/generated/resources/data/exdeorum/recipes/barrel_mixing/obsidian.json b/src/generated/resources/data/exdeorum/recipes/barrel_mixing/obsidian.json deleted file mode 100644 index 13029537..00000000 --- a/src/generated/resources/data/exdeorum/recipes/barrel_mixing/obsidian.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "type": "exdeorum:barrel_mixing", - "fluid": "minecraft:lava", - "fluid_amount": 1000, - "ingredient": { - "item": "minecraft:water_bucket" - }, - "result": "minecraft:obsidian" -} \ No newline at end of file diff --git a/src/generated/resources/data/exdeorum/recipes/barrel_mixing/obsidian_from_porcelain_bucket.json b/src/generated/resources/data/exdeorum/recipes/barrel_mixing/obsidian_from_porcelain_bucket.json deleted file mode 100644 index 006def43..00000000 --- a/src/generated/resources/data/exdeorum/recipes/barrel_mixing/obsidian_from_porcelain_bucket.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "type": "exdeorum:barrel_mixing", - "fluid": "minecraft:lava", - "fluid_amount": 1000, - "ingredient": { - "item": "exdeorum:porcelain_water_bucket" - }, - "result": "minecraft:obsidian" -} \ No newline at end of file diff --git a/src/generated/resources/data/exdeorum/recipes/barrel_mixing/stone.json b/src/generated/resources/data/exdeorum/recipes/barrel_mixing/stone.json deleted file mode 100644 index 19be08b8..00000000 --- a/src/generated/resources/data/exdeorum/recipes/barrel_mixing/stone.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "type": "exdeorum:barrel_mixing", - "fluid": "minecraft:water", - "fluid_amount": 1000, - "ingredient": { - "item": "minecraft:lava_bucket" - }, - "result": "minecraft:stone" -} \ No newline at end of file diff --git a/src/generated/resources/data/exdeorum/recipes/barrel_mixing/stone_from_porcelain_bucket.json b/src/generated/resources/data/exdeorum/recipes/barrel_mixing/stone_from_porcelain_bucket.json deleted file mode 100644 index 7df256fb..00000000 --- a/src/generated/resources/data/exdeorum/recipes/barrel_mixing/stone_from_porcelain_bucket.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "type": "exdeorum:barrel_mixing", - "fluid": "minecraft:water", - "fluid_amount": 1000, - "ingredient": { - "item": "exdeorum:porcelain_lava_bucket" - }, - "result": "minecraft:stone" -} \ No newline at end of file diff --git a/src/main/java/thedarkcolour/exdeorum/block/BarrelBlock.java b/src/main/java/thedarkcolour/exdeorum/block/BarrelBlock.java index a0108246..c277a873 100644 --- a/src/main/java/thedarkcolour/exdeorum/block/BarrelBlock.java +++ b/src/main/java/thedarkcolour/exdeorum/block/BarrelBlock.java @@ -91,4 +91,11 @@ public class BarrelBlock extends Block implements EntityBlock { super.onRemove(state, level, pos, newState, isMoving); } + + @Override + public void neighborChanged(BlockState pState, Level level, BlockPos pos, Block pBlock, BlockPos pFromPos, boolean pIsMoving) { + if (level.getBlockEntity(pos) instanceof BarrelBlockEntity barrel) { + barrel.tryInWorldFluidMixing(); + } + } } diff --git a/src/main/java/thedarkcolour/exdeorum/block/InfestedLeavesBlock.java b/src/main/java/thedarkcolour/exdeorum/block/InfestedLeavesBlock.java index af559589..fa72e650 100644 --- a/src/main/java/thedarkcolour/exdeorum/block/InfestedLeavesBlock.java +++ b/src/main/java/thedarkcolour/exdeorum/block/InfestedLeavesBlock.java @@ -40,6 +40,7 @@ import net.minecraft.world.phys.HitResult; import net.minecraftforge.fml.loading.FMLEnvironment; import org.jetbrains.annotations.Nullable; import thedarkcolour.exdeorum.blockentity.InfestedLeavesBlockEntity; +import thedarkcolour.exdeorum.client.RenderUtil; import thedarkcolour.exdeorum.config.EConfig; import thedarkcolour.exdeorum.registry.EBlockEntities; @@ -89,6 +90,6 @@ public class InfestedLeavesBlock extends LeavesBlock implements EntityBlock { @Override public RenderShape getRenderShape(BlockState pState) { - return EConfig.CLIENT_SPEC.isLoaded() && EConfig.CLIENT.useFastInfestedLeaves.get() ? RenderShape.MODEL : RenderShape.INVISIBLE; + return (EConfig.CLIENT_SPEC.isLoaded() && EConfig.CLIENT.useFastInfestedLeaves.get()) || RenderUtil.IRIS_ACCESS.areShadersEnabled() ? RenderShape.MODEL : RenderShape.INVISIBLE; } } \ No newline at end of file diff --git a/src/main/java/thedarkcolour/exdeorum/block/WitchWaterBlock.java b/src/main/java/thedarkcolour/exdeorum/block/WitchWaterBlock.java index efd51975..75b9dea7 100644 --- a/src/main/java/thedarkcolour/exdeorum/block/WitchWaterBlock.java +++ b/src/main/java/thedarkcolour/exdeorum/block/WitchWaterBlock.java @@ -18,14 +18,9 @@ package thedarkcolour.exdeorum.block; -import dev.latvian.mods.kubejs.core.ServerLevelKJS; import net.minecraft.core.BlockPos; import net.minecraft.nbt.NbtOps; -import net.minecraft.server.level.ServerLevel; import net.minecraft.world.Difficulty; -import net.minecraft.world.damagesource.DamageSource; -import net.minecraft.world.damagesource.DamageSources; -import net.minecraft.world.effect.MobEffect; import net.minecraft.world.effect.MobEffectInstance; import net.minecraft.world.effect.MobEffects; import net.minecraft.world.entity.*; @@ -33,7 +28,6 @@ import net.minecraft.world.entity.animal.MushroomCow; import net.minecraft.world.entity.animal.Rabbit; import net.minecraft.world.entity.animal.axolotl.Axolotl; import net.minecraft.world.entity.monster.Creeper; -import net.minecraft.world.entity.monster.Witch; import net.minecraft.world.entity.monster.Zombie; import net.minecraft.world.entity.npc.Villager; import net.minecraft.world.entity.npc.VillagerProfession; diff --git a/src/main/java/thedarkcolour/exdeorum/blockentity/BarrelBlockEntity.java b/src/main/java/thedarkcolour/exdeorum/blockentity/BarrelBlockEntity.java index 87128aae..db52a781 100644 --- a/src/main/java/thedarkcolour/exdeorum/blockentity/BarrelBlockEntity.java +++ b/src/main/java/thedarkcolour/exdeorum/blockentity/BarrelBlockEntity.java @@ -38,6 +38,7 @@ import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.BlockEntityTicker; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.material.Fluid; import net.minecraft.world.level.material.Fluids; import net.minecraftforge.common.ForgeMod; import net.minecraftforge.common.capabilities.Capability; @@ -56,11 +57,13 @@ import org.jetbrains.annotations.NotNull; import thedarkcolour.exdeorum.client.CompostColors; import thedarkcolour.exdeorum.config.EConfig; import thedarkcolour.exdeorum.recipe.RecipeUtil; +import thedarkcolour.exdeorum.recipe.barrel.BarrelFluidMixingRecipe; import thedarkcolour.exdeorum.registry.EBlockEntities; import thedarkcolour.exdeorum.registry.EFluids; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import javax.swing.text.html.Option; public class BarrelBlockEntity extends EBlockEntity { private static final int MOSS_SPREAD_RANGE = 2; @@ -131,7 +134,7 @@ public class BarrelBlockEntity extends EBlockEntity { } // Returns true if there are no solid ingredients (can a fluid be inserted?) - public boolean isEmptySolids() { + public boolean canInsertFluid() { return compost <= 0 && item.getStackInSlot(0).isEmpty(); } @@ -177,7 +180,7 @@ public class BarrelBlockEntity extends EBlockEntity { } // Handle item fluid interaction - if (isEmptySolids()) { + if (canInsertFluid()) { var wasBurning = isBurning(); if (FluidUtil.interactWithFluidHandler(player, hand, tank)) { @@ -186,6 +189,22 @@ public class BarrelBlockEntity extends EBlockEntity { } return InteractionResult.sidedSuccess(level.isClientSide); + } else { + var heldItem = player.getItemInHand(hand); + var optionalBool = heldItem.getCapability(ForgeCapabilities.FLUID_HANDLER_ITEM).map(item -> { + var fluidInTank = item.getFluidInTank(0); + if (fluidInTank.getAmount() >= 1000) { + if (!level.isClientSide) { + return tryFluidMixing(fluidInTank.getFluid()); + } + return true; + } + + return false; + }); + if (optionalBool.isPresent() && optionalBool.get()) { + return InteractionResult.sidedSuccess(level.isClientSide); + } } } @@ -313,11 +332,33 @@ public class BarrelBlockEntity extends EBlockEntity { } } + public boolean tryInWorldFluidMixing() { + if (!tank.isEmpty() && item.getStackInSlot(0).isEmpty()) { + var aboveFluid = level.getBlockState(worldPosition.above()).getFluidState().getType(); + + return aboveFluid != Fluids.EMPTY && tryFluidMixing(aboveFluid); + } else { + return false; + } + } + + private boolean tryFluidMixing(Fluid additive) { + BarrelFluidMixingRecipe recipe = RecipeUtil.getFluidMixingRecipe(tank.getFluid(), additive); + + if (recipe != null) { + tank.drain(recipe.baseFluidAmount, IFluidHandler.FluidAction.EXECUTE); + setItem(new ItemStack(recipe.result)); + return true; + } + + return false; + } + private boolean tryComposting(ItemStack stack, boolean simulate) { if (simulate) { return RecipeUtil.isCompostable(stack); } else { - var recipe = RecipeUtil.getBarrelCompostRecipe(stack.getItem()); + var recipe = RecipeUtil.getBarrelCompostRecipe(stack); if (recipe != null) { addCompost(stack, recipe.getVolume()); return true; @@ -447,6 +488,11 @@ public class BarrelBlockEntity extends EBlockEntity { return (stack.getItem() instanceof BowlFoodItem || stack.getItem() == Items.SUSPICIOUS_STEW) ? new ItemStack(Items.BOWL) : stack.getCraftingRemainingItem(); } + @Override + public void onLoad() { + tryInWorldFluidMixing(); + } + // Inner class private class ItemHandler extends ItemStackHandler { @Override @@ -475,6 +521,7 @@ public class BarrelBlockEntity extends EBlockEntity { return ItemHandlerHelper.copyStackWithSize(stack, stack.getCount() - 1); } } else { + tryInWorldFluidMixing(); return stack; } } @@ -504,7 +551,12 @@ public class BarrelBlockEntity extends EBlockEntity { @Override public boolean isFluidValid(FluidStack stack) { - return !isBrewing() && BarrelBlockEntity.this.isEmptySolids(); + return !isBrewing() && BarrelBlockEntity.this.canInsertFluid(); + } + + @Override + protected void onContentsChanged() { + BarrelBlockEntity.this.tryInWorldFluidMixing(); } } } diff --git a/src/main/java/thedarkcolour/exdeorum/blockentity/SieveBlockEntity.java b/src/main/java/thedarkcolour/exdeorum/blockentity/SieveBlockEntity.java index 7fb554b5..6b130cb4 100644 --- a/src/main/java/thedarkcolour/exdeorum/blockentity/SieveBlockEntity.java +++ b/src/main/java/thedarkcolour/exdeorum/blockentity/SieveBlockEntity.java @@ -250,7 +250,7 @@ public class SieveBlockEntity extends EBlockEntity { var rand = this.level.random; var limitDrops = this.contents.getItem() == Items.MOSS_BLOCK && EConfig.SERVER.limitMossSieveDrops.get(); - for (SieveRecipe recipe : RecipeUtil.getSieveRecipes(level.getRecipeManager(), this.mesh.getItem(), this.contents)) { + for (SieveRecipe recipe : RecipeUtil.getSieveRecipes(this.mesh.getItem(), this.contents)) { var amount = recipe.resultAmount.getInt(context); for (int i = 0; i < this.fortune; i++) { diff --git a/src/main/java/thedarkcolour/exdeorum/client/RenderUtil.java b/src/main/java/thedarkcolour/exdeorum/client/RenderUtil.java index 83041d55..db38981b 100644 --- a/src/main/java/thedarkcolour/exdeorum/client/RenderUtil.java +++ b/src/main/java/thedarkcolour/exdeorum/client/RenderUtil.java @@ -26,6 +26,7 @@ import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.blaze3d.vertex.VertexFormat; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import net.irisshaders.iris.api.v0.IrisApi; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderStateShard; @@ -64,8 +65,10 @@ public class RenderUtil { public static TextureAtlas blockAtlas; public static ShaderInstance renderTypeTintedCutoutMippedShader; private static final Map LEAF_BAKED_MODELS = new Object2ObjectOpenHashMap<>(); + public static final IrisAccess IRIS_ACCESS; static { + // todo remove these caches, google cache is slow TOP_RENDER_TYPES = CacheBuilder.newBuilder().maximumSize(10).build(new CacheLoader<>() { @Override public RenderType load(Block key) { @@ -88,21 +91,15 @@ public class RenderUtil { return sprite; } }); - } - public static BakedModel getMimicModel(BlockState state) { - var model = LEAF_BAKED_MODELS.get(state); - - if (model == null) { - model = Minecraft.getInstance().getBlockRenderer().getBlockModel(state); - - if (model == Minecraft.getInstance().getModelManager().getMissingModel()) { - model = Minecraft.getInstance().getBlockRenderer().getBlockModel(Blocks.OAK_LEAVES.defaultBlockState()); - } - - LEAF_BAKED_MODELS.put(state, model); + IrisAccess irisAccess; + try { + Class.forName("net.irisshaders.iris.api.v0.IrisApi"); + irisAccess = () -> IrisApi.getInstance().isShaderPackInUse(); + } catch (ClassNotFoundException e) { + irisAccess = () -> false; } - return model; + IRIS_ACCESS = irisAccess; } public static boolean isMissingTexture(TextureAtlasSprite sprite) { @@ -179,4 +176,8 @@ public class RenderUtil { public static int getFluidColor(Fluid fluid, Level level, BlockPos pos) { return IClientFluidTypeExtensions.of(fluid).getTintColor(fluid.defaultFluidState(), level, pos); } + + public interface IrisAccess { + boolean areShadersEnabled(); + } } diff --git a/src/main/java/thedarkcolour/exdeorum/client/ter/InfestedLeavesRenderer.java b/src/main/java/thedarkcolour/exdeorum/client/ter/InfestedLeavesRenderer.java index 0eb1e47d..00e9f8fe 100644 --- a/src/main/java/thedarkcolour/exdeorum/client/ter/InfestedLeavesRenderer.java +++ b/src/main/java/thedarkcolour/exdeorum/client/ter/InfestedLeavesRenderer.java @@ -24,6 +24,7 @@ import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; import net.minecraft.world.level.block.Blocks; import net.minecraftforge.client.model.data.ModelData; +import thedarkcolour.exdeorum.ExDeorum; import thedarkcolour.exdeorum.blockentity.InfestedLeavesBlockEntity; import thedarkcolour.exdeorum.client.RenderUtil; import thedarkcolour.exdeorum.config.EConfig; @@ -31,7 +32,7 @@ import thedarkcolour.exdeorum.config.EConfig; public class InfestedLeavesRenderer implements BlockEntityRenderer { @Override public void render(InfestedLeavesBlockEntity te, float partialTicks, PoseStack stack, MultiBufferSource buffer, int light, int unused) { - if (EConfig.CLIENT.useFastInfestedLeaves.get()) return; + if (EConfig.CLIENT.useFastInfestedLeaves.get() || RenderUtil.IRIS_ACCESS.areShadersEnabled()) return; var mc = Minecraft.getInstance(); var state = te.getMimic(); diff --git a/src/main/java/thedarkcolour/exdeorum/compat/jei/BarrelMixingCategory.java b/src/main/java/thedarkcolour/exdeorum/compat/jei/BarrelMixingCategory.java index 500fa905..64bab9cb 100644 --- a/src/main/java/thedarkcolour/exdeorum/compat/jei/BarrelMixingCategory.java +++ b/src/main/java/thedarkcolour/exdeorum/compat/jei/BarrelMixingCategory.java @@ -27,13 +27,17 @@ import mezz.jei.api.recipe.RecipeIngredientRole; import mezz.jei.api.recipe.RecipeType; import mezz.jei.api.recipe.category.IRecipeCategory; import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.core.NonNullList; import net.minecraft.network.chat.Component; +import net.minecraft.world.Container; import net.minecraft.world.item.ItemStack; +import thedarkcolour.exdeorum.ExDeorum; import thedarkcolour.exdeorum.data.TranslationKeys; +import thedarkcolour.exdeorum.recipe.barrel.BarrelFluidMixingRecipe; import thedarkcolour.exdeorum.recipe.barrel.BarrelMixingRecipe; import thedarkcolour.exdeorum.registry.EBlocks; -public class BarrelMixingCategory implements IRecipeCategory { +public abstract class BarrelMixingCategory implements IRecipeCategory { public static final int WIDTH = 120; public static final int HEIGHT = 18; @@ -44,18 +48,13 @@ public class BarrelMixingCategory implements IRecipeCategory private final IDrawable icon; private final Component title; - public BarrelMixingCategory(IGuiHelper helper, IDrawable plus, IDrawable arrow) { + public BarrelMixingCategory(IGuiHelper helper, IDrawable plus, IDrawable arrow, String titleKey) { this.background = helper.createBlankDrawable(WIDTH, HEIGHT); this.slot = helper.getSlotDrawable(); this.plus = plus; this.arrow = arrow; this.icon = helper.createDrawableItemStack(new ItemStack(EBlocks.STONE_BARREL.get())); - this.title = Component.translatable(TranslationKeys.BARREL_MIXING_CATEGORY_TITLE); - } - - @Override - public RecipeType getRecipeType() { - return ExDeorumJeiPlugin.BARREL_MIXING; + this.title = Component.translatable(titleKey); } @Override @@ -74,18 +73,47 @@ public class BarrelMixingCategory implements IRecipeCategory } @Override - public void setRecipe(IRecipeLayoutBuilder builder, BarrelMixingRecipe recipe, IFocusGroup focuses) { - builder.addSlot(RecipeIngredientRole.INPUT, 1, 1).addIngredients(recipe.getIngredient()); - builder.addSlot(RecipeIngredientRole.INPUT, 33, 1).addFluidStack(recipe.fluid, recipe.fluidAmount).setFluidRenderer(Math.max(1000, recipe.fluidAmount), false, 16, 16); - builder.addSlot(RecipeIngredientRole.OUTPUT, 79, 1).addItemStack(new ItemStack(recipe.result)); - } - - @Override - public void draw(BarrelMixingRecipe recipe, IRecipeSlotsView recipeSlotsView, GuiGraphics graphics, double mouseX, double mouseY) { + public void draw(T recipe, IRecipeSlotsView recipeSlotsView, GuiGraphics graphics, double mouseX, double mouseY) { slot.draw(graphics); plus.draw(graphics, 21, 5); slot.draw(graphics, 18 + 3 + 3 + 8, 0); arrow.draw(graphics, 53, 1); slot.draw(graphics, 78, 0); } + + public static class Items extends BarrelMixingCategory { + public Items(IGuiHelper helper, IDrawable plus, IDrawable arrow) { + super(helper, plus, arrow, TranslationKeys.BARREL_MIXING_CATEGORY_TITLE); + } + + @Override + public void setRecipe(IRecipeLayoutBuilder builder, BarrelMixingRecipe recipe, IFocusGroup focuses) { + builder.addSlot(RecipeIngredientRole.INPUT, 1, 1).addFluidStack(recipe.fluid, recipe.fluidAmount).setFluidRenderer(1000, false, 16, 16); + builder.addSlot(RecipeIngredientRole.INPUT, 33, 1).addIngredients(recipe.getIngredient()); + builder.addSlot(RecipeIngredientRole.OUTPUT, 79, 1).addItemStack(new ItemStack(recipe.result)); + } + + @Override + public RecipeType getRecipeType() { + return ExDeorumJeiPlugin.BARREL_MIXING; + } + } + + public static class Fluids extends BarrelMixingCategory { + public Fluids(IGuiHelper helper, IDrawable plus, IDrawable arrow) { + super(helper, plus, arrow, TranslationKeys.BARREL_FLUID_MIXING_CATEGORY_TITLE); + } + + @Override + public void setRecipe(IRecipeLayoutBuilder builder, BarrelFluidMixingRecipe recipe, IFocusGroup focuses) { + builder.addSlot(RecipeIngredientRole.INPUT, 1, 1).addFluidStack(recipe.baseFluid, recipe.baseFluidAmount).setFluidRenderer(1000, false, 16, 16); + builder.addSlot(RecipeIngredientRole.INPUT, 33, 1).addFluidStack(recipe.additiveFluid, 1000).setFluidRenderer(1000, false, 16, 16); + builder.addSlot(RecipeIngredientRole.OUTPUT, 79, 1).addItemStack(new ItemStack(recipe.result)); + } + + @Override + public RecipeType getRecipeType() { + return ExDeorumJeiPlugin.BARREL_FLUID_MIXING; + } + } } diff --git a/src/main/java/thedarkcolour/exdeorum/compat/jei/CrucibleHeatSourceRecipe.java b/src/main/java/thedarkcolour/exdeorum/compat/jei/CrucibleHeatSourceRecipe.java new file mode 100644 index 00000000..4c9f44df --- /dev/null +++ b/src/main/java/thedarkcolour/exdeorum/compat/jei/CrucibleHeatSourceRecipe.java @@ -0,0 +1,57 @@ +/* + * Ex Deorum + * Copyright (c) 2023 thedarkcolour + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package thedarkcolour.exdeorum.compat.jei; + +import mezz.jei.api.ingredients.IIngredientType; +import net.minecraft.world.level.block.state.BlockState; +import org.jetbrains.annotations.Nullable; + +final class CrucibleHeatSourceRecipe { + private final int meltRate; + private final BlockState blockState; + @Nullable + private final IIngredientType ingredientType; + @Nullable + private final Object ingredient; + + CrucibleHeatSourceRecipe(int meltRate, BlockState blockState, @Nullable IIngredientType ingredientType, @Nullable Object ingredient) { + this.meltRate = meltRate; + this.blockState = blockState; + this.ingredientType = ingredientType; + this.ingredient = ingredient; + } + + public int meltRate() { + return meltRate; + } + + public BlockState blockState() { + return blockState; + } + + @Nullable + public IIngredientType ingredientType() { + return ingredientType; + } + + @Nullable + public Object ingredient() { + return ingredient; + } +} diff --git a/src/main/java/thedarkcolour/exdeorum/compat/jei/CrucibleHeatSourcesCategory.java b/src/main/java/thedarkcolour/exdeorum/compat/jei/CrucibleHeatSourcesCategory.java index fb4272c6..9c087685 100644 --- a/src/main/java/thedarkcolour/exdeorum/compat/jei/CrucibleHeatSourcesCategory.java +++ b/src/main/java/thedarkcolour/exdeorum/compat/jei/CrucibleHeatSourcesCategory.java @@ -19,50 +19,60 @@ package thedarkcolour.exdeorum.compat.jei; import com.mojang.blaze3d.platform.InputConstants; -import it.unimi.dsi.fastutil.objects.Object2IntMap; import mezz.jei.api.constants.VanillaTypes; import mezz.jei.api.gui.builder.IRecipeLayoutBuilder; import mezz.jei.api.gui.drawable.IDrawable; import mezz.jei.api.gui.ingredient.IRecipeSlotsView; import mezz.jei.api.helpers.IGuiHelper; -import mezz.jei.api.ingredients.ITypedIngredient; -import mezz.jei.api.recipe.IFocus; +import mezz.jei.api.helpers.IJeiHelpers; +import mezz.jei.api.helpers.IModIdHelper; +import mezz.jei.api.ingredients.IIngredientType; import mezz.jei.api.recipe.IFocusFactory; import mezz.jei.api.recipe.IFocusGroup; import mezz.jei.api.recipe.RecipeIngredientRole; import mezz.jei.api.recipe.RecipeType; import mezz.jei.api.recipe.category.IRecipeCategory; +import mezz.jei.api.runtime.IIngredientManager; import mezz.jei.api.runtime.IRecipesGui; +import net.minecraft.ChatFormatting; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.network.chat.Component; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Items; import net.minecraft.world.item.TooltipFlag; -import net.minecraft.world.level.block.Block; +import net.minecraftforge.fml.ModContainer; +import net.minecraftforge.fml.ModList; +import net.minecraftforge.registries.ForgeRegistries; import thedarkcolour.exdeorum.data.TranslationKeys; import thedarkcolour.exdeorum.registry.EItems; import java.util.List; -class CrucibleHeatSourcesCategory implements IRecipeCategory> { +class CrucibleHeatSourcesCategory implements IRecipeCategory { public static final int WIDTH = 120; public static final int HEIGHT = 48; private final IDrawable background; private final IDrawable icon; private final Component title; - private final IFocusFactory focusFactory; - public CrucibleHeatSourcesCategory(IGuiHelper helper, IFocusFactory focusFactory) { + private final IFocusFactory focusFactory; + private final IIngredientManager ingredientManager; + private final IModIdHelper modIdHelper; + + public CrucibleHeatSourcesCategory(IJeiHelpers helpers) { + var helper = helpers.getGuiHelper(); this.background = helper.createBlankDrawable(WIDTH, HEIGHT); this.title = Component.translatable(TranslationKeys.CRUCIBLE_HEAT_SOURCE_CATEGORY_TITLE); this.icon = helper.createDrawableItemStack(new ItemStack(EItems.PORCELAIN_CRUCIBLE.get())); - this.focusFactory = focusFactory; + + this.focusFactory = helpers.getFocusFactory(); + this.ingredientManager = helpers.getIngredientManager(); + this.modIdHelper = helpers.getModIdHelper(); } @Override - public RecipeType> getRecipeType() { + public RecipeType getRecipeType() { return ExDeorumJeiPlugin.CRUCIBLE_HEAT_SOURCES; } @@ -82,43 +92,55 @@ class CrucibleHeatSourcesCategory implements IRecipeCategory recipe, IFocusGroup focuses) { - var itemForm = recipe.getKey().asItem(); - - if (itemForm != Items.AIR) { - builder.addInvisibleIngredients(RecipeIngredientRole.INPUT).addItemStack(new ItemStack(itemForm)); + public void setRecipe(IRecipeLayoutBuilder builder, CrucibleHeatSourceRecipe recipe, IFocusGroup focuses) { + if (recipe.ingredientType() != null) { + builder.addInvisibleIngredients(RecipeIngredientRole.INPUT).addIngredient(recipe.ingredientType(), recipe.ingredient()); + } else { + builder.addInvisibleIngredients(RecipeIngredientRole.INPUT).addIngredient(VanillaTypes.ITEM_STACK, ItemStack.EMPTY); } } @Override - public void draw(Object2IntMap.Entry recipe, IRecipeSlotsView recipeSlotsView, GuiGraphics graphics, double mouseX, double mouseY) { - var volume = recipe.getIntValue(); + public void draw(CrucibleHeatSourceRecipe recipe, IRecipeSlotsView recipeSlotsView, GuiGraphics graphics, double mouseX, double mouseY) { + var volume = recipe.meltRate(); var volumeLabel = Component.translatable(TranslationKeys.CRUCIBLE_HEAT_SOURCE_CATEGORY_MULTIPLIER, volume); var font = Minecraft.getInstance().font; graphics.drawString(font, volumeLabel, 60 - font.width(volumeLabel) / 2, 5, 0xff808080, false); - ClientJeiUtil.renderBlock(graphics, recipe.getKey().defaultBlockState(), 60, 24, 10, 20F); + ClientJeiUtil.renderBlock(graphics, recipe.blockState(), 60, 24, 10, 20F); } @Override - public List getTooltipStrings(Object2IntMap.Entry recipe, IRecipeSlotsView recipeSlotsView, double mouseX, double mouseY) { + public List getTooltipStrings(CrucibleHeatSourceRecipe recipe, IRecipeSlotsView recipeSlotsView, double mouseX, double mouseY) { if (44.0 < mouseX && mouseX < 76.0 && 16 < mouseY && mouseY < 48) { - return new ItemStack(recipe.getKey()).getTooltipLines(Minecraft.getInstance().player, Minecraft.getInstance().options.advancedItemTooltips ? TooltipFlag.ADVANCED : TooltipFlag.NORMAL); + if (recipe.ingredientType() != null) { + var tooltip = ingredientManager.getIngredientRenderer(recipe.ingredientType()).getTooltip(recipe.ingredient(), Minecraft.getInstance().options.advancedItemTooltips ? TooltipFlag.ADVANCED : TooltipFlag.NORMAL); + return modIdHelper.addModNameToIngredientTooltip(tooltip, recipe.ingredient(), ingredientManager.getIngredientHelper(recipe.ingredientType())); + } else { + + var block = recipe.blockState().getBlock(); + var modId = ForgeRegistries.BLOCKS.getKey(block).getNamespace(); + return List.of(Component.translatable(block.getDescriptionId()), Component.literal(modIdHelper.getFormattedModNameForModId(modId))); + } } + return List.of(); } @Override - public boolean handleInput(Object2IntMap.Entry recipe, double mouseX, double mouseY, InputConstants.Key input) { + public boolean handleInput(CrucibleHeatSourceRecipe recipe, double mouseX, double mouseY, InputConstants.Key input) { if (input.getType() == InputConstants.Type.MOUSE && (input.getValue() == InputConstants.MOUSE_BUTTON_LEFT || input.getValue() == InputConstants.MOUSE_BUTTON_RIGHT)) { if (44.0 < mouseX && mouseX < 76.0 && 16 < mouseY && mouseY < 48) { - var itemForm = recipe.getKey().asItem(); - - if (itemForm != Items.AIR && Minecraft.getInstance().screen instanceof IRecipesGui recipesGui) { - recipesGui.show(focusFactory.createFocus(input.getValue() == InputConstants.MOUSE_BUTTON_LEFT ? RecipeIngredientRole.INPUT : RecipeIngredientRole.OUTPUT, VanillaTypes.ITEM_STACK, new ItemStack(itemForm))); - return true; + if (recipe.ingredientType() != null) { + ingredientManager.createTypedIngredient(recipe.ingredientType(), recipe.ingredient()).ifPresent(ingredient -> { + if (Minecraft.getInstance().screen instanceof IRecipesGui recipesGui) { + recipesGui.show(focusFactory.createFocus(input.getValue() == InputConstants.MOUSE_BUTTON_LEFT ? RecipeIngredientRole.OUTPUT : RecipeIngredientRole.INPUT, ingredient)); + } + }); } + + return true; } } return false; diff --git a/src/main/java/thedarkcolour/exdeorum/compat/jei/ExDeorumJeiPlugin.java b/src/main/java/thedarkcolour/exdeorum/compat/jei/ExDeorumJeiPlugin.java index b174367e..3183dab9 100644 --- a/src/main/java/thedarkcolour/exdeorum/compat/jei/ExDeorumJeiPlugin.java +++ b/src/main/java/thedarkcolour/exdeorum/compat/jei/ExDeorumJeiPlugin.java @@ -19,7 +19,6 @@ package thedarkcolour.exdeorum.compat.jei; import com.google.common.collect.Lists; -import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import mezz.jei.api.IModPlugin; import mezz.jei.api.JeiPlugin; @@ -35,10 +34,11 @@ import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.Container; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; import net.minecraft.world.item.crafting.Recipe; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.WallBlock; +import net.minecraft.world.level.block.LiquidBlock; import net.minecraft.world.level.block.WallTorchBlock; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fml.ModList; @@ -49,6 +49,7 @@ import thedarkcolour.exdeorum.data.TranslationKeys; import thedarkcolour.exdeorum.item.WateringCanItem; import thedarkcolour.exdeorum.recipe.RecipeUtil; import thedarkcolour.exdeorum.recipe.barrel.BarrelCompostRecipe; +import thedarkcolour.exdeorum.recipe.barrel.BarrelFluidMixingRecipe; import thedarkcolour.exdeorum.recipe.barrel.BarrelMixingRecipe; import thedarkcolour.exdeorum.recipe.crucible.CrucibleRecipe; import thedarkcolour.exdeorum.recipe.hammer.HammerRecipe; @@ -69,11 +70,10 @@ public class ExDeorumJeiPlugin implements IModPlugin { static final RecipeType BARREL_COMPOST = RecipeType.create(ExDeorum.ID, "barrel_compost", BarrelCompostRecipe.class); static final RecipeType BARREL_MIXING = RecipeType.create(ExDeorum.ID, "barrel_mixing", BarrelMixingRecipe.class); + static final RecipeType BARREL_FLUID_MIXING = RecipeType.create(ExDeorum.ID, "barrel_fluid_mixing", BarrelFluidMixingRecipe.class); static final RecipeType LAVA_CRUCIBLE = RecipeType.create(ExDeorum.ID, "lava_crucible", CrucibleRecipe.class); static final RecipeType WATER_CRUCIBLE = RecipeType.create(ExDeorum.ID, "water_crucible", CrucibleRecipe.class); - // I love Java generics (todo finish implementing) - @SuppressWarnings("unchecked") - static final RecipeType> CRUCIBLE_HEAT_SOURCES = RecipeType.create(ExDeorum.ID, "crucible_heat_sources", (Class>) ((Object) Object2IntMap.Entry.class)); + static final RecipeType CRUCIBLE_HEAT_SOURCES = RecipeType.create(ExDeorum.ID, "crucible_heat_sources", CrucibleHeatSourceRecipe.class); static final RecipeType SIEVE = RecipeType.create(ExDeorum.ID, "sieve", JeiSieveRecipeGroup.class); static final RecipeType HAMMER = RecipeType.create(ExDeorum.ID, "hammer", HammerRecipe.class); @@ -89,10 +89,11 @@ public class ExDeorumJeiPlugin implements IModPlugin { var plus = helper.createDrawable(ExDeorumJeiPlugin.EX_DEORUM_JEI_TEXTURE, 22, 18, 8, 8); registration.addRecipeCategories(new BarrelCompostCategory(helper)); - registration.addRecipeCategories(new BarrelMixingCategory(helper, plus, arrow)); + registration.addRecipeCategories(new BarrelMixingCategory.Items(helper, plus, arrow)); + registration.addRecipeCategories(new BarrelMixingCategory.Fluids(helper, plus, arrow)); registration.addRecipeCategories(new CrucibleCategory.LavaCrucible(helper, arrow)); registration.addRecipeCategories(new CrucibleCategory.WaterCrucible(helper, arrow)); - registration.addRecipeCategories(new CrucibleHeatSourcesCategory(helper, registration.getJeiHelpers().getFocusFactory())); + registration.addRecipeCategories(new CrucibleHeatSourcesCategory(registration.getJeiHelpers())); registration.addRecipeCategories(new SieveCategory(helper)); registration.addRecipeCategories(new HammerCategory(helper, arrow)); } @@ -218,6 +219,7 @@ public class ExDeorumJeiPlugin implements IModPlugin { var stack = new ItemStack(barrel); registration.addRecipeCatalyst(stack, BARREL_COMPOST); registration.addRecipeCatalyst(stack, BARREL_MIXING); + registration.addRecipeCatalyst(stack, BARREL_FLUID_MIXING); } for (var lavaCrucible : lavaCrucibles) { var stack = new ItemStack(lavaCrucible); @@ -273,6 +275,7 @@ public class ExDeorumJeiPlugin implements IModPlugin { addRecipes(registration, BARREL_COMPOST, ERecipeTypes.BARREL_COMPOST); addRecipes(registration, BARREL_MIXING, ERecipeTypes.BARREL_MIXING); + addRecipes(registration, BARREL_FLUID_MIXING, ERecipeTypes.BARREL_FLUID_MIXING); addRecipes(registration, LAVA_CRUCIBLE, ERecipeTypes.LAVA_CRUCIBLE); addRecipes(registration, WATER_CRUCIBLE, ERecipeTypes.WATER_CRUCIBLE); addRecipes(registration, HAMMER, ERecipeTypes.HAMMER); @@ -301,7 +304,24 @@ public class ExDeorumJeiPlugin implements IModPlugin { }); } } - registration.addRecipes(CRUCIBLE_HEAT_SOURCES, List.copyOf(values.object2IntEntrySet())); + var fluidHelper = registration.getJeiHelpers().getPlatformFluidHelper(); + var fluidIngredientType = fluidHelper.getFluidIngredientType(); + var recipes = new ArrayList(); + + for (var entry : values.object2IntEntrySet()) { + if (entry.getKey() instanceof LiquidBlock liquid) { + recipes.add(new CrucibleHeatSourceRecipe(entry.getIntValue(), entry.getKey().defaultBlockState(), fluidIngredientType, fluidHelper.create(liquid.getFluid(), 1000))); + } else { + var itemForm = entry.getKey().asItem(); + + if (itemForm != Items.AIR) { + recipes.add(new CrucibleHeatSourceRecipe(entry.getIntValue(), entry.getKey().defaultBlockState(), VanillaTypes.ITEM_STACK, new ItemStack(itemForm))); + } else { + recipes.add(new CrucibleHeatSourceRecipe(entry.getIntValue(), entry.getKey().defaultBlockState(), null, null)); + } + } + } + registration.addRecipes(CRUCIBLE_HEAT_SOURCES, recipes); } @Override diff --git a/src/main/java/thedarkcolour/exdeorum/compat/jei/package-info.java b/src/main/java/thedarkcolour/exdeorum/compat/jei/package-info.java new file mode 100644 index 00000000..7565529c --- /dev/null +++ b/src/main/java/thedarkcolour/exdeorum/compat/jei/package-info.java @@ -0,0 +1,21 @@ +/* + * Ex Deorum + * Copyright (c) 2023 thedarkcolour + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +@net.minecraft.MethodsReturnNonnullByDefault +@javax.annotation.ParametersAreNonnullByDefault +package thedarkcolour.exdeorum.compat.jei; diff --git a/src/main/java/thedarkcolour/exdeorum/data/English.java b/src/main/java/thedarkcolour/exdeorum/data/English.java index d5ed57c5..81195058 100644 --- a/src/main/java/thedarkcolour/exdeorum/data/English.java +++ b/src/main/java/thedarkcolour/exdeorum/data/English.java @@ -53,6 +53,7 @@ class English { english.add(TranslationKeys.BARREL_COMPOST_CATEGORY_TITLE, "Barrel Compost"); english.add(TranslationKeys.BARREL_COMPOST_RECIPE_VOLUME, "Compost: %s"); english.add(TranslationKeys.BARREL_MIXING_CATEGORY_TITLE, "Barrel Mixing"); + english.add(TranslationKeys.BARREL_FLUID_MIXING_CATEGORY_TITLE, "Barrel Fluid Mixing"); english.add(TranslationKeys.WATER_CRUCIBLE_CATEGORY_TITLE, "Water Crucible"); english.add(TranslationKeys.LAVA_CRUCIBLE_CATEGORY_TITLE, "Lava Crucible"); english.add(TranslationKeys.CRUCIBLE_HEAT_SOURCE_CATEGORY_TITLE, "Crucible Heat Sources"); diff --git a/src/main/java/thedarkcolour/exdeorum/data/TranslationKeys.java b/src/main/java/thedarkcolour/exdeorum/data/TranslationKeys.java index 7191c6be..fc6ad624 100644 --- a/src/main/java/thedarkcolour/exdeorum/data/TranslationKeys.java +++ b/src/main/java/thedarkcolour/exdeorum/data/TranslationKeys.java @@ -52,6 +52,7 @@ public class TranslationKeys { public static final String BARREL_COMPOST_CATEGORY_TITLE = "gui." + ExDeorum.ID + ".category.barrel_compost"; public static final String BARREL_COMPOST_RECIPE_VOLUME = "gui." + ExDeorum.ID + ".category.barrel_compost.volume"; public static final String BARREL_MIXING_CATEGORY_TITLE = "gui." + ExDeorum.ID + ".category.barrel_mixing"; + public static final String BARREL_FLUID_MIXING_CATEGORY_TITLE = "gui." + ExDeorum.ID + ".category.barrel_fluid_mixing"; public static final String WATER_CRUCIBLE_CATEGORY_TITLE = "gui." + ExDeorum.ID + ".category.water_crucible"; public static final String LAVA_CRUCIBLE_CATEGORY_TITLE = "gui." + ExDeorum.ID + ".category.lava_crucible"; public static final String CRUCIBLE_HEAT_SOURCE_CATEGORY_TITLE = "gui." + ExDeorum.ID + ".category.crucible_heat_source"; diff --git a/src/main/java/thedarkcolour/exdeorum/data/recipe/Recipes.java b/src/main/java/thedarkcolour/exdeorum/data/recipe/Recipes.java index 9467f709..1a8bfb5a 100644 --- a/src/main/java/thedarkcolour/exdeorum/data/recipe/Recipes.java +++ b/src/main/java/thedarkcolour/exdeorum/data/recipe/Recipes.java @@ -46,6 +46,7 @@ import thedarkcolour.exdeorum.compat.ModIds; import thedarkcolour.exdeorum.data.ModCompatData; import thedarkcolour.exdeorum.recipe.TagResultRecipe; import thedarkcolour.exdeorum.recipe.barrel.FinishedBarrelCompostRecipe; +import thedarkcolour.exdeorum.recipe.barrel.FinishedBarrelFluidMixingRecipe; import thedarkcolour.exdeorum.recipe.barrel.FinishedBarrelMixingRecipe; import thedarkcolour.exdeorum.recipe.crucible.FinishedCrucibleRecipe; import thedarkcolour.exdeorum.recipe.hammer.FinishedHammerRecipe; @@ -523,14 +524,12 @@ public class Recipes { barrelMixing(writer, ingredient(Items.MILK_BUCKET), Fluids.WATER, Items.SLIME_BLOCK); barrelMixing(writer, "_from_porcelain_bucket", ingredient(EItems.PORCELAIN_MILK_BUCKET.get()), Fluids.WATER, Items.SLIME_BLOCK); barrelMixing(writer, ingredient(Items.SNOWBALL), Fluids.WATER, Items.ICE); - barrelMixing(writer, ingredient(Items.LAVA_BUCKET), Fluids.WATER, Items.STONE); - barrelMixing(writer, "_from_porcelain_bucket", ingredient(EItems.PORCELAIN_LAVA_BUCKET), Fluids.WATER, Items.STONE); + barrelFluidMixing(writer, Fluids.WATER, Fluids.LAVA, Items.STONE); // lava - barrelMixing(writer, ingredient(EItems.WITCH_WATER_BUCKET), Fluids.LAVA, Items.NETHERRACK); - barrelMixing(writer, "_from_porcelain_bucket", ingredient(EItems.PORCELAIN_WITCH_WATER_BUCKET), Fluids.LAVA, Items.NETHERRACK); + barrelFluidMixing(writer, EFluids.WITCH_WATER.get(), Fluids.LAVA, Items.NETHERRACK); + barrelFluidMixing(writer, Fluids.LAVA, EFluids.WITCH_WATER.get(), Items.BLACKSTONE); barrelMixing(writer, ingredient(Items.GLOWSTONE_DUST), Fluids.LAVA, Items.END_STONE); - barrelMixing(writer, ingredient(Items.WATER_BUCKET), Fluids.LAVA, Items.OBSIDIAN); - barrelMixing(writer, "_from_porcelain_bucket", ingredient(EItems.PORCELAIN_WATER_BUCKET), Fluids.LAVA, Items.OBSIDIAN); + barrelFluidMixing(writer, Fluids.LAVA, Fluids.WATER, Items.OBSIDIAN); barrelMixing(writer, ingredient(Items.SLIME_BALL), Fluids.LAVA, Items.MAGMA_CREAM); barrelMixing(writer, ingredient(Items.SOUL_SAND), Fluids.LAVA, Items.SOUL_SOIL); // witch water @@ -545,6 +544,10 @@ public class Recipes { writer.accept(new FinishedBarrelMixingRecipe(new ResourceLocation(ExDeorum.ID, "barrel_mixing/" + path(result) + suffix), ingredient, fluidType, 1000, result)); } + private static void barrelFluidMixing(Consumer writer, Fluid base, Fluid additive, Item result) { + writer.accept(new FinishedBarrelFluidMixingRecipe(new ResourceLocation(ExDeorum.ID, "barrel_fluid_mixing/" + path(result)), base, 1000, additive, result)); + } + static ICondition tagNotEmpty(TagKey tag) { return new NotCondition(new TagEmptyCondition(tag.location())); } diff --git a/src/main/java/thedarkcolour/exdeorum/event/EventHandler.java b/src/main/java/thedarkcolour/exdeorum/event/EventHandler.java index 9b52058e..bd802f83 100644 --- a/src/main/java/thedarkcolour/exdeorum/event/EventHandler.java +++ b/src/main/java/thedarkcolour/exdeorum/event/EventHandler.java @@ -18,7 +18,9 @@ package thedarkcolour.exdeorum.event; +import com.google.common.collect.ImmutableList; import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.registries.Registries; @@ -29,9 +31,11 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.util.Unit; +import net.minecraft.world.SimpleContainer; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; +import net.minecraft.world.item.crafting.RecipeType; import net.minecraft.world.level.GameRules; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.levelgen.Heightmap; @@ -46,7 +50,6 @@ import net.minecraftforge.event.OnDatapackSyncEvent; import net.minecraftforge.event.entity.player.PlayerEvent; import net.minecraftforge.event.level.LevelEvent; import net.minecraftforge.event.server.ServerStoppingEvent; -import net.minecraftforge.eventbus.api.Event; import net.minecraftforge.fluids.FluidInteractionRegistry; import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.fml.InterModComms; @@ -55,20 +58,20 @@ import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; import net.minecraftforge.fml.event.lifecycle.InterModEnqueueEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; import net.minecraftforge.fml.loading.FMLEnvironment; -import org.jetbrains.annotations.Nullable; import thedarkcolour.exdeorum.ExDeorum; import thedarkcolour.exdeorum.blockentity.LavaCrucibleBlockEntity; import thedarkcolour.exdeorum.client.CompostColors; import thedarkcolour.exdeorum.compat.ModIds; import thedarkcolour.exdeorum.compat.top.ExDeorumTopCompat; import thedarkcolour.exdeorum.config.EConfig; -import thedarkcolour.exdeorum.item.HammerItem; import thedarkcolour.exdeorum.item.WateringCanItem; -import thedarkcolour.exdeorum.network.ClientMessageHandler; import thedarkcolour.exdeorum.network.NetworkHandler; import thedarkcolour.exdeorum.recipe.RecipeUtil; +import thedarkcolour.exdeorum.recipe.barrel.BarrelCompostRecipe; +import thedarkcolour.exdeorum.recipe.sieve.SieveRecipe; import thedarkcolour.exdeorum.registry.EFluids; import thedarkcolour.exdeorum.registry.EItems; +import thedarkcolour.exdeorum.registry.ERecipeTypes; import thedarkcolour.exdeorum.tag.EBiomeTags; import thedarkcolour.exdeorum.voidworld.VoidChunkGenerator; diff --git a/src/main/java/thedarkcolour/exdeorum/item/HammerItem.java b/src/main/java/thedarkcolour/exdeorum/item/HammerItem.java index 21055a26..0d677521 100644 --- a/src/main/java/thedarkcolour/exdeorum/item/HammerItem.java +++ b/src/main/java/thedarkcolour/exdeorum/item/HammerItem.java @@ -24,7 +24,6 @@ import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.DiggerItem; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Tier; -import net.minecraft.world.item.crafting.RecipeManager; import net.minecraft.world.item.crafting.RecipeType; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; @@ -57,7 +56,7 @@ public class HammerItem extends DiggerItem { return validBlocks; } - public static void refreshValidBlocks(RecipeManager recipes) { + public static void refreshValidBlocks() { validBlocks = Lazy.of(HammerItem::computeValidBlocks); } diff --git a/src/main/java/thedarkcolour/exdeorum/recipe/BarrelFluidMixingRecipeCache.java b/src/main/java/thedarkcolour/exdeorum/recipe/BarrelFluidMixingRecipeCache.java new file mode 100644 index 00000000..737a8683 --- /dev/null +++ b/src/main/java/thedarkcolour/exdeorum/recipe/BarrelFluidMixingRecipeCache.java @@ -0,0 +1,60 @@ +/* + * Ex Deorum + * Copyright (c) 2023 thedarkcolour + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package thedarkcolour.exdeorum.recipe; + +import net.minecraft.world.item.crafting.RecipeManager; +import net.minecraft.world.level.material.Fluid; +import org.jetbrains.annotations.Nullable; +import thedarkcolour.exdeorum.recipe.barrel.BarrelFluidMixingRecipe; +import thedarkcolour.exdeorum.registry.ERecipeTypes; + +import java.util.IdentityHashMap; + +// for now, only simple recipes +public class BarrelFluidMixingRecipeCache { + private RecipeManager recipeManager; + @Nullable + private IdentityHashMap> recipes; + + public BarrelFluidMixingRecipeCache(RecipeManager recipeManager) { + this.recipeManager = recipeManager; + } + + @Nullable + public BarrelFluidMixingRecipe getRecipe(Fluid baseFluid, Fluid additive) { + if (recipes == null) { + buildRecipes(); + } + var recipesForBase = recipes.get(baseFluid); + if (recipesForBase != null) { + return recipesForBase.get(additive); + } + return null; + } + + private void buildRecipes() { + this.recipes = new IdentityHashMap<>(); + + for (var recipe : this.recipeManager.byType(ERecipeTypes.BARREL_FLUID_MIXING.get()).values()) { + recipes.computeIfAbsent(recipe.baseFluid, key -> new IdentityHashMap<>()).put(recipe.additiveFluid, recipe); + } + + this.recipeManager = null; + } +} diff --git a/src/main/java/thedarkcolour/exdeorum/recipe/RecipeUtil.java b/src/main/java/thedarkcolour/exdeorum/recipe/RecipeUtil.java index dfa4abfd..4e1edd4b 100644 --- a/src/main/java/thedarkcolour/exdeorum/recipe/RecipeUtil.java +++ b/src/main/java/thedarkcolour/exdeorum/recipe/RecipeUtil.java @@ -18,14 +18,12 @@ package thedarkcolour.exdeorum.recipe; -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; import com.google.gson.JsonObject; +import com.google.gson.JsonSyntaxException; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.resources.ResourceLocation; import net.minecraft.tags.TagKey; import net.minecraft.util.GsonHelper; import net.minecraft.world.Container; @@ -36,28 +34,28 @@ import net.minecraft.world.item.crafting.Ingredient; 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.material.Fluid; +import net.minecraft.world.level.material.Fluids; import net.minecraft.world.level.storage.loot.LootDataType; -import net.minecraft.world.level.storage.loot.providers.number.BinomialDistributionGenerator; -import net.minecraft.world.level.storage.loot.providers.number.ConstantValue; -import net.minecraft.world.level.storage.loot.providers.number.NumberProvider; -import net.minecraft.world.level.storage.loot.providers.number.NumberProviders; -import net.minecraft.world.level.storage.loot.providers.number.UniformGenerator; +import net.minecraft.world.level.storage.loot.providers.number.*; import net.minecraftforge.common.crafting.CraftingHelper; -import net.minecraftforge.common.util.Lazy; import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.registries.ForgeRegistries; import org.jetbrains.annotations.Nullable; import thedarkcolour.exdeorum.compat.PreferredOres; import thedarkcolour.exdeorum.item.HammerItem; import thedarkcolour.exdeorum.recipe.barrel.BarrelCompostRecipe; +import thedarkcolour.exdeorum.recipe.barrel.BarrelFluidMixingRecipe; import thedarkcolour.exdeorum.recipe.barrel.BarrelMixingRecipe; import thedarkcolour.exdeorum.recipe.crucible.CrucibleRecipe; import thedarkcolour.exdeorum.recipe.hammer.HammerRecipe; import thedarkcolour.exdeorum.recipe.sieve.SieveRecipe; import thedarkcolour.exdeorum.registry.ERecipeTypes; -import java.time.Duration; -import java.util.*; -import java.util.function.Supplier; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Objects; public final class RecipeUtil { private static final int CONSTANT_TYPE = 1; @@ -65,91 +63,58 @@ public final class RecipeUtil { private static final int BINOMIAL_TYPE = 3; private static final int UNKNOWN_TYPE = 99; - private static final Cache> SIEVE_RECIPE_CACHE = CacheBuilder.newBuilder().expireAfterAccess(Duration.ofMinutes(3)).build(); - private static Lazy> barrelCompostRecipeCache; - private static Lazy> lavaCrucibleRecipeCache; - private static Lazy> waterCrucibleRecipeCache; - private static Lazy> hammerRecipeCache; + private static SingleIngredientRecipeCache barrelCompostRecipeCache; + private static SingleIngredientRecipeCache lavaCrucibleRecipeCache; + private static SingleIngredientRecipeCache waterCrucibleRecipeCache; + private static SingleIngredientRecipeCache hammerRecipeCache; + private static SieveRecipeCache sieveRecipeCache; + private static BarrelFluidMixingRecipeCache barrelFluidMixingRecipeCache; public static void reload(RecipeManager recipes) { - SIEVE_RECIPE_CACHE.invalidateAll(); - - barrelCompostRecipeCache = loadSimpleRecipeCache(recipes, ERecipeTypes.BARREL_COMPOST); - lavaCrucibleRecipeCache = loadSimpleRecipeCache(recipes, ERecipeTypes.LAVA_CRUCIBLE); - waterCrucibleRecipeCache = loadSimpleRecipeCache(recipes, ERecipeTypes.WATER_CRUCIBLE); - hammerRecipeCache = loadSimpleRecipeCache(recipes, ERecipeTypes.HAMMER); - HammerItem.refreshValidBlocks(recipes); + barrelCompostRecipeCache = new SingleIngredientRecipeCache<>(recipes, ERecipeTypes.BARREL_COMPOST); + lavaCrucibleRecipeCache = new SingleIngredientRecipeCache<>(recipes, ERecipeTypes.LAVA_CRUCIBLE); + waterCrucibleRecipeCache = new SingleIngredientRecipeCache<>(recipes, ERecipeTypes.WATER_CRUCIBLE); + hammerRecipeCache = new SingleIngredientRecipeCache<>(recipes, ERecipeTypes.HAMMER).trackAllRecipes(); + sieveRecipeCache = new SieveRecipeCache(recipes); + barrelFluidMixingRecipeCache = new BarrelFluidMixingRecipeCache(recipes); + HammerItem.refreshValidBlocks(); } public static void unload() { - SIEVE_RECIPE_CACHE.invalidateAll(); barrelCompostRecipeCache = null; lavaCrucibleRecipeCache = null; waterCrucibleRecipeCache = null; hammerRecipeCache = null; + sieveRecipeCache = null; + barrelFluidMixingRecipeCache = null; } - private static Lazy> loadSimpleRecipeCache(RecipeManager recipes, Supplier> recipeType) { - return Lazy.of(() -> { - var builder = new ImmutableMap.Builder(); - for (var recipe : recipes.byType(recipeType.get()).values()) { - for (var item : recipe.getIngredient().getItems()) { - builder.put(item.getItem(), recipe); - } - } - - return builder.buildKeepingLast(); - }); - } - - public static List getSieveRecipes(RecipeManager manager, Item mesh, ItemStack item) { - var cacheKey = new SieveCacheKey(mesh, item.getItem()); - var cacheVal = SIEVE_RECIPE_CACHE.getIfPresent(cacheKey); - if (cacheVal != null) return cacheVal; - - var builder = new ImmutableList.Builder(); - var cache = true; - - for (var recipe : byType(manager, ERecipeTypes.SIEVE.get())) { - if (recipe.test(mesh, item)) { - builder.add(recipe); - - if (recipe.dependsOnNbt) { - cache = false; - } - } - } - - var recipes = builder.build(); - if (cache) { - SIEVE_RECIPE_CACHE.put(cacheKey, recipes); - } - - return recipes; + public static List getSieveRecipes(Item mesh, ItemStack item) { + return sieveRecipeCache.getRecipe(mesh, item); } @Nullable public static CrucibleRecipe getLavaCrucibleRecipe(ItemStack item) { - return lavaCrucibleRecipeCache.get().get(item.getItem()); + return lavaCrucibleRecipeCache.getRecipe(item); } @Nullable public static CrucibleRecipe getWaterCrucibleRecipe(ItemStack item) { - return waterCrucibleRecipeCache.get().get(item.getItem()); + return waterCrucibleRecipeCache.getRecipe(item); } @Nullable - public static BarrelCompostRecipe getBarrelCompostRecipe(Item playerItem) { - return barrelCompostRecipeCache.get().get(playerItem); + public static BarrelCompostRecipe getBarrelCompostRecipe(ItemStack item) { + return barrelCompostRecipeCache.getRecipe(item); } @Nullable - public static HammerRecipe getHammerRecipe(Item playerItem) { - return hammerRecipeCache.get().get(playerItem); + public static HammerRecipe getHammerRecipe(Item item) { + return hammerRecipeCache.getRecipe(item); } public static Collection getCachedHammerRecipes() { - return hammerRecipeCache.get().values(); + return hammerRecipeCache.getAllRecipes(); } public static > Collection byType(RecipeManager manager, RecipeType type) { @@ -168,6 +133,19 @@ public final class RecipeUtil { return CraftingHelper.getItem(GsonHelper.getAsString(json, key), true); } + public static Fluid readFluid(JsonObject json, String key) { + String fluidName = GsonHelper.getAsString(json, key); + ResourceLocation fluidKey = new ResourceLocation(fluidName); + if (!ForgeRegistries.FLUIDS.containsKey(fluidKey)) { + throw new JsonSyntaxException("Unknown fluid '" + fluidName + "'"); + } + Fluid fluid = ForgeRegistries.FLUIDS.getValue(fluidKey); + if (fluid == Fluids.EMPTY) { + throw new JsonSyntaxException("Invalid Fluid: " + fluidName); + } + return Objects.requireNonNull(fluid); + } + public static NumberProvider readNumberProvider(JsonObject json, String key) { var obj = json.get(key); return LootDataType.PREDICATE.parser().fromJson(obj, NumberProvider.class); @@ -292,7 +270,7 @@ public final class RecipeUtil { } public static boolean isCompostable(ItemStack stack) { - return barrelCompostRecipeCache != null && barrelCompostRecipeCache.get().containsKey(stack.getItem()); + return barrelCompostRecipeCache != null && barrelCompostRecipeCache.getRecipe(stack) != null; } public static @Nullable BarrelMixingRecipe getBarrelMixingRecipe(RecipeManager recipes, ItemStack stack, FluidStack fluid) { @@ -322,6 +300,13 @@ public final class RecipeUtil { return BuiltInRegistries.ITEM.getTag(tag).map(set -> !set.iterator().hasNext()).orElse(PreferredOres.getPreferredOre(tag) == Items.AIR); } - private record SieveCacheKey(Item mesh, Item ingredient) { + @Nullable + public static BarrelFluidMixingRecipe getFluidMixingRecipe(FluidStack base, Fluid additive) { + var recipe = barrelFluidMixingRecipeCache.getRecipe(base.getFluid(), additive); + if (recipe != null && base.getAmount() >= recipe.baseFluidAmount) { + return recipe; + } else { + return null; + } } } diff --git a/src/main/java/thedarkcolour/exdeorum/recipe/SieveRecipeCache.java b/src/main/java/thedarkcolour/exdeorum/recipe/SieveRecipeCache.java new file mode 100644 index 00000000..3990a4ad --- /dev/null +++ b/src/main/java/thedarkcolour/exdeorum/recipe/SieveRecipeCache.java @@ -0,0 +1,92 @@ +/* + * Ex Deorum + * Copyright (c) 2023 thedarkcolour + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package thedarkcolour.exdeorum.recipe; + +import com.google.common.collect.ImmutableList; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.RecipeManager; +import org.jetbrains.annotations.Nullable; +import thedarkcolour.exdeorum.recipe.sieve.SieveRecipe; +import thedarkcolour.exdeorum.registry.ERecipeTypes; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.IdentityHashMap; +import java.util.List; + +public class SieveRecipeCache { + private RecipeManager recipeManager; + @Nullable + private IdentityHashMap meshCaches; + + public SieveRecipeCache(RecipeManager recipeManager) { + this.recipeManager = recipeManager; + } + + public List getRecipe(Item mesh, ItemStack input) { + if (meshCaches == null) { + buildRecipes(); + } + var meshCache = meshCaches.get(mesh); + return meshCache == null ? List.of() : meshCache.getRecipes(input); + } + + private void buildRecipes() { + // Group recipes based on their mesh + var tempMap = new HashMap>(); + for (var recipe : recipeManager.byType(ERecipeTypes.SIEVE.get()).values()) { + tempMap.computeIfAbsent(recipe.mesh, k -> new ArrayList<>()).add(recipe); + } + this.meshCaches = new IdentityHashMap<>(); + for (var mesh : tempMap.entrySet()) { + this.meshCaches.put(mesh.getKey(), new MeshRecipeCache(mesh.getValue())); + } + this.recipeManager = null; + } + + // For now, there will be no complex recipes. What that means is, recipes may not use NBT information of the + // block being sifted to decide what its drops are. Firstly, this would be complicated for me to code. Secondly, + // conveying this information in JEI would be difficult (ex. Bottle drops from Sand, but only if the Sand has a + // certain NBT tag). Thirdly, I do not see anybody needing this use case, and if they do, they should contact + // me on GitHub or Discord so that I can get around to actually implementing it. + private static class MeshRecipeCache { + private final IdentityHashMap> simpleRecipes; + + private MeshRecipeCache(List recipes) { + this.simpleRecipes = new IdentityHashMap<>(); + var temp = new IdentityHashMap>(); + + for (var recipe : recipes) { + for (var item : recipe.ingredient.getItems()) { + temp.computeIfAbsent(item.getItem(), k -> ImmutableList.builder()).add(recipe); + } + } + + for (var entry : temp.entrySet()) { + this.simpleRecipes.put(entry.getKey(), entry.getValue().build()); + } + } + + public List getRecipes(ItemStack input) { + var result = simpleRecipes.get(input.getItem()); + return result == null ? List.of() : result; + } + } +} diff --git a/src/main/java/thedarkcolour/exdeorum/recipe/SingleIngredientRecipe.java b/src/main/java/thedarkcolour/exdeorum/recipe/SingleIngredientRecipe.java index cedbf5c4..03ffd526 100644 --- a/src/main/java/thedarkcolour/exdeorum/recipe/SingleIngredientRecipe.java +++ b/src/main/java/thedarkcolour/exdeorum/recipe/SingleIngredientRecipe.java @@ -60,7 +60,7 @@ public abstract class SingleIngredientRecipe implements Recipe { @Override public boolean canCraftInDimensions(int width, int height) { - return true; + return false; } @Override diff --git a/src/main/java/thedarkcolour/exdeorum/recipe/SingleIngredientRecipeCache.java b/src/main/java/thedarkcolour/exdeorum/recipe/SingleIngredientRecipeCache.java new file mode 100644 index 00000000..1b540b46 --- /dev/null +++ b/src/main/java/thedarkcolour/exdeorum/recipe/SingleIngredientRecipeCache.java @@ -0,0 +1,129 @@ +/* + * Ex Deorum + * Copyright (c) 2023 thedarkcolour + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package thedarkcolour.exdeorum.recipe; + +import com.google.common.collect.ImmutableList; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.RecipeManager; +import net.minecraft.world.item.crafting.RecipeType; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.IdentityHashMap; +import java.util.List; +import java.util.function.Supplier; + +public class SingleIngredientRecipeCache { + private final Supplier> recipeType; + private RecipeManager recipeManager; + @Nullable + private IdentityHashMap simpleRecipes; + @Nullable + private List complexRecipes; + @Nullable + private Collection allRecipes; + private boolean trackAllRecipes; + + public SingleIngredientRecipeCache(RecipeManager recipeManager, Supplier> recipeType) { + this.recipeType = recipeType; + this.recipeManager = recipeManager; + } + + public SingleIngredientRecipeCache trackAllRecipes() { + this.trackAllRecipes = true; + return this; + } + + @Nullable + public T getRecipe(Item item) { + return getRecipe(new ItemStack(item)); + } + + @Nullable + public T getRecipe(ItemStack item) { + if (simpleRecipes == null) { + buildRecipes(); + } + // simpleRecipes is guaranteed not null + var recipe = simpleRecipes.get(item.getItem()); + + // if there are complex recipes, test each one + if (recipe == null && complexRecipes != null) { + for (var complexRecipe : complexRecipes) { + if (complexRecipe.getIngredient().test(item)) { + return complexRecipe; + } + } + + // if neither list contains a recipe for this item, return null + return null; + } else { + return recipe; + } + } + + public Collection getAllRecipes() { + if (this.simpleRecipes == null) { + buildRecipes(); + } + //noinspection DataFlowIssue + return this.allRecipes; + } + + /** + * Called when this recipe cache is first queried. First, scans available recipes for recipes with "simple" + * ingredients that do not check an item's NBT. All of these recipes are added to the {@link #simpleRecipes} + * map, which is indexed by the item(s) the recipe's ingredient accepts. Recipes whose ingredients are "complex" + * and consider an item's NBT are added to the separate {@link #complexRecipes} list. Unlike simpleRecipes, + * complexRecipes may be null after this method call if no complex recipes are found. The {@link #allRecipes} + * field contains all recipes, simple and complex, in one collection. If this recipe cache is not set to track + * all recipes by {@link #trackAllRecipes}, then this list is discarded afterward. Finally, after all recipes + * have been scanned, the {@link #recipeManager} is set to null, since it is no longer needed. + */ + private void buildRecipes() { + this.simpleRecipes = new IdentityHashMap<>(); + var complexRecipes = ImmutableList.builder(); + + var allRecipes = this.recipeManager.byType(recipeType.get()).values(); + + for (var recipe : allRecipes) { + var ingredient = recipe.getIngredient(); + + if (ingredient.isSimple()) { + for (var item : ingredient.getItems()) { + simpleRecipes.put(item.getItem(), recipe); + } + } else { + complexRecipes.add(recipe); + } + } + + this.complexRecipes = complexRecipes.build(); + if (this.complexRecipes.isEmpty()) { + this.complexRecipes = null; + } + // Track list of simple and complex recipes (only used by hammer so far) + if (this.trackAllRecipes) { + this.allRecipes = allRecipes; + } + + this.recipeManager = null; + } +} diff --git a/src/main/java/thedarkcolour/exdeorum/recipe/barrel/BarrelFluidMixingRecipe.java b/src/main/java/thedarkcolour/exdeorum/recipe/barrel/BarrelFluidMixingRecipe.java new file mode 100644 index 00000000..e9ef260c --- /dev/null +++ b/src/main/java/thedarkcolour/exdeorum/recipe/barrel/BarrelFluidMixingRecipe.java @@ -0,0 +1,124 @@ +/* + * Ex Deorum + * Copyright (c) 2023 thedarkcolour + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package thedarkcolour.exdeorum.recipe.barrel; + +import com.google.gson.JsonObject; +import net.minecraft.core.RegistryAccess; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.GsonHelper; +import net.minecraft.world.Container; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +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.Level; +import net.minecraft.world.level.material.Fluid; +import net.minecraftforge.registries.ForgeRegistries; +import org.jetbrains.annotations.Nullable; +import thedarkcolour.exdeorum.recipe.RecipeUtil; +import thedarkcolour.exdeorum.registry.ERecipeSerializers; +import thedarkcolour.exdeorum.registry.ERecipeTypes; + +// A recipe where two fluids are mixed together, rather than a fluid and an item. +// The additive must be 1000mB or a source block worth of liquid. +// The additive is not consumed, however. Additives placed in the world are not consumed, +// so it would be unfair to consume the handheld additive. +public class BarrelFluidMixingRecipe implements Recipe { + private final ResourceLocation id; + + public final Fluid baseFluid; + public final int baseFluidAmount; + public final Fluid additiveFluid; + public final Item result; + + public BarrelFluidMixingRecipe(ResourceLocation id, Fluid baseFluid, int baseFluidAmount, Fluid additiveFluid, Item result) { + this.id = id; + this.baseFluid = baseFluid; + this.baseFluidAmount = baseFluidAmount; + this.additiveFluid = additiveFluid; + this.result = result; + } + + @Override + public boolean matches(Container pContainer, Level pLevel) { + return false; + } + + @Override + public ItemStack assemble(Container pContainer, RegistryAccess pRegistryAccess) { + return ItemStack.EMPTY; + } + + @Override + public boolean canCraftInDimensions(int pWidth, int pHeight) { + return false; + } + + @Override + public ItemStack getResultItem(RegistryAccess pRegistryAccess) { + return ItemStack.EMPTY; + } + + @Override + public ResourceLocation getId() { + return this.id; + } + + @Override + public RecipeSerializer getSerializer() { + return ERecipeSerializers.BARREL_FLUID_MIXING.get(); + } + + @Override + public RecipeType getType() { + return ERecipeTypes.BARREL_FLUID_MIXING.get(); + } + + public static class Serializer implements RecipeSerializer { + @Override + public BarrelFluidMixingRecipe fromJson(ResourceLocation id, JsonObject json) { + Fluid baseFluid = RecipeUtil.readFluid(json, "base_fluid"); + int baseFluidAmount = GsonHelper.getAsInt(json, "base_fluid_amount"); + Fluid additiveFluid = RecipeUtil.readFluid(json, "additive_fluid"); + Item result = RecipeUtil.readItem(json, "result"); + + return new BarrelFluidMixingRecipe(id, baseFluid, baseFluidAmount, additiveFluid, result); + } + + @Override + public void toNetwork(FriendlyByteBuf buffer, BarrelFluidMixingRecipe recipe) { + buffer.writeRegistryId(ForgeRegistries.FLUIDS, recipe.baseFluid); + buffer.writeVarInt(recipe.baseFluidAmount); + buffer.writeRegistryId(ForgeRegistries.FLUIDS, recipe.additiveFluid); + buffer.writeRegistryId(ForgeRegistries.ITEMS, recipe.result); + } + + @Override + public @Nullable BarrelFluidMixingRecipe fromNetwork(ResourceLocation id, FriendlyByteBuf buffer) { + Fluid baseFluid = buffer.readRegistryId(); + int baseFluidAmount = buffer.readVarInt(); + Fluid additiveFluid = buffer.readRegistryId(); + Item result = buffer.readRegistryId(); + + return new BarrelFluidMixingRecipe(id, baseFluid, baseFluidAmount, additiveFluid, result); + } + } +} diff --git a/src/main/java/thedarkcolour/exdeorum/recipe/barrel/BarrelMixingRecipe.java b/src/main/java/thedarkcolour/exdeorum/recipe/barrel/BarrelMixingRecipe.java index c2dd07de..0801ec26 100644 --- a/src/main/java/thedarkcolour/exdeorum/recipe/barrel/BarrelMixingRecipe.java +++ b/src/main/java/thedarkcolour/exdeorum/recipe/barrel/BarrelMixingRecipe.java @@ -75,9 +75,9 @@ public class BarrelMixingRecipe extends SingleIngredientRecipe { @Override public BarrelMixingRecipe fromJson(ResourceLocation id, JsonObject json) { Ingredient ingredient = RecipeUtil.readIngredient(json, "ingredient"); - Fluid fluid = ForgeRegistries.FLUIDS.getValue(new ResourceLocation(GsonHelper.getAsString(json, "fluid"))); + Fluid fluid = RecipeUtil.readFluid(json, "fluid");; int fluidAmount = GsonHelper.getAsInt(json, "fluid_amount"); - Item result = ForgeRegistries.ITEMS.getValue(new ResourceLocation(GsonHelper.getAsString(json, "result"))); + Item result = RecipeUtil.readItem(json, "result"); return new BarrelMixingRecipe(id, ingredient, fluid, fluidAmount, result); } diff --git a/src/main/java/thedarkcolour/exdeorum/recipe/barrel/FinishedBarrelFluidMixingRecipe.java b/src/main/java/thedarkcolour/exdeorum/recipe/barrel/FinishedBarrelFluidMixingRecipe.java new file mode 100644 index 00000000..f2ab2a30 --- /dev/null +++ b/src/main/java/thedarkcolour/exdeorum/recipe/barrel/FinishedBarrelFluidMixingRecipe.java @@ -0,0 +1,62 @@ +/* + * Ex Deorum + * Copyright (c) 2023 thedarkcolour + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package thedarkcolour.exdeorum.recipe.barrel; + +import com.google.gson.JsonObject; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.crafting.RecipeSerializer; +import net.minecraft.world.level.material.Fluid; +import net.minecraftforge.registries.ForgeRegistries; +import thedarkcolour.exdeorum.recipe.EFinishedRecipe; +import thedarkcolour.exdeorum.registry.ERecipeSerializers; + +public class FinishedBarrelFluidMixingRecipe implements EFinishedRecipe { + private final ResourceLocation id; + private final Fluid baseFluid; + private final int baseFluidAmount; + private final Fluid additiveFluid; + private final Item result; + + public FinishedBarrelFluidMixingRecipe(ResourceLocation id, Fluid baseFluid, int baseFluidAmount, Fluid additiveFluid, Item result) { + this.id = id; + this.baseFluid = baseFluid; + this.baseFluidAmount = baseFluidAmount; + this.additiveFluid = additiveFluid; + this.result = result; + } + + @Override + public void serializeRecipeData(JsonObject json) { + json.addProperty("base_fluid", ForgeRegistries.FLUIDS.getKey(this.baseFluid).toString()); + json.addProperty("base_fluid_amount", this.baseFluidAmount); + json.addProperty("additive_fluid", ForgeRegistries.FLUIDS.getKey(this.additiveFluid).toString()); + json.addProperty("result", ForgeRegistries.ITEMS.getKey(this.result).toString()); + } + + @Override + public ResourceLocation getId() { + return this.id; + } + + @Override + public RecipeSerializer getType() { + return ERecipeSerializers.BARREL_FLUID_MIXING.get(); + } +} diff --git a/src/main/java/thedarkcolour/exdeorum/registry/ERecipeSerializers.java b/src/main/java/thedarkcolour/exdeorum/registry/ERecipeSerializers.java index 511a1156..74e4514c 100644 --- a/src/main/java/thedarkcolour/exdeorum/registry/ERecipeSerializers.java +++ b/src/main/java/thedarkcolour/exdeorum/registry/ERecipeSerializers.java @@ -25,6 +25,7 @@ import net.minecraftforge.registries.RegistryObject; import thedarkcolour.exdeorum.ExDeorum; import thedarkcolour.exdeorum.recipe.TagResultRecipe; import thedarkcolour.exdeorum.recipe.barrel.BarrelCompostRecipe; +import thedarkcolour.exdeorum.recipe.barrel.BarrelFluidMixingRecipe; import thedarkcolour.exdeorum.recipe.barrel.BarrelMixingRecipe; import thedarkcolour.exdeorum.recipe.crucible.CrucibleRecipe; import thedarkcolour.exdeorum.recipe.hammer.HammerRecipe; @@ -35,6 +36,7 @@ public class ERecipeSerializers { public static final RegistryObject> BARREL_COMPOST = RECIPE_SERIALIZERS.register("barrel_compost", BarrelCompostRecipe.Serializer::new); public static final RegistryObject> BARREL_MIXING = RECIPE_SERIALIZERS.register("barrel_mixing", BarrelMixingRecipe.Serializer::new); + public static final RegistryObject> BARREL_FLUID_MIXING = RECIPE_SERIALIZERS.register("barrel_fluid_mixing", BarrelFluidMixingRecipe.Serializer::new); public static final RegistryObject> HAMMER = RECIPE_SERIALIZERS.register("hammer", HammerRecipe.Serializer::new); diff --git a/src/main/java/thedarkcolour/exdeorum/registry/ERecipeTypes.java b/src/main/java/thedarkcolour/exdeorum/registry/ERecipeTypes.java index af25f944..782ffcf9 100644 --- a/src/main/java/thedarkcolour/exdeorum/registry/ERecipeTypes.java +++ b/src/main/java/thedarkcolour/exdeorum/registry/ERecipeTypes.java @@ -24,6 +24,7 @@ import net.minecraftforge.registries.DeferredRegister; import net.minecraftforge.registries.RegistryObject; import thedarkcolour.exdeorum.ExDeorum; import thedarkcolour.exdeorum.recipe.barrel.BarrelCompostRecipe; +import thedarkcolour.exdeorum.recipe.barrel.BarrelFluidMixingRecipe; import thedarkcolour.exdeorum.recipe.barrel.BarrelMixingRecipe; import thedarkcolour.exdeorum.recipe.crucible.CrucibleRecipe; import thedarkcolour.exdeorum.recipe.hammer.HammerRecipe; @@ -34,6 +35,7 @@ public class ERecipeTypes { public static final RegistryObject> BARREL_COMPOST = RECIPE_TYPES.register("barrel_compost", () -> RecipeType.simple(ERecipeTypes.BARREL_COMPOST.getId())); public static final RegistryObject> BARREL_MIXING = RECIPE_TYPES.register("barrel_mixing", () -> RecipeType.simple(ERecipeTypes.BARREL_MIXING.getId())); + public static final RegistryObject> BARREL_FLUID_MIXING = RECIPE_TYPES.register("barrel_fluid_mixing", () -> RecipeType.simple(ERecipeTypes.BARREL_FLUID_MIXING.getId())); public static final RegistryObject> LAVA_CRUCIBLE = RECIPE_TYPES.register("lava_crucible", () -> RecipeType.simple(ERecipeTypes.LAVA_CRUCIBLE.getId())); public static final RegistryObject> WATER_CRUCIBLE = RECIPE_TYPES.register("water_crucible", () -> RecipeType.simple(ERecipeTypes.WATER_CRUCIBLE.getId())); diff --git a/src/main/resources/coremods.js b/src/main/resources/coremods.js index 503e3dac..1fb99f85 100644 --- a/src/main/resources/coremods.js +++ b/src/main/resources/coremods.js @@ -107,8 +107,6 @@ function initializeCoreMod() { new FieldInsnNode(Opcodes.PUTFIELD, insn.owner, insn.name, insn.desc) )); - ASMAPI.log('INFO', 'The node we are patching at: { opcode: ' + insn.getOpcode() + ', name: ' + insn.name); - ASMAPI.log('INFO', 'Successfully patched end portal.'); return method; }