diff --git a/build.gradle b/build.gradle index 8e04c17..cc8cb03 100644 --- a/build.gradle +++ b/build.gradle @@ -25,6 +25,11 @@ dependencies { modImplementation libs.quilt.loader + // Mixin Extras Importation + include libs.mixin.extras + implementation libs.mixin.extras + annotationProcessor libs.mixin.extras + // QSL is not a complete API; You will need Quilted Fabric API to fill in the gaps. // Quilted Fabric API will automatically pull in the correct QSL version. modImplementation libs.quilted.fabric.api diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e4cfe9e..94ee502 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,6 +3,7 @@ minecraft = "1.19.2" quilt_mappings = "1.19.2+build.22" quilt_loader = "0.17.6" +mixin_extras = "0.2.0-beta.11" quilted_fabric_api = "4.0.0-beta.18+0.64.0-1.19.2" modmenu = "4.0.6" @@ -11,6 +12,7 @@ modmenu = "4.0.6" minecraft = { module = "com.mojang:minecraft", version.ref = "minecraft" } quilt_mappings = { module = "org.quiltmc:quilt-mappings", version.ref = "quilt_mappings" } quilt_loader = { module = "org.quiltmc:quilt-loader", version.ref = "quilt_loader" } +mixin_extras = { module = "io.github.llamalad7:mixinextras-fabric", version.ref = "mixin_extras" } quilted_fabric_api = { module = "org.quiltmc.quilted-fabric-api:quilted-fabric-api", version.ref = "quilted_fabric_api" } modmenu = { module = "com.terraformersmc:modmenu", version.ref = "modmenu" } diff --git a/src/main/java/com/mmodding/mmodding_lib/ducks/FlowableFluidDuckInterface.java b/src/main/java/com/mmodding/mmodding_lib/ducks/FlowableFluidDuckInterface.java new file mode 100644 index 0000000..6d9820c --- /dev/null +++ b/src/main/java/com/mmodding/mmodding_lib/ducks/FlowableFluidDuckInterface.java @@ -0,0 +1,20 @@ +package com.mmodding.mmodding_lib.ducks; + +import net.minecraft.fluid.FluidState; + +import java.util.function.IntFunction; + +public interface FlowableFluidDuckInterface { + + void mmodding_lib$putCustomStates(FluidState stillState, IntFunction flowingStates); + + void mmodding_lib$removeCustomStates(); + + boolean mmodding_lib$hasStillState(); + + FluidState mmodding_lib$getStillState(); + + boolean mmodding_lib$hasFlowingStates(); + + IntFunction mmodding_lib$getFlowingStates(); +} diff --git a/src/main/java/com/mmodding/mmodding_lib/library/blocks/CustomFluidBlock.java b/src/main/java/com/mmodding/mmodding_lib/library/blocks/CustomFluidBlock.java index a513471..3ac6ed4 100644 --- a/src/main/java/com/mmodding/mmodding_lib/library/blocks/CustomFluidBlock.java +++ b/src/main/java/com/mmodding/mmodding_lib/library/blocks/CustomFluidBlock.java @@ -1,15 +1,27 @@ package com.mmodding.mmodding_lib.library.blocks; +import com.mmodding.mmodding_lib.ducks.FlowableFluidDuckInterface; import net.minecraft.block.FluidBlock; import net.minecraft.fluid.FlowableFluid; +import net.minecraft.fluid.FluidState; import net.minecraft.item.BlockItem; +import org.jetbrains.annotations.Nullable; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.IntFunction; +import java.util.function.Supplier; public class CustomFluidBlock extends FluidBlock implements BlockRegistrable, BlockWithItem { private final AtomicBoolean registered = new AtomicBoolean(false); + public CustomFluidBlock(FlowableFluid fluid, Settings settings, @Nullable FluidState stillState, @Nullable IntFunction flowingStates) { + this(((Supplier) () -> { + ((FlowableFluidDuckInterface) fluid).mmodding_lib$putCustomStates(stillState, flowingStates); + return fluid; + }).get(), settings); + } + public CustomFluidBlock(FlowableFluid fluid, Settings settings) { super(fluid, settings); } diff --git a/src/main/java/com/mmodding/mmodding_lib/library/fluids/FluidGroup.java b/src/main/java/com/mmodding/mmodding_lib/library/fluids/FluidGroup.java index 3c24bd4..f8f9ce2 100644 --- a/src/main/java/com/mmodding/mmodding_lib/library/fluids/FluidGroup.java +++ b/src/main/java/com/mmodding/mmodding_lib/library/fluids/FluidGroup.java @@ -5,31 +5,34 @@ import com.mmodding.mmodding_lib.library.items.settings.AdvancedItemSettings; import com.mmodding.mmodding_lib.library.utils.IdentifierUtils; import net.minecraft.block.AbstractBlock; +import net.minecraft.fluid.FlowableFluid; import net.minecraft.item.BucketItem; import net.minecraft.item.Item; import net.minecraft.item.Items; import net.minecraft.util.Identifier; +import net.minecraft.util.registry.Registry; import org.jetbrains.annotations.Nullable; public class FluidGroup { - private final Identifier identifier; private final CustomFluid still; private final CustomFluid flowing; private final CustomFluidBlock block; private final CustomBucketItem bucket; - public FluidGroup(Identifier identifier, CustomFluid still, CustomFluid flowable, AbstractBlock.Settings settings) { - this(identifier, still, flowable, settings, new AdvancedItemSettings().recipeRemainder(Items.BUCKET).maxCount(1)); + public FluidGroup(CustomFluid still, CustomFluid flowable, AbstractBlock.Settings settings) { + this(still, flowable, settings, new AdvancedItemSettings().recipeRemainder(Items.BUCKET).maxCount(1)); } - public FluidGroup(Identifier identifier, CustomFluid still, CustomFluid flowing, AbstractBlock.Settings blockSettings, Item.Settings itemSettings) { - this.identifier = identifier; + public FluidGroup(CustomFluid still, CustomFluid flowing, AbstractBlock.Settings blockSettings, Item.Settings itemSettings) { this.still = still; - this.still.register(this.identifier); this.flowing = flowing; - this.flowing.register(IdentifierUtils.extend("flowing", this.identifier)); - this.block = new CustomFluidBlock(this.still, blockSettings); + this.block = new CustomFluidBlock( + this.still, + blockSettings, + this.still.getDefaultState().with(FlowableFluid.FALLING, Boolean.FALSE), + value -> this.flowing.getDefaultState().with(FlowableFluid.LEVEL, value == 8 ? 8 : 8 - value).with(FlowableFluid.FALLING, Boolean.TRUE) + ); this.bucket = new CustomBucketItem(this.still, itemSettings); } @@ -50,8 +53,10 @@ public BucketItem getBucket() { return this.bucket; } - public void register() { - this.block.register(this.identifier); + public void register(Identifier identifier) { + this.still.register(identifier); + this.flowing.register(IdentifierUtils.extend("flowing", identifier)); + this.block.register(identifier); if (this.bucket != null) { this.bucket.register(IdentifierUtils.extend(identifier, "bucket")); } diff --git a/src/main/java/com/mmodding/mmodding_lib/mixin/injectors/FlowableFluidMixin.java b/src/main/java/com/mmodding/mmodding_lib/mixin/injectors/FlowableFluidMixin.java new file mode 100644 index 0000000..0cc7d4e --- /dev/null +++ b/src/main/java/com/mmodding/mmodding_lib/mixin/injectors/FlowableFluidMixin.java @@ -0,0 +1,51 @@ +package com.mmodding.mmodding_lib.mixin.injectors; + +import com.mmodding.mmodding_lib.ducks.FlowableFluidDuckInterface; +import net.minecraft.fluid.FlowableFluid; +import net.minecraft.fluid.FluidState; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; + +import java.util.function.IntFunction; + +@Mixin(FlowableFluid.class) +public class FlowableFluidMixin implements FlowableFluidDuckInterface { + + @Unique + private FluidState stillState = null; + + @Unique + private IntFunction flowingStates = null; + + @Override + public void mmodding_lib$putCustomStates(FluidState stillState, IntFunction flowingStates) { + this.stillState = stillState; + this.flowingStates = flowingStates; + } + + @Override + public void mmodding_lib$removeCustomStates() { + this.stillState = null; + this.flowingStates = null; + } + + @Override + public boolean mmodding_lib$hasStillState() { + return this.stillState != null; + } + + @Override + public FluidState mmodding_lib$getStillState() { + return this.stillState; + } + + @Override + public boolean mmodding_lib$hasFlowingStates() { + return this.flowingStates != null; + } + + @Override + public IntFunction mmodding_lib$getFlowingStates() { + return this.flowingStates; + } +} diff --git a/src/main/java/com/mmodding/mmodding_lib/mixin/injectors/FluidBlockMixin.java b/src/main/java/com/mmodding/mmodding_lib/mixin/injectors/FluidBlockMixin.java index ea82041..9a4fab9 100644 --- a/src/main/java/com/mmodding/mmodding_lib/mixin/injectors/FluidBlockMixin.java +++ b/src/main/java/com/mmodding/mmodding_lib/mixin/injectors/FluidBlockMixin.java @@ -1,27 +1,78 @@ package com.mmodding.mmodding_lib.mixin.injectors; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.mmodding.mmodding_lib.ducks.FlowableFluidDuckInterface; import com.mmodding.mmodding_lib.library.fluids.FluidExtensions; import com.mmodding.mmodding_lib.library.fluids.collisions.FluidCollisionHandler; +import net.minecraft.block.AbstractBlock; import net.minecraft.block.BlockState; import net.minecraft.block.FluidBlock; import net.minecraft.fluid.FlowableFluid; +import net.minecraft.fluid.FluidState; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; import net.minecraft.world.World; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; @Mixin(FluidBlock.class) public class FluidBlockMixin { + @Unique + private final ThreadLocal stateIndex = ThreadLocal.withInitial(() -> 0); + @Shadow @Final protected FlowableFluid fluid; + @WrapOperation(method = "", at = @At(value = "INVOKE", target = "Lnet/minecraft/fluid/FlowableFluid;getStill(Z)Lnet/minecraft/fluid/FluidState;", ordinal = 0)) + private FluidState first(FlowableFluid fluid, boolean falling, Operation original) { + if (this.getDuckedFlowableFluid(fluid).mmodding_lib$hasStillState()) { + return this.getDuckedFlowableFluid(fluid).mmodding_lib$getStillState(); + } + else { + return original.call(fluid, falling); + } + } + + @Inject(method = "", at = @At(value = "INVOKE", target = "Ljava/util/List;add(Ljava/lang/Object;)Z", ordinal = 1), locals = LocalCapture.CAPTURE_FAILEXCEPTION) + private void hook(FlowableFluid fluid, AbstractBlock.Settings settings, CallbackInfo ci, int i) { + this.stateIndex.set(i); + } + + @WrapOperation(method = "", at = @At(value = "INVOKE", target = "Lnet/minecraft/fluid/FlowableFluid;getFlowing(IZ)Lnet/minecraft/fluid/FluidState;", ordinal = 0)) + private FluidState second(FlowableFluid fluid, int level, boolean falling, Operation original) { + if (this.getDuckedFlowableFluid(fluid).mmodding_lib$hasFlowingStates()) { + return this.getDuckedFlowableFluid(fluid).mmodding_lib$getFlowingStates().apply(this.stateIndex.get()); + } + else { + return original.call(fluid, level, falling); + } + } + + @WrapOperation(method = "", at = @At(value = "INVOKE", target = "Lnet/minecraft/fluid/FlowableFluid;getFlowing(IZ)Lnet/minecraft/fluid/FluidState;", ordinal = 1)) + private FluidState third(FlowableFluid fluid, int level, boolean falling, Operation original) { + if (this.getDuckedFlowableFluid(fluid).mmodding_lib$hasStillState()) { + return this.getDuckedFlowableFluid(fluid).mmodding_lib$getFlowingStates().apply(8); + } + else { + return original.call(fluid, level, falling); + } + } + + @Inject(method = "", at = @At("TAIL")) + private void last(FlowableFluid fluid, AbstractBlock.Settings settings, CallbackInfo ci) { + this.getDuckedFlowableFluid(fluid).mmodding_lib$removeCustomStates(); + } + @Inject(method = "receiveNeighborFluids", at = @At("HEAD"), cancellable = true) private void receiveNeighborFluids(World world, BlockPos pos, BlockState state, CallbackInfoReturnable cir) { if (this.fluid instanceof FluidExtensions extensions) { @@ -45,4 +96,9 @@ private void receiveNeighborFluids(World world, BlockPos pos, BlockState state, } } } + + @Unique + private FlowableFluidDuckInterface getDuckedFlowableFluid(FlowableFluid fluid) { + return (FlowableFluidDuckInterface) fluid; + } } diff --git a/src/main/resources/mmodding_lib.mixins.json b/src/main/resources/mmodding_lib.mixins.json index 391d1fe..305b3bc 100644 --- a/src/main/resources/mmodding_lib.mixins.json +++ b/src/main/resources/mmodding_lib.mixins.json @@ -40,6 +40,7 @@ "injectors.ExplosionMixin", "injectors.FallingBlockEntityMixin", "injectors.FishingBobberEntityMixin", + "injectors.FlowableFluidMixin", "injectors.FluidBlockMixin", "injectors.FluidStateMixin", "injectors.GeneratorOptionsMixin",