diff --git a/src/core/java/com/enderio/core/common/fluid/package-info.java b/src/core/java/com/enderio/core/common/fluid/package-info.java deleted file mode 100644 index 1dce7f0eb0..0000000000 --- a/src/core/java/com/enderio/core/common/fluid/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -@javax.annotation.ParametersAreNonnullByDefault -@net.minecraft.MethodsReturnNonnullByDefault - -package com.enderio.core.common.fluid; diff --git a/src/core/java/com/enderio/core/common/fluid/FluidIngredient.java b/src/core/java/com/enderio/core/common/recipes/FluidIngredient.java similarity index 63% rename from src/core/java/com/enderio/core/common/fluid/FluidIngredient.java rename to src/core/java/com/enderio/core/common/recipes/FluidIngredient.java index 49a9ee6e4b..26e60c72f0 100644 --- a/src/core/java/com/enderio/core/common/fluid/FluidIngredient.java +++ b/src/core/java/com/enderio/core/common/recipes/FluidIngredient.java @@ -1,12 +1,14 @@ -package com.enderio.core.common.fluid; +package com.enderio.core.common.recipes; import com.google.common.collect.Lists; import com.mojang.datafixers.util.Either; import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; import com.mojang.serialization.codecs.RecordCodecBuilder; import net.minecraft.core.Holder; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.Registries; +import net.minecraft.network.FriendlyByteBuf; import net.minecraft.tags.TagKey; import net.minecraft.util.ExtraCodecs; import net.minecraft.world.level.material.Fluid; @@ -16,12 +18,30 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.Predicate; import java.util.stream.Stream; public class FluidIngredient implements Predicate { public static final FluidIngredient EMPTY = new FluidIngredient(Stream.empty()); + private static final Codec CODEC_LIST = Codec + .list(Value.CODEC) + .comapFlatMap(list -> list.isEmpty() ? + DataResult.error(() -> "Fluid array cannot be empty, at least one fluid must be defined") : + DataResult.success(list.toArray(new Value[0])), List::of); + + public static final Codec CODEC = ExtraCodecs + .either(CODEC_LIST, Value.CODEC) + .flatComapMap(either -> either.map(FluidIngredient::new, value -> new FluidIngredient(new Value[] { value })), fluidIngredient -> { + if (fluidIngredient.values.length == 1) { + return DataResult.success(Either.right(fluidIngredient.values[0])); + } else { + return fluidIngredient.values.length == 0 ? + DataResult.error(() -> "Fluid array cannot be empty, at least one fluid must be defined") : + DataResult.success(Either.left(fluidIngredient.values)); + } + }); private final Value[] values; @Nullable private Fluid[] fluids; @@ -85,14 +105,24 @@ public static FluidIngredient of(TagKey tag) { return fromValues(Stream.of(new TagValue(tag))); } + public final void toNetwork(FriendlyByteBuf pBuffer) { + BiConsumer writer = (buf, fluid) -> buf.writeId(BuiltInRegistries.FLUID, fluid); + pBuffer.writeCollection(Arrays.asList(this.getFluids()), writer::accept); + } + + public static FluidIngredient fromNetwork(FriendlyByteBuf buf) { + var size = buf.readVarInt(); + return new FluidIngredient(Stream.generate(() -> new FluidValue(buf.readById(BuiltInRegistries.FLUID))).limit(size)); + } + public record FluidValue(Fluid fluid, BiFunction comparator) implements Value { public FluidValue(Fluid fluid) { this(fluid, FluidValue::areFluidsEqual); } - static final Codec CODEC = RecordCodecBuilder.create(p_311727_ -> p_311727_ - .group(BuiltInRegistries.FLUID.byNameCodec().fieldOf("fluid").forGetter(FluidValue::fluid)) - .apply(p_311727_, FluidValue::new)); + static final Codec CODEC = RecordCodecBuilder.create(instance -> instance + .group(BuiltInRegistries.FLUID.byNameCodec().fieldOf("fluid_name").forGetter(FluidValue::fluid)) + .apply(instance, FluidValue::new)); @Override public boolean equals(Object other) { @@ -102,6 +132,11 @@ public boolean equals(Object other) { return false; } + @Override + public Codec getCodec() { + return CODEC; + } + @Override public Collection getFluids() { return Collections.singleton(this.fluid); @@ -113,14 +148,20 @@ private static boolean areFluidsEqual(Fluid left, Fluid right) { } public record TagValue(TagKey tag) implements Value { + static final Codec CODEC = RecordCodecBuilder.create( - p_301118_ -> p_301118_.group(TagKey.codec(Registries.FLUID).fieldOf("tag").forGetter(p_301154_ -> p_301154_.tag)).apply(p_301118_, TagValue::new)); + instance -> instance.group(TagKey.codec(Registries.FLUID).fieldOf("fluid_tag").forGetter(TagValue::tag)).apply(instance, TagValue::new)); @Override public boolean equals(Object other) { return other instanceof TagValue otherTag && otherTag.tag.location().equals(this.tag.location()); } + @Override + public Codec getCodec() { + return CODEC; + } + @Override public Collection getFluids() { List list = Lists.newArrayList(); @@ -133,19 +174,19 @@ public Collection getFluids() { } } - protected interface Value { + protected sealed interface Value { Codec CODEC = ExtraCodecs - .xor(FluidValue.CODEC, TagValue.CODEC) - .xmap(p_300956_ -> p_300956_.map(p_300932_ -> p_300932_, p_301313_ -> p_301313_), p_301304_ -> { - if (p_301304_ instanceof TagValue fluidTag) { - return Either.right(fluidTag); - } else if (p_301304_ instanceof FluidValue fluidValue) { + .xor(FluidValue.CODEC, TagValue.CODEC).xmap(either -> either.map(fluidValue -> fluidValue, tagValue -> tagValue), value -> { + if (value instanceof TagValue tagValue) { + return Either.right(tagValue); + } else if (value instanceof FluidValue fluidValue) { return Either.left(fluidValue); } else { throw new UnsupportedOperationException("This is neither an fluid value nor a tag value."); } }); + Codec getCodec(); Collection getFluids(); } } 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 1e3ed37a2c..ff448326bf 100644 --- a/src/machines/java/com/enderio/machines/common/init/MachineRecipes.java +++ b/src/machines/java/com/enderio/machines/common/init/MachineRecipes.java @@ -9,12 +9,12 @@ import com.enderio.machines.common.recipe.SlicingRecipe; import com.enderio.machines.common.recipe.SoulBindingRecipe; import com.enderio.machines.common.recipe.TankRecipe; +import com.enderio.machines.common.recipe.VatFermentingRecipe; import net.minecraft.core.registries.Registries; import net.minecraft.world.item.crafting.Recipe; import net.minecraft.world.item.crafting.RecipeSerializer; import net.minecraft.world.item.crafting.RecipeType; import net.neoforged.bus.api.IEventBus; -import net.neoforged.fml.javafmlmod.FMLJavaModLoadingContext; import net.neoforged.neoforge.registries.DeferredHolder; import net.neoforged.neoforge.registries.DeferredRegister; @@ -32,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", + VatFermentingRecipe.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/recipe/VatFermentingRecipe.java b/src/machines/java/com/enderio/machines/common/recipe/VatFermentingRecipe.java new file mode 100644 index 0000000000..caca1ff72c --- /dev/null +++ b/src/machines/java/com/enderio/machines/common/recipe/VatFermentingRecipe.java @@ -0,0 +1,192 @@ +package com.enderio.machines.common.recipe; + +import com.enderio.core.common.recipes.FluidIngredient; +import com.enderio.core.common.recipes.OutputStack; +import com.enderio.machines.common.init.MachineRecipes; +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.minecraft.core.RegistryAccess; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.core.registries.Registries; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.tags.TagKey; +import net.minecraft.world.item.Item; +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.neoforged.neoforge.fluids.FluidStack; +import net.neoforged.neoforge.fluids.capability.templates.FluidTank; +import net.neoforged.neoforge.items.IItemHandlerModifiable; +import net.neoforged.neoforge.items.wrapper.RecipeWrapper; + +import java.util.List; + +public class VatFermentingRecipe implements MachineRecipe { + + private final FluidIngredient inputFluid; + private final int inputFluidAmount; + private final TagKey leftReagent; + private final TagKey rightReagent; + private final int outputModifier; + private final Fluid outputFluid; + private final int ticks; + + public VatFermentingRecipe(FluidIngredient inputFluid, int inputFluidAmount, TagKey leftReagent, TagKey rightReagent, Fluid outputFluid, + int outputModifier, int ticks) { + this.inputFluid = inputFluid; + this.inputFluidAmount = inputFluidAmount; + this.leftReagent = leftReagent; + this.rightReagent = rightReagent; + this.outputModifier = outputModifier; + this.outputFluid = outputFluid; + this.ticks = ticks; + } + + @Override + public int getBaseEnergyCost() { + return 0; + } + + @Override + public List craft(Container container, RegistryAccess registryAccess) { + //Todo: get reagent modifiers + return List.of(OutputStack.of(new FluidStack(outputFluid, inputFluidAmount * outputModifier))); + } + + @Override + public List getResultStacks(RegistryAccess registryAccess) { + return List.of(OutputStack.EMPTY); + } + + @Override + public boolean matches(Container container, Level level) { + FluidStack inputTank = container.getInputTank().getFluid(); + if (!inputFluid.test(inputTank.getFluid()) || !(inputTank.getAmount() < inputFluidAmount)) { + return false; + } + if (!container.getItem(0).is(leftReagent)) { + return false; + } + if (!container.getItem(1).is(rightReagent)) { + return false; + } + + return true; + } + + public FluidIngredient getInputFluid() { + return inputFluid; + } + + public int getInputFluidAmount() { + return inputFluidAmount; + } + + public TagKey getLeftReagent() { + return leftReagent; + } + + public TagKey getRightReagent() { + return rightReagent; + } + + public int getOutputModifier() { + return outputModifier; + } + + public Fluid getOutputFluid() { + return outputFluid; + } + + public int getTicks() { + return ticks; + } + + @Override + public RecipeSerializer getSerializer() { + return MachineRecipes.VAT_FERMENTING.serializer().get(); + } + + @Override + public RecipeType getType() { + return MachineRecipes.VAT_FERMENTING.type().get(); + } + + public static class Container extends RecipeWrapper { + + private final FluidTank inputTank; + + private final FluidTank outputTank; + + public Container(IItemHandlerModifiable inv, FluidTank inputTank, FluidTank outputTank) { + super(inv); + this.inputTank = inputTank; + this.outputTank = outputTank; + } + + public FluidTank getInputTank() { + return inputTank; + } + + public FluidTank getOutputTank() { + return outputTank; + } + + } + + public static class Serializer implements RecipeSerializer { + + Codec CODEC = RecordCodecBuilder.create(instance -> instance + .group(FluidIngredient.CODEC.fieldOf("inputFluid").forGetter(VatFermentingRecipe::getInputFluid), + Codec.INT.fieldOf("inputFluidAmount").forGetter(VatFermentingRecipe::getInputFluidAmount), + TagKey.codec(Registries.ITEM).fieldOf("leftReagent").forGetter(VatFermentingRecipe::getLeftReagent), + TagKey.codec(Registries.ITEM).fieldOf("rightReagent").forGetter(VatFermentingRecipe::getRightReagent), + BuiltInRegistries.FLUID.byNameCodec().fieldOf("FluidName").forGetter(VatFermentingRecipe::getOutputFluid), + Codec.INT.fieldOf("outputModifier").forGetter(VatFermentingRecipe::getOutputModifier), + Codec.INT.fieldOf("ticks").forGetter(VatFermentingRecipe::getTicks)) + .apply(instance, VatFermentingRecipe::new)); + + @Override + public Codec codec() { + return CODEC; + } + + @Override + public VatFermentingRecipe fromNetwork(FriendlyByteBuf buffer) { + //TODO : NETWORK + // try { + // FluidStack inputFluid = FluidStack.readFromPacket(buffer); + // FluidStack outputFluid = FluidStack.readFromPacket(buffer); + // int baseModifier = buffer.readInt(); + // ResourceLocation leftReagent = buffer.readResourceLocation(); + // ResourceLocation rightReagent = buffer.readResourceLocation(); + // int ticks = buffer.readInt(); + // return new VatFermentingRecipe(inputFluid, outputFluid, baseModifier, leftReagent, rightReagent, ticks); + // } catch (Exception ex) { + // EnderIO.LOGGER.error("Error reading Vat recipe for packet.", ex); + // throw ex; + // } + return null; + } + + @Override + public void toNetwork(FriendlyByteBuf buffer, VatFermentingRecipe recipe) { + //TODO : NETWORK + // try { + // recipe.inputFluid.toNetwork(buffer); + // buffer.writeInt(recipe.inputFluidAmount); + // buffer.; + // buffer.ta(recipe.leftReagent); + // buffer.writeResourceLocation(recipe.rightReagent); + // buffer.writeId(BuiltInRegistries.FLUID, recipe.outputFluid); + // buffer.writeInt(recipe.outputModifier); + // buffer.writeInt(recipe.ticks); + // } catch (Exception ex) { + // EnderIO.LOGGER.error("Error reading Vat recipe for packet.", ex); + // throw ex; + // } + + } + } +}