diff --git a/src/core/java/com/enderio/core/client/gui/widgets/EIOImageButton.java b/src/core/java/com/enderio/core/client/gui/widgets/EIOImageButton.java index 257b17519c..87cd2b5a03 100644 --- a/src/core/java/com/enderio/core/client/gui/widgets/EIOImageButton.java +++ b/src/core/java/com/enderio/core/client/gui/widgets/EIOImageButton.java @@ -5,21 +5,34 @@ import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.ImageButton; import net.minecraft.client.gui.components.WidgetSprites; +import net.minecraft.network.chat.Component; + +import javax.annotation.Nullable; // Wrapper for ImageButton to draw background. // Can be removed after GUI redesign if no longer required. public class EIOImageButton extends ImageButton { - private final EIOScreen addedOn; + private final EIOScreen screen; + @Nullable private final Component message; - public EIOImageButton(EIOScreen addedOn, int x, int y, int width, int height, WidgetSprites sprites, OnPress onPress) { + public EIOImageButton(EIOScreen screen, int x, int y, int width, int height, WidgetSprites sprites, OnPress onPress, @Nullable Component message) { super(x, y, width, height, sprites, onPress); - this.addedOn = addedOn; + this.screen = screen; + this.message = message; + } + + public EIOImageButton(EIOScreen screen, int x, int y, int width, int height, WidgetSprites sprites, OnPress onPress) { + this(screen, x, y, width, height, sprites, onPress, null); } @Override public void renderWidget(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) { - addedOn.renderSimpleArea(guiGraphics, new Vector2i(getX(), getY()), new Vector2i(getX() + getWidth(), getY() + getHeight())); + screen.renderSimpleArea(guiGraphics, new Vector2i(getX(), getY()), new Vector2i(getX() + getWidth(), getY() + getHeight())); super.renderWidget(guiGraphics, mouseX, mouseY, partialTick); + + if (this.isHovered() && message != null) { + guiGraphics.renderTooltip(screen.getMinecraft().font, message, mouseX, mouseY); + } } } diff --git a/src/generated/resources/assets/enderio/blockstates/vat.json b/src/generated/resources/assets/enderio/blockstates/vat.json new file mode 100644 index 0000000000..1c3e62e96b --- /dev/null +++ b/src/generated/resources/assets/enderio/blockstates/vat.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "enderio:block/vat_combined", + "y": 90 + }, + "facing=north": { + "model": "enderio:block/vat_combined" + }, + "facing=south": { + "model": "enderio:block/vat_combined", + "y": 180 + }, + "facing=west": { + "model": "enderio:block/vat_combined", + "y": 270 + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/enderio/lang/en_us.json b/src/generated/resources/assets/enderio/lang/en_us.json index eb71693437..61603d2b84 100644 --- a/src/generated/resources/assets/enderio/lang/en_us.json +++ b/src/generated/resources/assets/enderio/lang/en_us.json @@ -205,6 +205,7 @@ "block.enderio.travel_anchor": "Travel Anchor", "block.enderio.vacuum_chest": "Vacuum Chest", "block.enderio.vapor_of_levity": "Vapor Of Levity", + "block.enderio.vat": "VAT", "block.enderio.vibrant_alloy_block": "Vibrant Alloy Block", "block.enderio.vibrant_capacitor_bank": "Vibrant Capacitor Bank", "block.enderio.vibrant_photovoltaic_module": "Vibrant Photovoltaic Module", @@ -237,12 +238,14 @@ "gui.enderio.alloy_smelter.mode_alloy": "Alloys Only", "gui.enderio.alloy_smelter.mode_furnace": "Furnace Only", "gui.enderio.blocked_redstone": "The machine is blocked by redstone", + "gui.enderio.button.dump_tank": "Void tank contents", "gui.enderio.button.retrieve_10_level": "Retrieve 10 levels of XP", "gui.enderio.button.retrieve_1_level": "Retrieve 1 level of XP", "gui.enderio.button.retrieve_all_level": "Retrieve all levels of XP", "gui.enderio.button.store_10_level": "Store 10 levels of XP", "gui.enderio.button.store_1_level": "Store 1 level of XP", "gui.enderio.button.store_all_level": "Store all levels of XP", + "gui.enderio.button.transfer_tank": "Transfer tank contents", "gui.enderio.cancel": "Cancel", "gui.enderio.category.alloy_smelting": "Alloy Smelting", "gui.enderio.category.enchanter": "Enchanting", diff --git a/src/generated/resources/assets/enderio/models/block/vat_combined.json b/src/generated/resources/assets/enderio/models/block/vat_combined.json new file mode 100644 index 0000000000..f1fd6a8292 --- /dev/null +++ b/src/generated/resources/assets/enderio/models/block/vat_combined.json @@ -0,0 +1,19 @@ +{ + "parent": "minecraft:block/block", + "children": { + "machine": { + "parent": "enderio:block/vat" + }, + "overlay": { + "parent": "enderio:block/io_overlay" + } + }, + "item_render_order": [ + "machine", + "overlay" + ], + "loader": "neoforge:composite", + "textures": { + "particle": "enderio:block/vat_front" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/enderio/models/item/vat.json b/src/generated/resources/assets/enderio/models/item/vat.json new file mode 100644 index 0000000000..7eec742c9c --- /dev/null +++ b/src/generated/resources/assets/enderio/models/item/vat.json @@ -0,0 +1,3 @@ +{ + "parent": "enderio:block/vat" +} \ No newline at end of file diff --git a/src/generated/resources/data/c/tags/item/crops.json b/src/generated/resources/data/c/tags/item/crops.json new file mode 100644 index 0000000000..498cb445f6 --- /dev/null +++ b/src/generated/resources/data/c/tags/item/crops.json @@ -0,0 +1,5 @@ +{ + "values": [ + "minecraft:wheat" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/c/tags/item/seeds.json b/src/generated/resources/data/c/tags/item/seeds.json new file mode 100644 index 0000000000..498cb445f6 --- /dev/null +++ b/src/generated/resources/data/c/tags/item/seeds.json @@ -0,0 +1,5 @@ +{ + "values": [ + "minecraft:wheat" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/enderio/data_maps/item/vat_reagent.json b/src/generated/resources/data/enderio/data_maps/item/vat_reagent.json new file mode 100644 index 0000000000..4fea5d770f --- /dev/null +++ b/src/generated/resources/data/enderio/data_maps/item/vat_reagent.json @@ -0,0 +1,8 @@ +{ + "values": { + "minecraft:wheat": { + "#c:crops": 3.0, + "#c:seeds": 2.0 + } + } +} \ No newline at end of file diff --git a/src/generated/resources/data/enderio/loot_table/blocks/vat.json b/src/generated/resources/data/enderio/loot_table/blocks/vat.json new file mode 100644 index 0000000000..64cca3b6b6 --- /dev/null +++ b/src/generated/resources/data/enderio/loot_table/blocks/vat.json @@ -0,0 +1,22 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:item", + "functions": [ + { + "function": "minecraft:copy_components", + "source": "block_entity" + } + ], + "name": "enderio:vat" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "enderio:blocks/vat" +} \ No newline at end of file diff --git a/src/generated/resources/data/enderio/recipe/fermenting/fluid_hootch_still.json b/src/generated/resources/data/enderio/recipe/fermenting/fluid_hootch_still.json new file mode 100644 index 0000000000..b088d8032d --- /dev/null +++ b/src/generated/resources/data/enderio/recipe/fermenting/fluid_hootch_still.json @@ -0,0 +1,14 @@ +{ + "type": "enderio:vat_fermenting", + "input": { + "amount": 1000, + "tag": "minecraft:water" + }, + "left_reagent": "c:seeds", + "output": { + "amount": 250, + "id": "enderio:fluid_hootch_still" + }, + "right_reagent": "c:crops", + "ticks": 100 +} \ No newline at end of file diff --git a/src/generated/resources/data/minecraft/tags/block/mineable/pickaxe.json b/src/generated/resources/data/minecraft/tags/block/mineable/pickaxe.json index 0fbadc0db3..e2862f2fa9 100644 --- a/src/generated/resources/data/minecraft/tags/block/mineable/pickaxe.json +++ b/src/generated/resources/data/minecraft/tags/block/mineable/pickaxe.json @@ -62,6 +62,7 @@ "enderio:crafter", "enderio:soul_engine", "enderio:drain", + "enderio:vat", "enderio:xp_obelisk", "enderio:conduit" ] diff --git a/src/generated/resources/data/minecraft/tags/block/needs_iron_tool.json b/src/generated/resources/data/minecraft/tags/block/needs_iron_tool.json index d1051c6e55..dd82758a57 100644 --- a/src/generated/resources/data/minecraft/tags/block/needs_iron_tool.json +++ b/src/generated/resources/data/minecraft/tags/block/needs_iron_tool.json @@ -26,6 +26,7 @@ "enderio:crafter", "enderio:soul_engine", "enderio:drain", + "enderio:vat", "enderio:xp_obelisk" ] } \ No newline at end of file diff --git a/src/machines/java/com/enderio/machines/EIOMachines.java b/src/machines/java/com/enderio/machines/EIOMachines.java index b77fe360fd..f1446212e4 100644 --- a/src/machines/java/com/enderio/machines/EIOMachines.java +++ b/src/machines/java/com/enderio/machines/EIOMachines.java @@ -19,8 +19,10 @@ import com.enderio.machines.common.menu.PreviewMachineSlot; import com.enderio.machines.common.tag.MachineTags; import com.enderio.machines.data.advancements.MachinesAdvancementGenerator; +import com.enderio.machines.data.reagentdata.ReagentDataProvider; import com.enderio.machines.data.recipes.AlloyRecipeProvider; import com.enderio.machines.data.recipes.EnchanterRecipeProvider; +import com.enderio.machines.data.recipes.FermentingRecipeProvider; import com.enderio.machines.data.recipes.MachineRecipeProvider; import com.enderio.machines.data.recipes.PaintingRecipeProvider; import com.enderio.machines.data.recipes.SagMillRecipeProvider; @@ -88,6 +90,7 @@ public static void gatherData(GatherDataEvent event) { provider.addSubProvider(event.includeServer(), new MachineRecipeProvider(packOutput, lookupProvider)); provider.addSubProvider(event.includeServer(), new AlloyRecipeProvider(packOutput, lookupProvider)); provider.addSubProvider(event.includeServer(), new EnchanterRecipeProvider(packOutput, lookupProvider)); + provider.addSubProvider(event.includeServer(), new FermentingRecipeProvider(packOutput, lookupProvider)); provider.addSubProvider(event.includeServer(), new SagMillRecipeProvider(packOutput, lookupProvider)); provider.addSubProvider(event.includeServer(), new SlicingRecipeProvider(packOutput, lookupProvider)); provider.addSubProvider(event.includeServer(), new SoulBindingRecipeProvider(packOutput, lookupProvider)); @@ -95,6 +98,7 @@ public static void gatherData(GatherDataEvent event) { provider.addSubProvider(event.includeServer(), new PaintingRecipeProvider(packOutput, lookupProvider)); provider.addSubProvider(event.includeServer(), new SoulDataProvider(packOutput)); provider.addSubProvider(event.includeServer(), new MachineEntityTypeTagsProvider(packOutput, lookupProvider, event.getExistingFileHelper())); + provider.addSubProvider(event.includeServer(), new ReagentDataProvider(packOutput, lookupProvider, event.getExistingFileHelper())); generator.addProvider(true, provider); provider.addSubProvider(event.includeServer(), new AdvancementProvider(packOutput, event.getLookupProvider(), event.getExistingFileHelper(), diff --git a/src/machines/java/com/enderio/machines/client/gui/screen/VatScreen.java b/src/machines/java/com/enderio/machines/client/gui/screen/VatScreen.java new file mode 100644 index 0000000000..2caeeb87a9 --- /dev/null +++ b/src/machines/java/com/enderio/machines/client/gui/screen/VatScreen.java @@ -0,0 +1,161 @@ +package com.enderio.machines.client.gui.screen; + +import com.enderio.EnderIO; +import com.enderio.api.misc.Vector2i; +import com.enderio.base.common.lang.EIOLang; +import com.enderio.core.client.gui.screen.EIOScreen; +import com.enderio.core.client.gui.widgets.EIOImageButton; +import com.enderio.core.client.gui.widgets.EnumIconWidget; +import com.enderio.machines.client.gui.widget.ActivityWidget; +import com.enderio.machines.client.gui.widget.FermentationWidget; +import com.enderio.machines.client.gui.widget.FluidStackWidget; +import com.enderio.machines.client.gui.widget.ProgressWidget; +import com.enderio.machines.client.gui.widget.ioconfig.IOConfigButton; +import com.enderio.machines.common.io.fluid.MachineFluidTank; +import com.enderio.machines.common.lang.MachineLang; +import com.enderio.machines.common.menu.VatMenu; +import com.enderio.machines.common.recipe.FermentingRecipe; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.WidgetSprites; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.RecipeHolder; +import net.neoforged.neoforge.fluids.FluidStack; +import org.jetbrains.annotations.NotNull; + +import java.util.Optional; + +public class VatScreen extends EIOScreen { + + private static final ResourceLocation VAT_BG = EnderIO.loc("textures/gui/vat.png"); + private static final ResourceLocation VAT_COVER = EnderIO.loc("vat_cover"); + public static final ResourceLocation MOVE_FLUID = EnderIO.loc("buttons/move_fluid"); + public static final ResourceLocation VOID_FLUID = EnderIO.loc("buttons/void_fluid"); + + private FermentingRecipe recipeCache; + private ResourceLocation recipeId; + + public VatScreen(VatMenu pMenu, Inventory pPlayerInventory, Component pTitle) { + super(pMenu, pPlayerInventory, pTitle, false); + } + + @Override + protected void init() { + super.init(); + updateRecipeCache(); + addRenderableOnly(new FluidStackWidget(this, this::wrappedInputTank, 30 + leftPos, 12 + topPos, 15, 47)); + addRenderableOnly(new FluidStackWidget(this, getMenu().getBlockEntity()::getOutputTank, 132 + leftPos, 12 + topPos, 15, 47)); + + addRenderableOnly( + new FermentationWidget(this::isCrafting, this::inputFluidStack, this::outputFluidStack, this::getProgress, 76 + leftPos, 34 + topPos, 26, 28)); + + addRenderableOnly(new ProgressWidget.BottomUp(this, this::getProgress, 82 + leftPos, 64 + topPos, 14, 14, 176, 0)); + + addRenderableWidget(new EnumIconWidget<>(this, leftPos + imageWidth - 6 - 16, topPos + 6, () -> menu.getBlockEntity().getRedstoneControl(), + control -> menu.getBlockEntity().setRedstoneControl(control), EIOLang.REDSTONE_MODE)); + + addRenderableWidget(new IOConfigButton<>(this, leftPos + imageWidth - 6 - 16, topPos + 24, 16, 16, menu, this::addRenderableWidget, font)); + addRenderableWidget(new ActivityWidget(this, menu.getBlockEntity()::getMachineStates, leftPos + imageWidth - 6 - 16, topPos + 16 * 4)); + + addRenderableWidget(new EIOImageButton(this, leftPos + 29, topPos + 62, 16, 16, new WidgetSprites(MOVE_FLUID, MOVE_FLUID), + press -> menu.getBlockEntity().moveFluidToOutputTank(), MachineLang.TRANSFER_TANK)); + + addRenderableWidget(new EIOImageButton(this, leftPos + 131, topPos + 62, 16, 16, new WidgetSprites(VOID_FLUID, VOID_FLUID), + press -> menu.getBlockEntity().dumpOutputTank(), MachineLang.DUMP_TANK)); + } + + @Override + public void render(GuiGraphics guiGraphics, int pMouseX, int pMouseY, float pPartialTicks) { + updateRecipeCache(); + super.render(guiGraphics, pMouseX, pMouseY, pPartialTicks); + + guiGraphics.blitSprite(VAT_COVER, 76 + leftPos, 34 + topPos, 26, 28); + drawModifierStrings(guiGraphics); + } + + @Override + public ResourceLocation getBackgroundImage() { + return VAT_BG; + } + + @Override + protected Vector2i getBackgroundImageSize() { + return new Vector2i(176, 166); + } + + private void updateRecipeCache() { + if (recipeId != getMenu().getBlockEntity().getRecipeId()) { + recipeId = getMenu().getBlockEntity().getRecipeId(); + Optional> optional = Minecraft.getInstance().level.getRecipeManager().byKey(recipeId); + if (optional.isPresent() && optional.get().value() instanceof FermentingRecipe recipe) { + recipeCache = recipe; + } + } + } + + private boolean isCrafting() { + return recipeCache != null && getMenu().getBlockEntity().getCraftingHost().getProgress() > 0; + } + + private FluidStack inputFluidStack() { + return getMenu().getBlockEntity().getInputTank().getFluid(); + } + + private FluidStack outputFluidStack() { + return recipeCache.output(); + } + + private float getProgress() { + return menu.getBlockEntity().getProgress(); + } + + /** + * Wraps the essential parts of the input tank. Remove the amount of fluid in client screen to fake the effect of consumption of fluid. + */ + private MachineFluidTank wrappedInputTank() { + MachineFluidTank tank = getMenu().getBlockEntity().getInputTank(); + return new MachineFluidTank(0, null) { + @Override + public @NotNull FluidStack getFluid() { + return tank.getFluid(); + } + + @Override + public int getFluidAmount() { + int reduced = 0; + if (isCrafting()) { + reduced = recipeCache.input().amount(); + } + return Math.max(tank.getFluidAmount() - reduced, 0); + } + + @Override + public int getCapacity() { + return tank.getCapacity(); + } + }; + } + + private void drawModifierStrings(GuiGraphics guiGraphics) { + if (!isCrafting()) { + return; + } + // left modifier + ItemStack item = getMenu().getSlot(0).getItem(); + double modifier = FermentingRecipe.getModifier(item, recipeCache.leftReagent()); + String text = "x" + modifier; + int x = getGuiLeft() + 63 - minecraft.font.width(text) / 2; + guiGraphics.drawString(minecraft.font, text, x, getGuiTop() + 32, 4210752, false); + + // right modifier + item = getMenu().getSlot(1).getItem(); + modifier = FermentingRecipe.getModifier(item, recipeCache.rightReagent()); + text = "x" + modifier; + x = getGuiLeft() + 113 - minecraft.font.width(text) / 2; + guiGraphics.drawString(minecraft.font, text, x, getGuiTop() + 32, 4210752, false); + + } +} diff --git a/src/machines/java/com/enderio/machines/client/gui/widget/FermentationWidget.java b/src/machines/java/com/enderio/machines/client/gui/widget/FermentationWidget.java new file mode 100644 index 0000000000..ee74117182 --- /dev/null +++ b/src/machines/java/com/enderio/machines/client/gui/widget/FermentationWidget.java @@ -0,0 +1,74 @@ +package com.enderio.machines.client.gui.widget; + +import com.enderio.core.client.gui.widgets.EIOWidget; +import com.mojang.blaze3d.systems.RenderSystem; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.narration.NarrationElementOutput; +import net.minecraft.client.renderer.texture.AbstractTexture; +import net.minecraft.client.renderer.texture.TextureAtlas; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.FastColor; +import net.neoforged.neoforge.client.extensions.common.IClientFluidTypeExtensions; +import net.neoforged.neoforge.fluids.FluidStack; + +import java.util.function.Supplier; + +public class FermentationWidget extends EIOWidget { + private final Supplier shouldShow; + private final Supplier first; + private final Supplier second; + private final Supplier progress; + + public FermentationWidget(Supplier shouldShow, Supplier first, Supplier second, Supplier progress, int x, int y, + int width, + int height) { + super(x, y, width, height); + this.shouldShow = shouldShow; + this.first = first; + this.second = second; + this.progress = progress; + } + + @Override + protected void renderWidget(GuiGraphics guiGraphics, int pMouseX, int pMouseY, float pPartialTick) { + RenderSystem.defaultBlendFunc(); + RenderSystem.enableDepthTest(); + + if (shouldShow.get() && !first.get().isEmpty()) { + renderFluid(guiGraphics, first.get(), 1 - progress.get()); + renderFluid(guiGraphics, second.get(), progress.get()); + } + + RenderSystem.disableDepthTest(); + } + + @Override + protected void updateWidgetNarration(NarrationElementOutput pNarrationElementOutput) {} + + public void renderFluid(GuiGraphics guiGraphics, FluidStack fluid, float opacity) { + if (fluid.isEmpty()) { + return; + } + Minecraft minecraft = Minecraft.getInstance(); + IClientFluidTypeExtensions props = IClientFluidTypeExtensions.of(fluid.getFluid()); + ResourceLocation loc = props.getStillTexture(); + + AbstractTexture texture = minecraft.getTextureManager().getTexture(TextureAtlas.LOCATION_BLOCKS); + if (texture instanceof TextureAtlas atlas) { + TextureAtlasSprite sprite = atlas.getSprite(loc); + + int color = props.getTintColor(); + RenderSystem.setShaderColor(FastColor.ARGB32.red(color) / 255.0F, FastColor.ARGB32.green(color) / 255.0F, FastColor.ARGB32.blue(color) / 255.0F, + FastColor.ARGB32.alpha(color) * opacity / 255.0F); + RenderSystem.enableBlend(); + + int atlasWidth = (int) (sprite.contents().width() / (sprite.getU1() - sprite.getU0())); + int atlasHeight = (int) (sprite.contents().height() / (sprite.getV1() - sprite.getV0())); + guiGraphics.blit(TextureAtlas.LOCATION_BLOCKS, x, y, width, height, sprite.getU0() * atlasWidth, sprite.getV0() * atlasHeight, + sprite.contents().width(), sprite.contents().height(), atlasWidth, atlasHeight); + RenderSystem.setShaderColor(1, 1, 1, 1); + } + } +} diff --git a/src/machines/java/com/enderio/machines/common/blockentity/FluidTankBlockEntity.java b/src/machines/java/com/enderio/machines/common/blockentity/FluidTankBlockEntity.java index 029bc8c381..5f06998c5f 100644 --- a/src/machines/java/com/enderio/machines/common/blockentity/FluidTankBlockEntity.java +++ b/src/machines/java/com/enderio/machines/common/blockentity/FluidTankBlockEntity.java @@ -245,7 +245,7 @@ public ItemInteractionResult onBlockEntityUsed(BlockState state, Level level, Bl ItemStack stack = player.getItemInHand(hand); if (!stack.isEmpty() && handleFluidItemInteraction(player, hand, stack, this, TANK)) { player.getInventory().setChanged(); - return ItemInteractionResult.CONSUME; + return ItemInteractionResult.sidedSuccess(level.isClientSide()); } return super.onBlockEntityUsed(state, level, pos, player, hand, hit); } diff --git a/src/machines/java/com/enderio/machines/common/blockentity/VatBlockEntity.java b/src/machines/java/com/enderio/machines/common/blockentity/VatBlockEntity.java new file mode 100644 index 0000000000..8fc9f4a77a --- /dev/null +++ b/src/machines/java/com/enderio/machines/common/blockentity/VatBlockEntity.java @@ -0,0 +1,260 @@ +package com.enderio.machines.common.blockentity; + +import com.enderio.EnderIO; +import com.enderio.core.common.network.NetworkDataSlot; +import com.enderio.core.common.recipes.OutputStack; +import com.enderio.machines.common.attachment.FluidTankUser; +import com.enderio.machines.common.blockentity.base.MachineBlockEntity; +import com.enderio.machines.common.blockentity.task.CraftingMachineTask; +import com.enderio.machines.common.blockentity.task.host.CraftingMachineTaskHost; +import com.enderio.machines.common.init.MachineBlockEntities; +import com.enderio.machines.common.init.MachineRecipes; +import com.enderio.machines.common.io.fluid.FluidItemInteractive; +import com.enderio.machines.common.io.fluid.MachineFluidHandler; +import com.enderio.machines.common.io.fluid.MachineFluidTank; +import com.enderio.machines.common.io.fluid.MachineTankLayout; +import com.enderio.machines.common.io.fluid.TankAccess; +import com.enderio.machines.common.io.item.MachineInventory; +import com.enderio.machines.common.io.item.MachineInventoryLayout; +import com.enderio.machines.common.io.item.MultiSlotAccess; +import com.enderio.machines.common.menu.VatMenu; +import com.enderio.machines.common.network.VatDumpTankPacket; +import com.enderio.machines.common.network.VatMoveTankPacket; +import com.enderio.machines.common.recipe.FermentingRecipe; +import net.minecraft.core.BlockPos; +import net.minecraft.core.HolderLookup; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.ItemInteractionResult; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.RecipeHolder; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.neoforged.neoforge.fluids.FluidStack; +import net.neoforged.neoforge.fluids.FluidType; +import net.neoforged.neoforge.fluids.capability.IFluidHandler; +import net.neoforged.neoforge.network.PacketDistributor; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +public class VatBlockEntity extends MachineBlockEntity implements FluidTankUser, FluidItemInteractive { + + public static final int TANK_CAPACITY = 8 * FluidType.BUCKET_VOLUME; + private static final TankAccess INPUT_TANK = new TankAccess(); + private static final TankAccess OUTPUT_TANK = new TankAccess(); + public static final MultiSlotAccess REAGENTS = new MultiSlotAccess(); + private static final ResourceLocation EMPTY = EnderIO.loc(""); + + private final MachineFluidHandler fluidHandler; + private final CraftingMachineTaskHost craftingTaskHost; + private final NetworkDataSlot inputTankDataSlot; + private final NetworkDataSlot outputTankDataSlot; + + private ResourceLocation recipeId; + + public VatBlockEntity(BlockPos worldPosition, BlockState blockState) { + super(MachineBlockEntities.VAT.get(), worldPosition, blockState); + fluidHandler = createFluidHandler(); + + // Sync fluid_stacks and active recipe. + inputTankDataSlot = addDataSlot(NetworkDataSlot.FLUID_STACK.create(() -> INPUT_TANK.getFluid(this), stack -> INPUT_TANK.setFluid(this, stack))); + outputTankDataSlot = addDataSlot(NetworkDataSlot.FLUID_STACK.create(() -> OUTPUT_TANK.getFluid(this), stack -> OUTPUT_TANK.setFluid(this, stack))); + + addDataSlot(NetworkDataSlot.RESOURCE_LOCATION.create(this::getRecipeId, this::setRecipeId)); + + craftingTaskHost = new CraftingMachineTaskHost<>(this, () -> true, MachineRecipes.VAT_FERMENTING.type().get(), this::createTask, + this::createRecipeInput); + } + + @Nullable + @Override + public AbstractContainerMenu createMenu(int containerId, Inventory playerInventory, Player player) { + return new VatMenu(this, playerInventory, containerId); + } + + @Override + public void serverTick() { + super.serverTick(); + + if (canAct()) { + craftingTaskHost.tick(); + } + updateMachineState(MachineState.ACTIVE, isActive()); + } + + protected boolean isActive() { + return canAct() && craftingTaskHost.hasTask(); + } + + @Override + public void onLoad() { + super.onLoad(); + craftingTaskHost.onLevelReady(); + } + + @Override + public ItemInteractionResult onBlockEntityUsed(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) { + ItemStack stack = player.getItemInHand(hand); + if (!stack.isEmpty()) { + if (handleFluidItemInteraction(player, hand, stack, this, INPUT_TANK) || handleFluidItemInteraction(player, hand, stack, this, OUTPUT_TANK)) { + player.getInventory().setChanged(); + return ItemInteractionResult.sidedSuccess(level.isClientSide()); + } + } + return super.onBlockEntityUsed(state, level, pos, player, hand, hit); + } + + protected VatBlockEntity.VatCraftingMachineTask createTask(Level level, FermentingRecipe.Input input, + @Nullable RecipeHolder recipe) { + return new VatBlockEntity.VatCraftingMachineTask(level, getInventoryNN(), getFluidHandler(), input, recipe); + } + + @Override + public @Nullable MachineInventoryLayout getInventoryLayout() { + return MachineInventoryLayout.builder().inputSlot(2).slotAccess(REAGENTS).build(); + } + + @Override + protected void onInventoryContentsChanged(int slot) { + super.onInventoryContentsChanged(slot); + craftingTaskHost.newTaskAvailable(); + } + + private FermentingRecipe.Input createRecipeInput() { + List reagents = REAGENTS.getItemStacks(getInventoryNN()); + return new FermentingRecipe.Input(reagents.get(0), reagents.get(1), getInputTank()); + } + + @Override + public MachineTankLayout getTankLayout() { + return MachineTankLayout + .builder() + .tank(INPUT_TANK, TANK_CAPACITY, true, false, (stack) -> true) + .tank(OUTPUT_TANK, TANK_CAPACITY, false, true, (stack) -> true) + .build(); + } + + @Override + public MachineFluidHandler getFluidHandler() { + return fluidHandler; + } + + @Override + public MachineFluidHandler createFluidHandler() { + return new MachineFluidHandler(this, getTankLayout()) { + @Override + protected void onContentsChanged(int slot) { + super.onContentsChanged(slot); + craftingTaskHost.newTaskAvailable(); + setChanged(); + } + }; + } + + public MachineFluidTank getInputTank() { + return INPUT_TANK.getTank(this); + } + + public MachineFluidTank getOutputTank() { + return OUTPUT_TANK.getTank(this); + } + + public float getProgress() { + return craftingTaskHost.getProgress(); + } + + public ResourceLocation getRecipeId() { + if (level.isClientSide()) { + return recipeId; + } + + if (craftingTaskHost.getCurrentTask() != null) { + ResourceLocation id = craftingTaskHost.getCurrentTask().getRecipeId(); + return id != null ? id : EMPTY; + } + return EMPTY; + } + + public void setRecipeId(ResourceLocation recipeId) { + this.recipeId = recipeId; + } + + public CraftingMachineTaskHost getCraftingHost() { + return craftingTaskHost; + } + + public void moveFluidToOutputTank() { + if (level != null && level.isClientSide()) { + PacketDistributor.sendToServer(new VatMoveTankPacket(getBlockPos())); + } else { + if (OUTPUT_TANK.isEmpty(this) && !INPUT_TANK.isEmpty(this)) { + OUTPUT_TANK.setFluid(this, INPUT_TANK.getFluid(this)); + INPUT_TANK.setFluid(this, FluidStack.EMPTY); + } + } + } + + public void dumpOutputTank() { + if (level != null && level.isClientSide()) { + PacketDistributor.sendToServer(new VatDumpTankPacket(getBlockPos())); + } else { + OUTPUT_TANK.setFluid(this, FluidStack.EMPTY); + } + } + + protected static class VatCraftingMachineTask extends CraftingMachineTask { + + public VatCraftingMachineTask(@NotNull Level level, MachineInventory inventory, MachineFluidHandler fluidHandler, FermentingRecipe.Input input, + @Nullable RecipeHolder recipe) { + super(level, inventory, fluidHandler, input, recipe); + } + + @Override + protected void consumeInputs(FermentingRecipe recipe) { + REAGENTS.get(0).getItemStack(inventory).shrink(1); + REAGENTS.get(1).getItemStack(inventory).shrink(1); + + INPUT_TANK.getTank(fluidHandler).drain(recipe.input().amount(), IFluidHandler.FluidAction.EXECUTE); + } + + @Override + protected boolean placeOutputs(List outputs, boolean simulate) { + var action = simulate ? IFluidHandler.FluidAction.SIMULATE : IFluidHandler.FluidAction.EXECUTE; + FluidStack output = outputs.getFirst().getFluid(); + int filled = OUTPUT_TANK.getTank(fluidHandler).fill(output, action); + return filled == output.getAmount(); + } + + @Override + protected int makeProgress(int remainingProgress) { + return 1; // do nothing. VAT doesn't consume power + } + + @Override + protected int getProgressRequired(FermentingRecipe recipe) { + return recipe.ticks(); + } + + } + + @Override + public void saveAdditional(CompoundTag pTag, HolderLookup.Provider lookupProvider) { + super.saveAdditional(pTag, lookupProvider); + saveTank(lookupProvider, pTag); + craftingTaskHost.save(lookupProvider, pTag); + } + + @Override + public void loadAdditional(CompoundTag pTag, HolderLookup.Provider lookupProvider) { + super.loadAdditional(pTag, lookupProvider); + loadTank(lookupProvider, pTag); + craftingTaskHost.load(lookupProvider, pTag); + } +} diff --git a/src/machines/java/com/enderio/machines/common/blockentity/base/MachineBlockEntity.java b/src/machines/java/com/enderio/machines/common/blockentity/base/MachineBlockEntity.java index 0255eba9f4..1b620d4365 100644 --- a/src/machines/java/com/enderio/machines/common/blockentity/base/MachineBlockEntity.java +++ b/src/machines/java/com/enderio/machines/common/blockentity/base/MachineBlockEntity.java @@ -1,6 +1,5 @@ package com.enderio.machines.common.blockentity.base; -import com.enderio.api.UseOnly; import com.enderio.api.capability.SideConfig; import com.enderio.api.io.IOConfigurable; import com.enderio.api.io.IOMode; @@ -39,7 +38,6 @@ import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.BlockHitResult; -import net.neoforged.fml.LogicalSide; import net.neoforged.neoforge.capabilities.Capabilities; import net.neoforged.neoforge.capabilities.ICapabilityProvider; import net.neoforged.neoforge.client.model.data.ModelData; @@ -410,7 +408,7 @@ private void moveFluids(Direction side) { return; } - TransferUtil.distributeFluids(getIOConfig().getMode(side), selfHandler, otherHandler); + TransferUtil.distributeFluids(getIOMode(side), selfHandler, otherHandler); } // endregion diff --git a/src/machines/java/com/enderio/machines/common/blockentity/task/CraftingMachineTask.java b/src/machines/java/com/enderio/machines/common/blockentity/task/CraftingMachineTask.java index b60bcb28c3..2711440b13 100644 --- a/src/machines/java/com/enderio/machines/common/blockentity/task/CraftingMachineTask.java +++ b/src/machines/java/com/enderio/machines/common/blockentity/task/CraftingMachineTask.java @@ -2,6 +2,7 @@ import com.enderio.core.common.recipes.OutputStack; import com.enderio.machines.common.blockentity.MachineState; +import com.enderio.machines.common.io.fluid.MachineFluidHandler; import com.enderio.machines.common.io.item.MachineInventory; import com.enderio.machines.common.io.item.MultiSlotAccess; import com.enderio.machines.common.io.item.SingleSlotAccess; @@ -27,6 +28,8 @@ public abstract class CraftingMachineTask, T extends protected final Level level; protected final MachineInventory inventory; + @Nullable protected final MachineFluidHandler fluidHandler; + @Nullable protected final MultiSlotAccess outputSlots; protected final T recipeInput; @@ -43,9 +46,21 @@ public abstract class CraftingMachineTask, T extends private boolean isComplete; - public CraftingMachineTask(@NotNull Level level, MachineInventory inventory, T recipeInput, MultiSlotAccess outputSlots, @Nullable RecipeHolder recipe) { + public CraftingMachineTask(@NotNull Level level, MachineInventory inventory, T recipeInput, @Nullable MultiSlotAccess outputSlots, + @Nullable RecipeHolder recipe) { + this(level, inventory, null, recipeInput, outputSlots, recipe); + } + + public CraftingMachineTask(@NotNull Level level, MachineInventory inventory, @Nullable MachineFluidHandler fluidHandler, T recipeInput, + @Nullable RecipeHolder recipe) { + this(level, inventory, fluidHandler, recipeInput, null, recipe); + } + + public CraftingMachineTask(@NotNull Level level, MachineInventory inventory, @Nullable MachineFluidHandler fluidHandler, T recipeInput, + @Nullable MultiSlotAccess outputSlots, @Nullable RecipeHolder recipe) { this.level = level; this.inventory = inventory; + this.fluidHandler = fluidHandler; this.recipeInput = recipeInput; this.outputSlots = outputSlots; this.recipe = recipe; @@ -63,6 +78,11 @@ public R getRecipe() { return recipe.value(); } + @Nullable + public ResourceLocation getRecipeId() { + return recipe.id(); + } + // region Abstract Implementation protected abstract void consumeInputs(R recipe); @@ -160,6 +180,11 @@ public boolean isCompleted() { protected boolean placeOutputs(List outputs, boolean simulate) { // TODO: Handle fluids too. + //return early if there are no output slots + if (outputSlots == null) { + return false; + } + // See that we can add all the outputs for (OutputStack output : outputs) { ItemStack item = output.getItem(); diff --git a/src/machines/java/com/enderio/machines/common/datamap/VatReagent.java b/src/machines/java/com/enderio/machines/common/datamap/VatReagent.java new file mode 100644 index 0000000000..37150585dd --- /dev/null +++ b/src/machines/java/com/enderio/machines/common/datamap/VatReagent.java @@ -0,0 +1,23 @@ +package com.enderio.machines.common.datamap; + +import com.enderio.EnderIO; +import com.mojang.serialization.Codec; +import net.minecraft.core.registries.Registries; +import net.minecraft.tags.TagKey; +import net.minecraft.util.ExtraCodecs; +import net.minecraft.world.item.Item; +import net.neoforged.neoforge.registries.datamaps.AdvancedDataMapType; +import net.neoforged.neoforge.registries.datamaps.DataMapValueRemover; + +import java.util.Map; + +public class VatReagent { + public static final ExtraCodecs.StrictUnboundedMapCodec, Double> CODEC = ExtraCodecs.strictUnboundedMap(TagKey.hashedCodec(Registries.ITEM), + Codec.DOUBLE); + + public static final AdvancedDataMapType, Double>, DataMapValueRemover.Default, Double>, Item>> DATA_MAP = AdvancedDataMapType + .builder(EnderIO.loc("vat_reagent"), Registries.ITEM, CODEC) + .synced(CODEC, true) + .build(); + +} diff --git a/src/machines/java/com/enderio/machines/common/datamap/package-info.java b/src/machines/java/com/enderio/machines/common/datamap/package-info.java new file mode 100644 index 0000000000..72c49f2a76 --- /dev/null +++ b/src/machines/java/com/enderio/machines/common/datamap/package-info.java @@ -0,0 +1,4 @@ +@javax.annotation.ParametersAreNonnullByDefault +@net.minecraft.MethodsReturnNonnullByDefault + +package com.enderio.machines.common.datamap; diff --git a/src/machines/java/com/enderio/machines/common/init/MachineBlockEntities.java b/src/machines/java/com/enderio/machines/common/init/MachineBlockEntities.java index ce5ebc0c2e..9460c9fd1e 100644 --- a/src/machines/java/com/enderio/machines/common/init/MachineBlockEntities.java +++ b/src/machines/java/com/enderio/machines/common/init/MachineBlockEntities.java @@ -24,6 +24,7 @@ import com.enderio.machines.common.blockentity.StirlingGeneratorBlockEntity; import com.enderio.machines.common.blockentity.TravelAnchorBlockEntity; import com.enderio.machines.common.blockentity.VacuumChestBlockEntity; +import com.enderio.machines.common.blockentity.VatBlockEntity; import com.enderio.machines.common.blockentity.WiredChargerBlockEntity; import com.enderio.machines.common.blockentity.XPObeliskBlockEntity; import com.enderio.machines.common.blockentity.XPVacuumBlockEntity; @@ -55,14 +56,13 @@ public class MachineBlockEntities { register("fluid_tank", FluidTankBlockEntity.Standard::new, MachineBlocks.FLUID_TANK) .setRenderer(() -> FluidTankBER::new) .apply(MachineBlockEntities::machineBlockEntityCapabilities) - .addCapability(Capabilities.FluidHandler.BLOCK, FluidTankUser.FLUID_HANDLER_PROVIDER); - + .apply(MachineBlockEntities::fluidHandlerCapability); public static final RegiliteBlockEntity PRESSURIZED_FLUID_TANK = register("pressurized_fluid_tank", FluidTankBlockEntity.Enhanced::new, MachineBlocks.PRESSURIZED_FLUID_TANK) .setRenderer(() -> FluidTankBER::new) .apply(MachineBlockEntities::machineBlockEntityCapabilities) - .addCapability(Capabilities.FluidHandler.BLOCK, FluidTankUser.FLUID_HANDLER_PROVIDER); + .apply(MachineBlockEntities::fluidHandlerCapability); public static final RegiliteBlockEntity ENCHANTER = register("enchanter", EnchanterBlockEntity::new, MachineBlocks.ENCHANTER); @@ -102,15 +102,14 @@ public class MachineBlockEntities { public static final RegiliteBlockEntity XP_VACUUM = register("xp_vacuum", XPVacuumBlockEntity::new, MachineBlocks.XP_VACUUM) .apply(MachineBlockEntities::machineBlockEntityCapabilities) - .addCapability(Capabilities.FluidHandler.BLOCK, FluidTankUser.FLUID_HANDLER_PROVIDER); + .apply(MachineBlockEntities::fluidHandlerCapability); public static final RegiliteBlockEntity TRAVEL_ANCHOR = register("travel_anchor", TravelAnchorBlockEntity::new, MachineBlocks.TRAVEL_ANCHOR) .apply(MachineBlockEntities::machineBlockEntityCapabilities); - public static final RegiliteBlockEntity PAINTED_TRAVEL_ANCHOR = - register("painted_travel_anchor", PaintedTravelAnchorBlockEntity::new, MachineBlocks.PAINTED_TRAVEL_ANCHOR) - .apply(MachineBlockEntities::machineBlockEntityCapabilities); + public static final RegiliteBlockEntity PAINTED_TRAVEL_ANCHOR = register("painted_travel_anchor", + PaintedTravelAnchorBlockEntity::new, MachineBlocks.PAINTED_TRAVEL_ANCHOR).apply(MachineBlockEntities::machineBlockEntityCapabilities); public static final RegiliteBlockEntity CRAFTER = register("crafter", CrafterBlockEntity::new, MachineBlocks.CRAFTER) @@ -119,12 +118,12 @@ public class MachineBlockEntities { public static final RegiliteBlockEntity DRAIN = register("drain", DrainBlockEntity::new, MachineBlocks.DRAIN) .apply(MachineBlockEntities::poweredMachineBlockEntityCapabilities) - .addCapability(Capabilities.FluidHandler.BLOCK, FluidTankUser.FLUID_HANDLER_PROVIDER); + .apply(MachineBlockEntities::fluidHandlerCapability); public static final RegiliteBlockEntity SOUL_BINDER = register("soul_binder", SoulBinderBlockEntity::new, MachineBlocks.SOUL_BINDER) .apply(MachineBlockEntities::poweredMachineBlockEntityCapabilities) - .addCapability(Capabilities.FluidHandler.BLOCK, FluidTankUser.FLUID_HANDLER_PROVIDER); + .apply(MachineBlockEntities::fluidHandlerCapability); public static final RegiliteBlockEntity WIRED_CHARGER = register("wired_charger", WiredChargerBlockEntity::new, MachineBlocks.WIRED_CHARGER) @@ -169,13 +168,17 @@ public class MachineBlockEntities { public static final RegiliteBlockEntity SOUL_ENGINE = register("soul_engine", SoulEngineBlockEntity::new, MachineBlocks.SOUL_ENGINE) .apply(MachineBlockEntities::poweredMachineBlockEntityCapabilities) - .addCapability(Capabilities.FluidHandler.BLOCK, FluidTankUser.FLUID_HANDLER_PROVIDER); + .apply(MachineBlockEntities::fluidHandlerCapability); public static final RegiliteBlockEntity XP_OBELISK = register("xp_obelisk", XPObeliskBlockEntity::new, MachineBlocks.XP_OBELISK) .setRenderer(() -> XPObeliskBER::new) .apply(MachineBlockEntities::machineBlockEntityCapabilities) - .addCapability(Capabilities.FluidHandler.BLOCK, FluidTankUser.FLUID_HANDLER_PROVIDER); + .apply(MachineBlockEntities::fluidHandlerCapability); + + public static final RegiliteBlockEntity VAT = register("vat", VatBlockEntity::new, MachineBlocks.VAT) + .apply(MachineBlockEntities::machineBlockEntityCapabilities) + .apply(MachineBlockEntities::fluidHandlerCapability); @SafeVarargs private static RegiliteBlockEntity register(String name, BlockEntityType.BlockEntitySupplier beFactory, @@ -194,6 +197,10 @@ private static void poweredMachineBlockEntityCapabilities(RegiliteBlockEntity blockEntity) { + blockEntity.addCapability(Capabilities.FluidHandler.BLOCK, FluidTankUser.FLUID_HANDLER_PROVIDER); + } + public static void register(IEventBus bus) { BLOCK_ENTITY_REGISTRY.register(bus); } diff --git a/src/machines/java/com/enderio/machines/common/init/MachineBlocks.java b/src/machines/java/com/enderio/machines/common/init/MachineBlocks.java index d494e28a78..3b3d2ec196 100644 --- a/src/machines/java/com/enderio/machines/common/init/MachineBlocks.java +++ b/src/machines/java/com/enderio/machines/common/init/MachineBlocks.java @@ -217,6 +217,8 @@ public class MachineBlocks { public static final RegiliteBlock DRAIN = progressMachine("drain", () -> MachineBlockEntities.DRAIN); + public static final RegiliteBlock VAT = machine("vat", () -> MachineBlockEntities.VAT).setTranslation("VAT"); + public static final RegiliteBlock XP_OBELISK = BLOCK_REGISTRY .registerBlock("xp_obelisk", props -> new MachineBlock(MachineBlockEntities.XP_OBELISK, props), BlockBehaviour.Properties.of().strength(2.5f, 8).isViewBlocking((pState, pLevel, pPos) -> false).noOcclusion()) diff --git a/src/machines/java/com/enderio/machines/common/init/MachineDataMaps.java b/src/machines/java/com/enderio/machines/common/init/MachineDataMaps.java new file mode 100644 index 0000000000..90084560ce --- /dev/null +++ b/src/machines/java/com/enderio/machines/common/init/MachineDataMaps.java @@ -0,0 +1,14 @@ +package com.enderio.machines.common.init; + +import com.enderio.machines.common.datamap.VatReagent; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.registries.datamaps.RegisterDataMapTypesEvent; + +@EventBusSubscriber(bus = EventBusSubscriber.Bus.MOD) +public class MachineDataMaps { + @SubscribeEvent + public static void registerDataMap(RegisterDataMapTypesEvent event) { + event.register(VatReagent.DATA_MAP); + } +} diff --git a/src/machines/java/com/enderio/machines/common/init/MachineMenus.java b/src/machines/java/com/enderio/machines/common/init/MachineMenus.java index d91e74d9b0..9f670b3549 100644 --- a/src/machines/java/com/enderio/machines/common/init/MachineMenus.java +++ b/src/machines/java/com/enderio/machines/common/init/MachineMenus.java @@ -18,6 +18,7 @@ import com.enderio.machines.client.gui.screen.StirlingGeneratorScreen; import com.enderio.machines.client.gui.screen.TravelAnchorScreen; import com.enderio.machines.client.gui.screen.VacuumChestScreen; +import com.enderio.machines.client.gui.screen.VatScreen; import com.enderio.machines.client.gui.screen.WiredChargerScreen; import com.enderio.machines.client.gui.screen.XPObeliskScreen; import com.enderio.machines.client.gui.screen.XPVacuumScreen; @@ -38,6 +39,7 @@ import com.enderio.machines.common.menu.StirlingGeneratorMenu; import com.enderio.machines.common.menu.TravelAnchorMenu; import com.enderio.machines.common.menu.VacuumChestMenu; +import com.enderio.machines.common.menu.VatMenu; import com.enderio.machines.common.menu.WiredChargerMenu; import com.enderio.machines.common.menu.XPObeliskMenu; import com.enderio.machines.common.menu.XPVacuumMenu; @@ -90,6 +92,7 @@ private MachineMenus() {} .registerMenu("travel_anchor", TravelAnchorMenu::factory, () -> TravelAnchorScreen::new); public static final RegiliteMenu XP_OBELISK = MENU_REGISTRY .registerMenu("xp_obelisk", XPObeliskMenu::factory, () -> XPObeliskScreen::new); + public static final RegiliteMenu VAT = MENU_REGISTRY.registerMenu("vat", VatMenu::factory, () -> VatScreen::new); public static void register(IEventBus bus) { MENU_REGISTRY.register(bus); diff --git a/src/machines/java/com/enderio/machines/common/init/MachineNetwork.java b/src/machines/java/com/enderio/machines/common/init/MachineNetwork.java index 6c9ab72f0c..451d9f9155 100644 --- a/src/machines/java/com/enderio/machines/common/init/MachineNetwork.java +++ b/src/machines/java/com/enderio/machines/common/init/MachineNetwork.java @@ -5,6 +5,8 @@ import com.enderio.machines.common.network.PoweredSpawnerSoulPacket; import com.enderio.machines.common.network.SoulEngineSoulPacket; import com.enderio.machines.common.network.UpdateCrafterTemplatePacket; +import com.enderio.machines.common.network.VatDumpTankPacket; +import com.enderio.machines.common.network.VatMoveTankPacket; import com.enderio.machines.common.souldata.EngineSoul; import com.enderio.machines.common.souldata.SpawnerSoul; import net.neoforged.bus.api.SubscribeEvent; @@ -34,5 +36,8 @@ public static void register(final RegisterPayloadHandlersEvent event) { registrar.playToServer(UpdateCrafterTemplatePacket.TYPE, UpdateCrafterTemplatePacket.STREAM_CODEC, MachinePayloadHandler.Server.getInstance()::updateCrafterTemplate); + + registrar.playToServer(VatMoveTankPacket.TYPE, VatMoveTankPacket.STREAM_CODEC, MachinePayloadHandler.Server.getInstance()::vatMoveTank); + registrar.playToServer(VatDumpTankPacket.TYPE, VatDumpTankPacket.STREAM_CODEC, MachinePayloadHandler.Server.getInstance()::vatDumpTank); } } diff --git a/src/machines/java/com/enderio/machines/common/init/MachineRecipes.java b/src/machines/java/com/enderio/machines/common/init/MachineRecipes.java index 702ec1126e..5ac5dbe546 100644 --- a/src/machines/java/com/enderio/machines/common/init/MachineRecipes.java +++ b/src/machines/java/com/enderio/machines/common/init/MachineRecipes.java @@ -4,6 +4,7 @@ import com.enderio.core.common.recipes.RecipeTypeSerializerPair; import com.enderio.machines.common.recipe.AlloySmeltingRecipe; import com.enderio.machines.common.recipe.EnchanterRecipe; +import com.enderio.machines.common.recipe.FermentingRecipe; import com.enderio.machines.common.recipe.PaintingRecipe; import com.enderio.machines.common.recipe.SagMillingRecipe; import com.enderio.machines.common.recipe.SlicingRecipe; @@ -31,6 +32,8 @@ public class MachineRecipes { public static final RecipeTypeSerializerPair SOUL_BINDING = register("soul_binding", SoulBindingRecipe.Serializer::new); public static final RecipeTypeSerializerPair TANK = register("tank", TankRecipe.Serializer::new); public static final RecipeTypeSerializerPair PAINTING = register("painting", PaintingRecipe.Serializer::new); + public static final RecipeTypeSerializerPair VAT_FERMENTING = register("vat_fermenting", + FermentingRecipe.Serializer::new); private static > DeferredHolder, RecipeType> registerType(String name) { return RECIPE_TYPES.register(name, () -> RecipeType.simple(EnderIO.loc(name))); diff --git a/src/machines/java/com/enderio/machines/common/io/fluid/FluidItemInteractive.java b/src/machines/java/com/enderio/machines/common/io/fluid/FluidItemInteractive.java index 270cb0b208..5dff5a32c2 100644 --- a/src/machines/java/com/enderio/machines/common/io/fluid/FluidItemInteractive.java +++ b/src/machines/java/com/enderio/machines/common/io/fluid/FluidItemInteractive.java @@ -34,7 +34,7 @@ default boolean handleFluidItemInteraction(Player player, InteractionHand hand, fluidInItem = handler.drain(new FluidStack(tankAccess.getFluid(machine).getFluid(), Integer.MAX_VALUE), IFluidHandler.FluidAction.SIMULATE); } if (fluidInItem.isEmpty()) { - if (!tankAccess.isEmpty(machine)) { + if (!tankAccess.isEmpty(machine) && tankAccess.canExtract(machine)) { int filled = handler.fill(tankAccess.getFluid(machine), player.isCreative() ? IFluidHandler.FluidAction.SIMULATE : IFluidHandler.FluidAction.EXECUTE); ItemStack container = handler.getContainer(); @@ -60,7 +60,7 @@ default boolean handleFluidItemInteraction(Player player, InteractionHand hand, return true; } } - } else { + } else if (tankAccess.canInsert(machine)) { int filledAmount = tankAccess.fill(machine, fluidInItem, IFluidHandler.FluidAction.SIMULATE); if (filledAmount > 0) { boolean filled = false; diff --git a/src/machines/java/com/enderio/machines/common/io/fluid/MachineFluidHandler.java b/src/machines/java/com/enderio/machines/common/io/fluid/MachineFluidHandler.java index 08ef06a01c..f3cc6df07b 100644 --- a/src/machines/java/com/enderio/machines/common/io/fluid/MachineFluidHandler.java +++ b/src/machines/java/com/enderio/machines/common/io/fluid/MachineFluidHandler.java @@ -84,6 +84,14 @@ public boolean isFluidValid(int tank, FluidStack stack) { return layout.isFluidValid(tank, stack); } + public boolean canInsert(int tank) { + return layout.canInsert(tank); + } + + public boolean canExtract(int tank) { + return layout.canExtract(tank); + } + @Nullable public IFluidHandler getForSide(@Nullable Direction side) { if (side == null) { @@ -158,8 +166,9 @@ public int fill(FluidStack resource, FluidAction action) { int totalFilled = 0; for (int index = 0; index < getTanks(); index++) { - if (!layout.canInsert(index)) + if (!canInsert(index)) { continue; + } // Attempt to fill the tank int filled = fill(index, resourceLeft, action); @@ -205,13 +214,15 @@ public FluidStack drain(int tank, FluidStack resource, IFluidHandler.FluidAction @Override public FluidStack drain(FluidStack resource, FluidAction action) { for (int index = 0; index < getTanks(); index++) { - if (drain(index, resource, FluidAction.SIMULATE) != FluidStack.EMPTY) { - FluidStack drained = drain(index, resource, action); - if (!drained.isEmpty()) { - onContentsChanged(index); - changeListener.accept(index); + if (canExtract(index)) { + if (drain(index, resource, FluidAction.SIMULATE) != FluidStack.EMPTY) { + FluidStack drained = drain(index, resource, action); + if (!drained.isEmpty()) { + onContentsChanged(index); + changeListener.accept(index); + } + return drained; } - return drained; } } @@ -221,13 +232,15 @@ public FluidStack drain(FluidStack resource, FluidAction action) { @Override public FluidStack drain(int maxDrain, FluidAction action) { for (int index = 0; index < getTanks(); index++) { - if (drain(index, maxDrain, FluidAction.SIMULATE) != FluidStack.EMPTY) { - FluidStack drained = drain(index, maxDrain, action); - if (!drained.isEmpty()) { - onContentsChanged(index); - changeListener.accept(index); + if (canExtract(index)) { + if (drain(index, maxDrain, FluidAction.SIMULATE) != FluidStack.EMPTY) { + FluidStack drained = drain(index, maxDrain, action); + if (!drained.isEmpty()) { + onContentsChanged(index); + changeListener.accept(index); + } + return drained; } - return drained; } } @@ -243,7 +256,6 @@ public CompoundTag serializeNBT(HolderLookup.Provider lookupProvider) { CompoundTag tankTag = new CompoundTag(); tankTag.putInt(TANK_INDEX, i); tankTag.put(TANK_CONTENTS, stacks.get(i).saveOptional(lookupProvider)); - nbtTagList.add(tankTag); } CompoundTag nbt = new CompoundTag(); @@ -257,7 +269,7 @@ public void deserializeNBT(HolderLookup.Provider lookupProvider, CompoundTag nbt for (int i = 0; i < tagList.size(); i++) { CompoundTag tankTag = tagList.getCompound(i); int index = tankTag.getInt(TANK_INDEX); - stacks.set(index, FluidStack.parseOptional(lookupProvider, tankTag)); + stacks.set(index, FluidStack.parseOptional(lookupProvider, tankTag.getCompound(TANK_CONTENTS))); } } diff --git a/src/machines/java/com/enderio/machines/common/io/fluid/TankAccess.java b/src/machines/java/com/enderio/machines/common/io/fluid/TankAccess.java index e2b6b19a1a..b455b5a682 100644 --- a/src/machines/java/com/enderio/machines/common/io/fluid/TankAccess.java +++ b/src/machines/java/com/enderio/machines/common/io/fluid/TankAccess.java @@ -64,6 +64,22 @@ public boolean isEmpty(MachineFluidHandler handler) { return getFluid(handler).isEmpty(); } + public boolean canInsert(FluidTankUser machine) { + return canInsert(machine.getFluidHandler()); + } + + public boolean canInsert(MachineFluidHandler handler) { + return handler.canInsert(index); + } + + public boolean canExtract(FluidTankUser machine) { + return canExtract(machine.getFluidHandler()); + } + + public boolean canExtract(MachineFluidHandler handler) { + return handler.canExtract(index); + } + public int fill(MachineFluidHandler handler, FluidStack stack, IFluidHandler.FluidAction action) { return handler.fill(index, stack, action); } diff --git a/src/machines/java/com/enderio/machines/common/lang/MachineLang.java b/src/machines/java/com/enderio/machines/common/lang/MachineLang.java index 09cdc59ee4..8ad510ec33 100644 --- a/src/machines/java/com/enderio/machines/common/lang/MachineLang.java +++ b/src/machines/java/com/enderio/machines/common/lang/MachineLang.java @@ -65,6 +65,8 @@ public class MachineLang { public static final Component STORE_1 = addTranslation("gui", EnderIO.loc("button.store_1_level"), "Store 1 level of XP"); public static final Component STORE_10 = addTranslation("gui", EnderIO.loc("button.store_10_level"), "Store 10 levels of XP"); public static final Component STORE_ALL = addTranslation("gui", EnderIO.loc("button.store_all_level"), "Store all levels of XP"); + public static final Component TRANSFER_TANK = addTranslation("gui", EnderIO.loc("button.transfer_tank"), "Transfer tank contents"); + public static final Component DUMP_TANK = addTranslation("gui", EnderIO.loc("button.dump_tank"), "Void tank contents"); // TODO: NEO-PORT: Common lang base class? private static MutableComponent addTranslation(String prefix, ResourceLocation id, String translation) { diff --git a/src/machines/java/com/enderio/machines/common/menu/VatMenu.java b/src/machines/java/com/enderio/machines/common/menu/VatMenu.java new file mode 100644 index 0000000000..accebe9383 --- /dev/null +++ b/src/machines/java/com/enderio/machines/common/menu/VatMenu.java @@ -0,0 +1,30 @@ +package com.enderio.machines.common.menu; + +import com.enderio.machines.common.blockentity.VatBlockEntity; +import com.enderio.machines.common.init.MachineMenus; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.level.block.entity.BlockEntity; +import org.apache.logging.log4j.LogManager; +import org.jetbrains.annotations.Nullable; + +public class VatMenu extends MachineMenu { + public VatMenu(@Nullable VatBlockEntity blockEntity, Inventory inventory, int pContainerId) { + super(blockEntity, inventory, MachineMenus.VAT.get(), pContainerId); + if (blockEntity != null) { + addSlot(new MachineSlot(blockEntity.getInventory(), VatBlockEntity.REAGENTS.get(0), 56, 12)); + addSlot(new MachineSlot(blockEntity.getInventory(), VatBlockEntity.REAGENTS.get(1), 105, 12)); + } + addInventorySlots(8, 84); + } + + public static VatMenu factory(int pContainerId, Inventory inventory, FriendlyByteBuf buf) { + BlockEntity entity = inventory.player.level().getBlockEntity(buf.readBlockPos()); + if (entity instanceof VatBlockEntity castBlockEntity) { + return new VatMenu(castBlockEntity, inventory, pContainerId); + } + + LogManager.getLogger().warn("couldn't find BlockEntity"); + return new VatMenu(null, inventory, pContainerId); + } +} diff --git a/src/machines/java/com/enderio/machines/common/network/MachinePayloadHandler.java b/src/machines/java/com/enderio/machines/common/network/MachinePayloadHandler.java index 87454a6e8c..c65d192b98 100644 --- a/src/machines/java/com/enderio/machines/common/network/MachinePayloadHandler.java +++ b/src/machines/java/com/enderio/machines/common/network/MachinePayloadHandler.java @@ -1,5 +1,6 @@ package com.enderio.machines.common.network; +import com.enderio.machines.common.blockentity.VatBlockEntity; import com.enderio.machines.common.menu.CrafterMenu; import com.enderio.machines.common.souldata.EngineSoul; import com.enderio.machines.common.souldata.SpawnerSoul; @@ -38,5 +39,21 @@ public void updateCrafterTemplate(UpdateCrafterTemplatePacket packet, IPayloadCo } }); } + + public void vatMoveTank(VatMoveTankPacket packet, IPayloadContext context) { + context.enqueueWork(() -> { + if (context.player().level().getBlockEntity(packet.pos()) instanceof VatBlockEntity vatBlockEntity) { + vatBlockEntity.moveFluidToOutputTank(); + } + }); + } + + public void vatDumpTank(VatDumpTankPacket packet, IPayloadContext context) { + context.enqueueWork(() -> { + if (context.player().level().getBlockEntity(packet.pos()) instanceof VatBlockEntity vatBlockEntity) { + vatBlockEntity.dumpOutputTank(); + } + }); + } } } diff --git a/src/machines/java/com/enderio/machines/common/network/VatDumpTankPacket.java b/src/machines/java/com/enderio/machines/common/network/VatDumpTankPacket.java new file mode 100644 index 0000000000..72808450a5 --- /dev/null +++ b/src/machines/java/com/enderio/machines/common/network/VatDumpTankPacket.java @@ -0,0 +1,19 @@ +package com.enderio.machines.common.network; + +import com.enderio.EnderIO; +import io.netty.buffer.ByteBuf; +import net.minecraft.core.BlockPos; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; + +public record VatDumpTankPacket(BlockPos pos) implements CustomPacketPayload { + public static final Type TYPE = new Type<>(EnderIO.loc("vat_dump_tank")); + + public static StreamCodec STREAM_CODEC = StreamCodec.composite(BlockPos.STREAM_CODEC, VatDumpTankPacket::pos, + VatDumpTankPacket::new); + + @Override + public Type type() { + return TYPE; + } +} diff --git a/src/machines/java/com/enderio/machines/common/network/VatMoveTankPacket.java b/src/machines/java/com/enderio/machines/common/network/VatMoveTankPacket.java new file mode 100644 index 0000000000..f45221c583 --- /dev/null +++ b/src/machines/java/com/enderio/machines/common/network/VatMoveTankPacket.java @@ -0,0 +1,19 @@ +package com.enderio.machines.common.network; + +import com.enderio.EnderIO; +import io.netty.buffer.ByteBuf; +import net.minecraft.core.BlockPos; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; + +public record VatMoveTankPacket(BlockPos pos) implements CustomPacketPayload { + public static final Type TYPE = new Type<>(EnderIO.loc("vat_move_tank")); + + public static StreamCodec STREAM_CODEC = StreamCodec.composite(BlockPos.STREAM_CODEC, VatMoveTankPacket::pos, + VatMoveTankPacket::new); + + @Override + public Type type() { + return TYPE; + } +} diff --git a/src/machines/java/com/enderio/machines/common/recipe/FermentingRecipe.java b/src/machines/java/com/enderio/machines/common/recipe/FermentingRecipe.java new file mode 100644 index 0000000000..823377d6ae --- /dev/null +++ b/src/machines/java/com/enderio/machines/common/recipe/FermentingRecipe.java @@ -0,0 +1,126 @@ +package com.enderio.machines.common.recipe; + +import com.enderio.core.common.recipes.OutputStack; +import com.enderio.machines.common.datamap.VatReagent; +import com.enderio.machines.common.init.MachineRecipes; +import com.enderio.machines.common.io.fluid.MachineFluidTank; +import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import io.netty.buffer.ByteBuf; +import net.minecraft.core.RegistryAccess; +import net.minecraft.core.registries.Registries; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.TagKey; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.RecipeInput; +import net.minecraft.world.item.crafting.RecipeSerializer; +import net.minecraft.world.item.crafting.RecipeType; +import net.minecraft.world.level.Level; +import net.neoforged.neoforge.fluids.FluidStack; +import net.neoforged.neoforge.fluids.crafting.SizedFluidIngredient; + +import java.util.List; + +public record FermentingRecipe(SizedFluidIngredient input, TagKey leftReagent, TagKey rightReagent, FluidStack output, int ticks) + implements MachineRecipe { + + @Override + public int getBaseEnergyCost() { + return 0; + } + + @Override + public List craft(Input input, RegistryAccess registryAccess) { + + double modifier = getModifier(input.getItem(0), leftReagent); + modifier *= getModifier(input.getItem(1), rightReagent); + + return List.of(OutputStack.of(new FluidStack(output.getFluid(), (int) (output.getAmount() * modifier)))); + } + + @Override + public List getResultStacks(RegistryAccess registryAccess) { + return List.of(OutputStack.of(output().copy())); + } + + @Override + public boolean matches(Input input, Level level) { + FluidStack inputTank = input.getInputTank().getFluid(); + if (!this.input.test(inputTank) || inputTank.getAmount() < this.input.amount()) { + return false; + } + + return input.getItem(0).is(leftReagent) && input.getItem(1).is(rightReagent); + } + + public static double getModifier(ItemStack stack, TagKey reagent) { + var map = stack.getItemHolder().getData(VatReagent.DATA_MAP); + if (map != null) { + return map.getOrDefault(reagent, 1D); + } + return 1; + } + + @Override + public RecipeSerializer getSerializer() { + return MachineRecipes.VAT_FERMENTING.serializer().get(); + } + + @Override + public RecipeType getType() { + return MachineRecipes.VAT_FERMENTING.type().get(); + } + + public record Input(ItemStack leftReagent, ItemStack rightStack, MachineFluidTank inputTank) implements RecipeInput { + + @Override + public ItemStack getItem(int slotIndex) { + return switch (slotIndex) { + case 0 -> leftReagent; + case 1 -> rightStack; + default -> throw new IllegalArgumentException("No item for index " + slotIndex); + }; + } + + @Override + public int size() { + return 2; + } + + public MachineFluidTank getInputTank() { + return inputTank; + } + + } + + public static class Serializer implements RecipeSerializer { + private static final StreamCodec> ITEM_TAG_STREAM_CODEC = ResourceLocation.STREAM_CODEC.map( + loc -> TagKey.create(Registries.ITEM, loc), TagKey::location); + + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec( + instance -> instance.group(SizedFluidIngredient.FLAT_CODEC.fieldOf("input").forGetter(FermentingRecipe::input), + TagKey.codec(Registries.ITEM).fieldOf("left_reagent").forGetter(FermentingRecipe::leftReagent), + TagKey.codec(Registries.ITEM).fieldOf("right_reagent").forGetter(FermentingRecipe::rightReagent), + FluidStack.CODEC.fieldOf("output").forGetter(FermentingRecipe::output), Codec.INT.fieldOf("ticks").forGetter(FermentingRecipe::ticks)) + .apply(instance, FermentingRecipe::new)); + + public static final StreamCodec STREAM_CODEC = StreamCodec.composite(SizedFluidIngredient.STREAM_CODEC, + FermentingRecipe::input, ITEM_TAG_STREAM_CODEC, FermentingRecipe::leftReagent, ITEM_TAG_STREAM_CODEC, FermentingRecipe::rightReagent, + FluidStack.STREAM_CODEC, FermentingRecipe::output, ByteBufCodecs.INT, FermentingRecipe::ticks, FermentingRecipe::new); + + @Override + public MapCodec codec() { + return CODEC; + } + + @Override + public StreamCodec streamCodec() { + return STREAM_CODEC; + } + } +} diff --git a/src/machines/java/com/enderio/machines/common/recipe/RecipeCaches.java b/src/machines/java/com/enderio/machines/common/recipe/RecipeCaches.java index 148b6d8adc..c78b501dd6 100644 --- a/src/machines/java/com/enderio/machines/common/recipe/RecipeCaches.java +++ b/src/machines/java/com/enderio/machines/common/recipe/RecipeCaches.java @@ -2,7 +2,6 @@ import com.enderio.machines.common.init.MachineRecipes; import com.enderio.machines.common.utility.RecipeInputCache; -import net.minecraft.world.Container; import net.minecraft.world.item.crafting.RecipeType; import net.minecraft.world.item.crafting.SingleRecipeInput; import net.minecraft.world.item.crafting.SmeltingRecipe; @@ -10,7 +9,6 @@ import net.neoforged.fml.common.EventBusSubscriber; import net.neoforged.neoforge.client.event.RecipesUpdatedEvent; import net.neoforged.neoforge.event.AddReloadListenerEvent; -import net.neoforged.neoforge.items.wrapper.RecipeWrapper; @EventBusSubscriber @@ -30,6 +28,9 @@ public class RecipeCaches { public static final RecipeInputCache SOUL_BINDING = new RecipeInputCache<>(MachineRecipes.SOUL_BINDING.type()); + public static final RecipeInputCache FERMENTING = new RecipeInputCache<>( + MachineRecipes.VAT_FERMENTING.type()); + @SubscribeEvent public static void registerReloadListener(AddReloadListenerEvent event) { ALLOY_SMELTING.markCacheDirty(); @@ -37,6 +38,7 @@ public static void registerReloadListener(AddReloadListenerEvent event) { PAINTING.markCacheDirty(); SAG_MILLING.markCacheDirty(); SOUL_BINDING.markCacheDirty(); + FERMENTING.markCacheDirty(); } @SubscribeEvent @@ -46,5 +48,6 @@ public static void onRecipesUpdated(RecipesUpdatedEvent event) { PAINTING.rebuildCache(event.getRecipeManager()); SAG_MILLING.rebuildCache(event.getRecipeManager()); SOUL_BINDING.rebuildCache(event.getRecipeManager()); + FERMENTING.rebuildCache(event.getRecipeManager()); } } diff --git a/src/machines/java/com/enderio/machines/data/reagentdata/ReagentDataProvider.java b/src/machines/java/com/enderio/machines/data/reagentdata/ReagentDataProvider.java new file mode 100644 index 0000000000..3b2b18a3d4 --- /dev/null +++ b/src/machines/java/com/enderio/machines/data/reagentdata/ReagentDataProvider.java @@ -0,0 +1,98 @@ +package com.enderio.machines.data.reagentdata; + +import com.enderio.EnderIO; +import com.enderio.machines.common.datamap.VatReagent; +import net.minecraft.core.HolderLookup; +import net.minecraft.core.registries.Registries; +import net.minecraft.data.CachedOutput; +import net.minecraft.data.DataProvider; +import net.minecraft.data.PackOutput; +import net.minecraft.data.tags.IntrinsicHolderTagsProvider; +import net.minecraft.tags.TagKey; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.Items; +import net.neoforged.neoforge.common.Tags; +import net.neoforged.neoforge.common.data.DataMapProvider; +import net.neoforged.neoforge.common.data.ExistingFileHelper; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; + +public class ReagentDataProvider implements DataProvider { + + private final TagsProvider tagsProvider; + private final DataProvider dataProvider; + + public ReagentDataProvider(PackOutput packOutput, CompletableFuture lookupProvider, ExistingFileHelper existingFileHelper) { + tagsProvider = new TagsProvider(packOutput, lookupProvider, existingFileHelper); + dataProvider = new DataProvider(packOutput, lookupProvider); + } + + protected void gather() { + addReagent(Items.WHEAT, Tags.Items.CROPS, 3D); + addReagent(Items.WHEAT, Tags.Items.SEEDS, 2D); + } + + @Override + public CompletableFuture run(CachedOutput pOutput) { + gather(); + List> list = new ArrayList<>(); + list.add(tagsProvider.run(pOutput)); + list.add(dataProvider.run(pOutput)); + return CompletableFuture.allOf(list.toArray(CompletableFuture[]::new)); + } + + public void addReagent(Item item, TagKey tag, double value) { + tagsProvider.addItemTag(tag, item); + dataProvider.addData(tag, item, value); + } + + @Override + public String getName() { + return "Fermenting Reagent Datamaps"; + } + + private static class TagsProvider extends IntrinsicHolderTagsProvider { + private final Map, List> tagsMap = new HashMap<>(); + + protected TagsProvider(PackOutput packOutput, CompletableFuture provider, @Nullable ExistingFileHelper existingFileHelper) { + super(packOutput, Registries.ITEM, provider, item -> item.builtInRegistryHolder().key(), EnderIO.MODID, existingFileHelper); + } + + public void addItemTag(TagKey tag, Item item) { + tagsMap.computeIfAbsent(tag, it -> new ArrayList<>()).add(item); + } + + @Override + protected void addTags(HolderLookup.Provider pProvider) { + tagsMap.forEach((key, value) -> { + var tag = this.tag(key); + value.forEach(tag::add); + }); + } + } + + private static class DataProvider extends DataMapProvider { + private final Map, Double>> data = new HashMap<>(); + + protected DataProvider(PackOutput packOutput, CompletableFuture lookupProvider) { + super(packOutput, lookupProvider); + } + + public void addData(TagKey tag, Item item, double value) { + data.computeIfAbsent(item, it -> new HashMap<>()).put(tag, value); + } + + @Override + protected void gather() { + var builder = builder(VatReagent.DATA_MAP); + data.forEach((item, map) -> { + builder.add(item.builtInRegistryHolder(), map, false); + }); + } + } +} diff --git a/src/machines/java/com/enderio/machines/data/reagentdata/package-info.java b/src/machines/java/com/enderio/machines/data/reagentdata/package-info.java new file mode 100644 index 0000000000..e22d36810c --- /dev/null +++ b/src/machines/java/com/enderio/machines/data/reagentdata/package-info.java @@ -0,0 +1,4 @@ +@javax.annotation.ParametersAreNonnullByDefault +@net.minecraft.MethodsReturnNonnullByDefault + +package com.enderio.machines.data.reagentdata; diff --git a/src/machines/java/com/enderio/machines/data/recipes/FermentingRecipeProvider.java b/src/machines/java/com/enderio/machines/data/recipes/FermentingRecipeProvider.java new file mode 100644 index 0000000000..f0dddb5e11 --- /dev/null +++ b/src/machines/java/com/enderio/machines/data/recipes/FermentingRecipeProvider.java @@ -0,0 +1,37 @@ +package com.enderio.machines.data.recipes; + +import com.enderio.EnderIO; +import com.enderio.base.common.init.EIOFluids; +import com.enderio.machines.common.recipe.FermentingRecipe; +import net.minecraft.core.HolderLookup; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.data.PackOutput; +import net.minecraft.data.recipes.RecipeOutput; +import net.minecraft.data.recipes.RecipeProvider; +import net.minecraft.tags.FluidTags; +import net.minecraft.tags.TagKey; +import net.minecraft.world.item.Item; +import net.neoforged.neoforge.common.Tags; +import net.neoforged.neoforge.fluids.FluidStack; +import net.neoforged.neoforge.fluids.crafting.SizedFluidIngredient; + +import java.util.concurrent.CompletableFuture; + +public class FermentingRecipeProvider extends RecipeProvider { + + public FermentingRecipeProvider(PackOutput packOutput, CompletableFuture registries) { + super(packOutput, registries); + } + + @Override + protected void buildRecipes(RecipeOutput recipeOutput) { + build(new FluidStack(EIOFluids.HOOTCH.getSource(), 250), SizedFluidIngredient.of(FluidTags.WATER, 1000), Tags.Items.SEEDS, Tags.Items.CROPS, 100, + recipeOutput); + } + + protected void build(FluidStack output, SizedFluidIngredient input, TagKey leftReagent, TagKey rightReagent, + int ticks, RecipeOutput recipeOutput) { + recipeOutput.accept(EnderIO.loc("fermenting/" + BuiltInRegistries.FLUID.getKey(output.getFluid()).getPath()), + new FermentingRecipe(input, leftReagent, rightReagent, output, ticks), null); + } +} diff --git a/src/machines/resources/assets/enderio/models/block/vat.json b/src/machines/resources/assets/enderio/models/block/vat.json new file mode 100644 index 0000000000..515ee6ce83 --- /dev/null +++ b/src/machines/resources/assets/enderio/models/block/vat.json @@ -0,0 +1,12 @@ +{ + "parent": "minecraft:block/cube", + "textures": { + "down": "enderio:block/machine_bottom", + "east": "enderio:block/machine_side", + "north": "enderio:block/vat_front", + "particle": "enderio:block/vat_front", + "south": "enderio:block/vat_back", + "up": "enderio:block/vat_top", + "west": "enderio:block/machine_side" + } +} diff --git a/src/machines/resources/assets/enderio/textures/block/vat_back.png b/src/machines/resources/assets/enderio/textures/block/vat_back.png new file mode 100644 index 0000000000..a2a07ca868 Binary files /dev/null and b/src/machines/resources/assets/enderio/textures/block/vat_back.png differ diff --git a/src/machines/resources/assets/enderio/textures/block/vat_front.png b/src/machines/resources/assets/enderio/textures/block/vat_front.png new file mode 100644 index 0000000000..c186057f6a Binary files /dev/null and b/src/machines/resources/assets/enderio/textures/block/vat_front.png differ diff --git a/src/machines/resources/assets/enderio/textures/block/vat_top.png b/src/machines/resources/assets/enderio/textures/block/vat_top.png new file mode 100644 index 0000000000..a1c2fec919 Binary files /dev/null and b/src/machines/resources/assets/enderio/textures/block/vat_top.png differ diff --git a/src/machines/resources/assets/enderio/textures/gui/vat.png b/src/machines/resources/assets/enderio/textures/gui/vat.png index b860d8c4b0..459d4a4db2 100644 Binary files a/src/machines/resources/assets/enderio/textures/gui/vat.png and b/src/machines/resources/assets/enderio/textures/gui/vat.png differ diff --git a/src/main/resources/assets/enderio/textures/gui/sprites/buttons/move_fluid.png b/src/main/resources/assets/enderio/textures/gui/sprites/buttons/move_fluid.png new file mode 100644 index 0000000000..e6847e790b Binary files /dev/null and b/src/main/resources/assets/enderio/textures/gui/sprites/buttons/move_fluid.png differ diff --git a/src/main/resources/assets/enderio/textures/gui/sprites/buttons/void_fluid.png b/src/main/resources/assets/enderio/textures/gui/sprites/buttons/void_fluid.png new file mode 100644 index 0000000000..c7dfc6557e Binary files /dev/null and b/src/main/resources/assets/enderio/textures/gui/sprites/buttons/void_fluid.png differ diff --git a/src/main/resources/assets/enderio/textures/gui/sprites/vat_cover.png b/src/main/resources/assets/enderio/textures/gui/sprites/vat_cover.png new file mode 100644 index 0000000000..e3dc441923 Binary files /dev/null and b/src/main/resources/assets/enderio/textures/gui/sprites/vat_cover.png differ