diff --git a/common/src/main/java/dev/architectury/fluid/FluidStack.java b/common/src/main/java/dev/architectury/fluid/FluidStack.java index b3b4fa4b..b522c32c 100644 --- a/common/src/main/java/dev/architectury/fluid/FluidStack.java +++ b/common/src/main/java/dev/architectury/fluid/FluidStack.java @@ -21,6 +21,9 @@ package dev.architectury.fluid; import dev.architectury.hooks.fluid.FluidStackHooks; import dev.architectury.utils.NbtType; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.Tag; import net.minecraft.network.FriendlyByteBuf; @@ -199,4 +202,26 @@ public final class FluidStack { public CompoundTag write(CompoundTag tag) { return FluidStackHooks.write(this, tag); } + + @Environment(EnvType.CLIENT) + @Nullable + public TextureAtlasSprite getStillTexture() { + return FluidStackHooks.getStillTexture(this); + } + + @Environment(EnvType.CLIENT) + @Nullable + public TextureAtlasSprite getFlowingTexture() { + return FluidStackHooks.getFlowingTexture(this); + } + + @Environment(EnvType.CLIENT) + public int getColor() { + return FluidStackHooks.getColor(this); + } + + @Environment(EnvType.CLIENT) + public boolean shouldRenderFromTop() { + return FluidStackHooks.shouldRenderFromTop(this); + } } diff --git a/common/src/main/java/dev/architectury/hooks/fluid/FluidStackHooks.java b/common/src/main/java/dev/architectury/hooks/fluid/FluidStackHooks.java index 0cf4c911..a13e2764 100644 --- a/common/src/main/java/dev/architectury/hooks/fluid/FluidStackHooks.java +++ b/common/src/main/java/dev/architectury/hooks/fluid/FluidStackHooks.java @@ -31,6 +31,7 @@ import net.minecraft.network.chat.Component; import net.minecraft.world.level.BlockAndTintGetter; import net.minecraft.world.level.material.Fluid; import net.minecraft.world.level.material.FluidState; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public class FluidStackHooks { @@ -143,9 +144,27 @@ public class FluidStackHooks { throw new AssertionError(); } + @ExpectPlatform + @Environment(EnvType.CLIENT) + public static int getColor(@NotNull FluidStack stack, @Nullable BlockAndTintGetter level, @Nullable BlockPos pos) { + throw new AssertionError(); + } + @ExpectPlatform @Environment(EnvType.CLIENT) public static int getColor(Fluid fluid) { throw new AssertionError(); } + + @ExpectPlatform + @Environment(EnvType.CLIENT) + public static boolean shouldRenderFromTop(FluidStack stack) { + throw new AssertionError(); + } + + @ExpectPlatform + @Environment(EnvType.CLIENT) + public static boolean shouldRenderFromTop(Fluid fluid) { + throw new AssertionError(); + } } diff --git a/common/src/main/java/dev/architectury/transfer/EmptyTransferHandler.java b/common/src/main/java/dev/architectury/transfer/EmptyTransferHandler.java new file mode 100644 index 00000000..65927146 --- /dev/null +++ b/common/src/main/java/dev/architectury/transfer/EmptyTransferHandler.java @@ -0,0 +1,41 @@ +/* + * This file is part of architectury. + * Copyright (C) 2020, 2021 architectury + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package dev.architectury.transfer; + +import java.util.Collections; + +enum EmptyTransferHandler implements TransferHandler { + INSTANCE; + + @Override + public Iterable> getResources(TransferContext context) { + return Collections.emptyList(); + } + + @Override + public long insert(Object toInsert, TransferAction action, TransferContext context) { + return 0; + } + + @Override + public long extract(Object toExtract, TransferAction action, TransferContext context) { + return 0; + } +} diff --git a/common/src/main/java/dev/architectury/transfer/ResourceView.java b/common/src/main/java/dev/architectury/transfer/ResourceView.java new file mode 100644 index 00000000..c666fb78 --- /dev/null +++ b/common/src/main/java/dev/architectury/transfer/ResourceView.java @@ -0,0 +1,31 @@ +/* + * This file is part of architectury. + * Copyright (C) 2020, 2021 architectury + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package dev.architectury.transfer; + +/** + * Represents an immutable view of a resource. + * + * @param the type of resource + */ +public interface ResourceView { + T getResource(); + + long getCapacity(); +} diff --git a/common/src/main/java/dev/architectury/transfer/TransferAction.java b/common/src/main/java/dev/architectury/transfer/TransferAction.java new file mode 100644 index 00000000..50762013 --- /dev/null +++ b/common/src/main/java/dev/architectury/transfer/TransferAction.java @@ -0,0 +1,26 @@ +/* + * This file is part of architectury. + * Copyright (C) 2020, 2021 architectury + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package dev.architectury.transfer; + +public enum TransferAction { + SIMULATE, + COMMIT, + ; +} diff --git a/common/src/main/java/dev/architectury/transfer/TransferContext.java b/common/src/main/java/dev/architectury/transfer/TransferContext.java new file mode 100644 index 00000000..f4e7827b --- /dev/null +++ b/common/src/main/java/dev/architectury/transfer/TransferContext.java @@ -0,0 +1,53 @@ +/* + * This file is part of architectury. + * Copyright (C) 2020, 2021 architectury + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package dev.architectury.transfer; + +import dev.architectury.injectables.annotations.ExpectPlatform; +import dev.architectury.injectables.annotations.PlatformOnly; +import org.jetbrains.annotations.Nullable; + +/** + * Transfer context is used to defer the state of the transaction. + *

+ * On Fabric, each thread can only have one transaction at a time, + * you can create a new context with {@link #create()}, this will instantiate + * a Transaction on Fabric. + *

+ * If you wish to create a context with a transaction, you can use + * {@link #create(Object)} with the transaction object, this method + * is only available on Fabric. + *

+ * This class must be closed with {@link #close()}, you can use try-and-resources + * block to ensure that the context is closed. + */ +public interface TransferContext extends AutoCloseable { + @ExpectPlatform + static TransferContext create() { + throw new AssertionError(); + } + + @PlatformOnly(PlatformOnly.FABRIC) + @ExpectPlatform + static TransferContext create(@Nullable Object transaction) { + throw new AssertionError(); + } + + int nestingDepth(); +} diff --git a/common/src/main/java/dev/architectury/transfer/TransferHandler.java b/common/src/main/java/dev/architectury/transfer/TransferHandler.java new file mode 100644 index 00000000..9cff017d --- /dev/null +++ b/common/src/main/java/dev/architectury/transfer/TransferHandler.java @@ -0,0 +1,72 @@ +/* + * This file is part of architectury. + * Copyright (C) 2020, 2021 architectury + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package dev.architectury.transfer; + +import org.jetbrains.annotations.ApiStatus; + +/** + * A handler for transferring resources. + * This is wrapped around apis given by the platform, + *

+ * DO NOT extend this interface, binary compatibility is not guaranteed + * with future versions if you do. + * + * @param the type of resource + */ +@ApiStatus.NonExtendable +public interface TransferHandler { + /** + * Returns an empty transfer handler, which does nothing. + * + * @param the type of resource + * @return an empty transfer handler + */ + static TransferHandler empty() { + return (TransferHandler) EmptyTransferHandler.INSTANCE; + } + + /** + * Returns the iterable of immutable resources that are currently in the handler. + * + * @param context the context of the transfer + * @return the iterable of resources that are currently in the handler + */ + Iterable> getResources(TransferContext context); + + /** + * Inserts the given resource into the handler, returning the amount that was inserted. + * + * @param toInsert the resource to insert + * @param action whether to simulate or actually insert the resource + * @param context the context of the transfer + * @return the amount that was inserted + */ + long insert(T toInsert, TransferAction action, TransferContext context); + + /** + * Extracts the given resource from the handler, returning the amount that was extracted. + * + * @param toExtract the resource to extract + * @param action whether to simulate or actually extract the resource + * @param context the context of the transfer + * @return the amount that was extracted + */ + long extract(T toExtract, TransferAction action, TransferContext context); +} diff --git a/common/src/main/java/dev/architectury/transfer/fluid/FluidTransfer.java b/common/src/main/java/dev/architectury/transfer/fluid/FluidTransfer.java new file mode 100644 index 00000000..c3675628 --- /dev/null +++ b/common/src/main/java/dev/architectury/transfer/fluid/FluidTransfer.java @@ -0,0 +1,61 @@ +/* + * This file is part of architectury. + * Copyright (C) 2020, 2021 architectury + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package dev.architectury.transfer.fluid; + +import dev.architectury.fluid.FluidStack; +import dev.architectury.injectables.annotations.ExpectPlatform; +import dev.architectury.transfer.TransferHandler; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import org.jetbrains.annotations.Nullable; + +public class FluidTransfer { + private FluidTransfer() { + } + + @ExpectPlatform + @Nullable + public static TransferHandler get(Level level, BlockPos pos, Direction direction) { + throw new AssertionError(); + } + + @ExpectPlatform + @Nullable + public static TransferHandler get(Level level, BlockPos pos, @Nullable BlockEntity blockEntity, Direction direction) { + throw new AssertionError(); + } + + /** + * Wraps a platform-specific fluid transfer handler into the architectury transfer handler. + * This accepts {@code IFluidHandler} on Forge. + * This accepts {@code Storage} on Fabric. + * + * @param object the handler to wrap + * @return the wrapped handler, or {@code null} if {@code object} is null + * @throws IllegalArgumentException if {@code object} is not a supported handler + */ + @ExpectPlatform + @Nullable + public static TransferHandler wrap(@Nullable Object object) { + throw new AssertionError(); + } +} diff --git a/fabric/src/main/java/dev/architectury/hooks/fluid/fabric/FluidStackHooksFabric.java b/fabric/src/main/java/dev/architectury/hooks/fluid/fabric/FluidStackHooksFabric.java new file mode 100644 index 00000000..5dc48fa6 --- /dev/null +++ b/fabric/src/main/java/dev/architectury/hooks/fluid/fabric/FluidStackHooksFabric.java @@ -0,0 +1,36 @@ +/* + * This file is part of architectury. + * Copyright (C) 2020, 2021 architectury + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package dev.architectury.hooks.fluid.fabric; + +import dev.architectury.fluid.FluidStack; +import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant; + +public final class FluidStackHooksFabric { + private FluidStackHooksFabric() { + } + + public static FluidStack fromFabric(FluidVariant variant, long amount) { + return FluidStack.create(variant.getFluid(), amount, variant.getNbt()); + } + + public static FluidVariant toFabric(FluidStack stack) { + return FluidVariant.of(stack.getFluid(), stack.getTag()); + } +} diff --git a/fabric/src/main/java/dev/architectury/hooks/fluid/fabric/FluidStackHooksImpl.java b/fabric/src/main/java/dev/architectury/hooks/fluid/fabric/FluidStackHooksImpl.java index 26b5a05d..6089431b 100644 --- a/fabric/src/main/java/dev/architectury/hooks/fluid/fabric/FluidStackHooksImpl.java +++ b/fabric/src/main/java/dev/architectury/hooks/fluid/fabric/FluidStackHooksImpl.java @@ -25,6 +25,8 @@ import dev.architectury.utils.Env; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRenderHandlerRegistry; +import net.fabricmc.fabric.api.transfer.v1.client.fluid.FluidVariantRendering; +import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.core.BlockPos; import net.minecraft.core.Registry; @@ -122,9 +124,7 @@ public class FluidStackHooksImpl { @Nullable public static TextureAtlasSprite getStillTexture(@NotNull FluidStack stack) { if (stack.getFluid() == Fluids.EMPTY) return null; - var handler = FluidRenderHandlerRegistry.INSTANCE.get(stack.getFluid()); - if (handler == null) return null; - var sprites = handler.getFluidSprites(null, null, stack.getFluid().defaultFluidState()); + var sprites = FluidVariantRendering.getSprites(FluidStackHooksFabric.toFabric(stack)); if (sprites == null) return null; return sprites[0]; } @@ -133,9 +133,7 @@ public class FluidStackHooksImpl { @Nullable public static TextureAtlasSprite getStillTexture(@NotNull Fluid fluid) { if (fluid == Fluids.EMPTY) return null; - var handler = FluidRenderHandlerRegistry.INSTANCE.get(fluid); - if (handler == null) return null; - var sprites = handler.getFluidSprites(null, null, fluid.defaultFluidState()); + var sprites = FluidVariantRendering.getSprites(FluidVariant.of(fluid)); if (sprites == null) return null; return sprites[0]; } @@ -155,9 +153,7 @@ public class FluidStackHooksImpl { @Nullable public static TextureAtlasSprite getFlowingTexture(@NotNull FluidStack stack) { if (stack.getFluid() == Fluids.EMPTY) return null; - var handler = FluidRenderHandlerRegistry.INSTANCE.get(stack.getFluid()); - if (handler == null) return null; - var sprites = handler.getFluidSprites(null, null, stack.getFluid().defaultFluidState()); + var sprites = FluidVariantRendering.getSprites(FluidStackHooksFabric.toFabric(stack)); if (sprites == null) return null; return sprites[1]; } @@ -166,9 +162,7 @@ public class FluidStackHooksImpl { @Nullable public static TextureAtlasSprite getFlowingTexture(@NotNull Fluid fluid) { if (fluid == Fluids.EMPTY) return null; - var handler = FluidRenderHandlerRegistry.INSTANCE.get(fluid); - if (handler == null) return null; - var sprites = handler.getFluidSprites(null, null, fluid.defaultFluidState()); + var sprites = FluidVariantRendering.getSprites(FluidVariant.of(fluid)); if (sprites == null) return null; return sprites[1]; } @@ -184,16 +178,30 @@ public class FluidStackHooksImpl { @Environment(EnvType.CLIENT) public static int getColor(@NotNull FluidStack stack) { if (stack.getFluid() == Fluids.EMPTY) return -1; - var handler = FluidRenderHandlerRegistry.INSTANCE.get(stack.getFluid()); - if (handler == null) return -1; - return handler.getFluidColor(null, null, stack.getFluid().defaultFluidState()); + return FluidVariantRendering.getColor(FluidStackHooksFabric.toFabric(stack)); + } + + @Environment(EnvType.CLIENT) + public static int getColor(@NotNull FluidStack stack, @Nullable BlockAndTintGetter level, @Nullable BlockPos pos) { + if (stack.getFluid() == Fluids.EMPTY) return -1; + return FluidVariantRendering.getColor(FluidStackHooksFabric.toFabric(stack), level, pos); } @Environment(EnvType.CLIENT) public static int getColor(@NotNull Fluid fluid) { if (fluid == Fluids.EMPTY) return -1; - var handler = FluidRenderHandlerRegistry.INSTANCE.get(fluid); - if (handler == null) return -1; - return handler.getFluidColor(null, null, fluid.defaultFluidState()); + return FluidVariantRendering.getColor(FluidVariant.of(fluid)); + } + + @Environment(EnvType.CLIENT) + public static boolean shouldRenderFromTop(FluidStack stack) { + if (stack.getFluid() == Fluids.EMPTY) return false; + return FluidVariantRendering.fillsFromTop(FluidStackHooksFabric.toFabric(stack)); + } + + @Environment(EnvType.CLIENT) + public static boolean shouldRenderFromTop(Fluid fluid) { + if (fluid == Fluids.EMPTY) return false; + return FluidVariantRendering.fillsFromTop(FluidVariant.of(fluid)); } } diff --git a/fabric/src/main/java/dev/architectury/transfer/fabric/TransferContextImpl.java b/fabric/src/main/java/dev/architectury/transfer/fabric/TransferContextImpl.java new file mode 100644 index 00000000..e90939bb --- /dev/null +++ b/fabric/src/main/java/dev/architectury/transfer/fabric/TransferContextImpl.java @@ -0,0 +1,56 @@ +/* + * This file is part of architectury. + * Copyright (C) 2020, 2021 architectury + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package dev.architectury.transfer.fabric; + +import dev.architectury.transfer.TransferContext; +import net.fabricmc.fabric.api.transfer.v1.transaction.Transaction; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; + +public class TransferContextImpl implements TransferContext { + @ApiStatus.Internal + public final Transaction transaction; + + private TransferContextImpl(Transaction transaction) { + this.transaction = transaction; + } + + public static TransferContext create() { + return new TransferContextImpl(Transaction.openOuter()); + } + + public static TransferContext create(@Nullable Object transaction) { + if (transaction != null && !(transaction instanceof Transaction)) { + throw new IllegalArgumentException("transaction must be a Transaction"); + } + + return new TransferContextImpl(transaction == null ? Transaction.openOuter() : (Transaction) transaction); + } + + @Override + public int nestingDepth() { + return transaction.nestingDepth(); + } + + @Override + public void close() throws Exception { + this.transaction.close(); + } +} diff --git a/fabric/src/main/java/dev/architectury/transfer/fluid/fabric/FluidTransferImpl.java b/fabric/src/main/java/dev/architectury/transfer/fluid/fabric/FluidTransferImpl.java new file mode 100644 index 00000000..0ef7e30a --- /dev/null +++ b/fabric/src/main/java/dev/architectury/transfer/fluid/fabric/FluidTransferImpl.java @@ -0,0 +1,130 @@ +/* + * This file is part of architectury. + * Copyright (C) 2020, 2021 architectury + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package dev.architectury.transfer.fluid.fabric; + +import com.google.common.collect.Iterables; +import dev.architectury.fluid.FluidStack; +import dev.architectury.hooks.fluid.fabric.FluidStackHooksFabric; +import dev.architectury.transfer.ResourceView; +import dev.architectury.transfer.TransferAction; +import dev.architectury.transfer.TransferContext; +import dev.architectury.transfer.TransferHandler; +import dev.architectury.transfer.fabric.TransferContextImpl; +import net.fabricmc.fabric.api.transfer.v1.fluid.FluidStorage; +import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant; +import net.fabricmc.fabric.api.transfer.v1.storage.Storage; +import net.fabricmc.fabric.api.transfer.v1.storage.StorageView; +import net.fabricmc.fabric.api.transfer.v1.transaction.Transaction; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import org.jetbrains.annotations.Nullable; + +public class FluidTransferImpl { + @Nullable + public static TransferHandler get(Level level, BlockPos pos, Direction direction) { + return wrap(FluidStorage.SIDED.find(level, pos, direction)); + } + + @Nullable + public static TransferHandler get(Level level, BlockPos pos, @Nullable BlockEntity blockEntity, Direction direction) { + if (blockEntity != null) { + return wrap(FluidStorage.SIDED.find(level, pos, blockEntity.getBlockState(), blockEntity, direction)); + } else { + return get(level, pos, direction); + } + } + + @Nullable + public static TransferHandler wrap(@Nullable Object object) { + if (object == null) return null; + + if (object instanceof Storage) { + return new FabricTransferHandler((Storage) object); + } else { + throw new IllegalArgumentException("Unsupported object type: " + object.getClass().getName()); + } + } + + private static class FabricTransferHandler implements TransferHandler { + private final Storage storage; + + private FabricTransferHandler(Storage storage) { + this.storage = storage; + } + + @Override + public Iterable> getResources(TransferContext context) { + return Iterables.transform(storage.iterable(((TransferContextImpl) context).transaction), + FabricResourceView::new); + } + + @Override + public long insert(FluidStack toInsert, TransferAction action, TransferContext context) { + Transaction transaction = ((TransferContextImpl) context).transaction; + long inserted; + + try (Transaction nested = Transaction.openNested(transaction)) { + inserted = this.storage.insert(FluidStackHooksFabric.toFabric(toInsert), toInsert.getAmount(), nested); + + if (action == TransferAction.COMMIT) { + nested.commit(); + } + } + + return inserted; + } + + @Override + public long extract(FluidStack toExtract, TransferAction action, TransferContext context) { + Transaction transaction = ((TransferContextImpl) context).transaction; + long extracted; + + try (Transaction nested = Transaction.openNested(transaction)) { + extracted = this.storage.extract(FluidStackHooksFabric.toFabric(toExtract), toExtract.getAmount(), nested); + + if (action == TransferAction.COMMIT) { + nested.commit(); + } + } + + return extracted; + } + + private static class FabricResourceView implements ResourceView { + private final StorageView view; + + private FabricResourceView(StorageView view) { + this.view = view; + } + + @Override + public FluidStack getResource() { + return FluidStackHooksFabric.fromFabric(view.getResource(), view.getAmount()); + } + + @Override + public long getCapacity() { + return view.getCapacity(); + } + } + } +} diff --git a/forge/src/main/java/dev/architectury/hooks/fluid/forge/FluidStackHooksImpl.java b/forge/src/main/java/dev/architectury/hooks/fluid/forge/FluidStackHooksImpl.java index 8ce0863f..1ab57477 100644 --- a/forge/src/main/java/dev/architectury/hooks/fluid/forge/FluidStackHooksImpl.java +++ b/forge/src/main/java/dev/architectury/hooks/fluid/forge/FluidStackHooksImpl.java @@ -117,7 +117,11 @@ public class FluidStackHooksImpl { @OnlyIn(Dist.CLIENT) public static int getColor(@Nullable BlockAndTintGetter level, @Nullable BlockPos pos, @NotNull FluidState state) { if (state.getType() == Fluids.EMPTY) return -1; - return state.getType().getAttributes().getColor(level, pos); + if (level != null && pos != null) { + return state.getType().getAttributes().getColor(level, pos); + } else { + return getColor(state.getType()); + } } @OnlyIn(Dist.CLIENT) @@ -126,9 +130,29 @@ public class FluidStackHooksImpl { return stack.getFluid().getAttributes().getColor(FluidStackHooksForge.toForge(stack)); } + @OnlyIn(Dist.CLIENT) + public static int getColor(@NotNull FluidStack stack, @Nullable BlockAndTintGetter level, @Nullable BlockPos pos) { + if (stack.getFluid() == Fluids.EMPTY) return -1; + if (level != null && pos != null) { + return stack.getFluid().getAttributes().getColor(level, pos); + } else { + return stack.getFluid().getAttributes().getColor(FluidStackHooksForge.toForge(stack)); + } + } + @OnlyIn(Dist.CLIENT) public static int getColor(@NotNull Fluid fluid) { if (fluid == Fluids.EMPTY) return -1; return fluid.getAttributes().getColor(); } + + @OnlyIn(Dist.CLIENT) + public static boolean shouldRenderFromTop(FluidStack stack) { + return stack.getFluid().getAttributes().isGaseous(); + } + + @OnlyIn(Dist.CLIENT) + public static boolean shouldRenderFromTop(Fluid fluid) { + return fluid.getAttributes().isGaseous(); + } } diff --git a/forge/src/main/java/dev/architectury/transfer/fluid/forge/FluidTransferImpl.java b/forge/src/main/java/dev/architectury/transfer/fluid/forge/FluidTransferImpl.java new file mode 100644 index 00000000..8bce40f5 --- /dev/null +++ b/forge/src/main/java/dev/architectury/transfer/fluid/forge/FluidTransferImpl.java @@ -0,0 +1,164 @@ +/* + * This file is part of architectury. + * Copyright (C) 2020, 2021 architectury + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package dev.architectury.transfer.fluid.forge; + +import dev.architectury.fluid.FluidStack; +import dev.architectury.hooks.fluid.forge.FluidStackHooksForge; +import dev.architectury.transfer.ResourceView; +import dev.architectury.transfer.TransferAction; +import dev.architectury.transfer.TransferContext; +import dev.architectury.transfer.TransferHandler; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.BucketPickup; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.fluids.IFluidBlock; +import net.minecraftforge.fluids.capability.CapabilityFluidHandler; +import net.minecraftforge.fluids.capability.IFluidHandler; +import net.minecraftforge.fluids.capability.wrappers.BucketPickupHandlerWrapper; +import net.minecraftforge.fluids.capability.wrappers.FluidBlockWrapper; +import org.jetbrains.annotations.Nullable; + +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.Objects; +import java.util.function.Consumer; + +public class FluidTransferImpl { + @Nullable + public static TransferHandler get(Level level, BlockPos pos, Direction direction) { + return get(level, pos, null, direction); + } + + @Nullable + public static TransferHandler get(Level level, BlockPos pos, @Nullable BlockEntity blockEntity, Direction direction) { + BlockState state = level.getBlockState(pos); + Block block = state.getBlock(); + IFluidHandler handler = null; + if (block instanceof IFluidBlock) { + handler = new FluidBlockWrapper((IFluidBlock) block, level, pos); + } else if (block instanceof BucketPickup) { + handler = new BucketPickupHandlerWrapper((BucketPickup) block, level, pos); + } else if (state.hasBlockEntity()) { + if (blockEntity == null) { + blockEntity = level.getBlockEntity(pos); + } + if (blockEntity != null) { + handler = blockEntity.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, direction).resolve().orElse(null); + } + } + return wrap(handler); + } + + @Nullable + public static TransferHandler get(ItemStack stack) { + return wrap(stack.getCapability(CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY).resolve().orElse(null)); + } + + @Nullable + public static TransferHandler wrap(@Nullable Object object) { + if (object == null) return null; + + if (object instanceof IFluidHandler) { + return new ForgeTransferHandler((IFluidHandler) object); + } else { + throw new IllegalArgumentException("Unsupported object type: " + object.getClass().getName()); + } + } + + private static class ForgeTransferHandler implements TransferHandler { + private IFluidHandler handler; + + private ForgeTransferHandler(IFluidHandler handler) { + this.handler = handler; + } + + @Override + public Iterable> getResources(TransferContext context) { + return Itr::new; + } + + @Override + public long insert(FluidStack toInsert, TransferAction action, TransferContext context) { + return handler.fill(FluidStackHooksForge.toForge(toInsert), action == TransferAction.SIMULATE ? IFluidHandler.FluidAction.SIMULATE : IFluidHandler.FluidAction.EXECUTE); + } + + @Override + public long extract(FluidStack toExtract, TransferAction action, TransferContext context) { + return handler.drain(FluidStackHooksForge.toForge(toExtract), action == TransferAction.SIMULATE ? IFluidHandler.FluidAction.SIMULATE : IFluidHandler.FluidAction.EXECUTE).getAmount(); + } + + private class Itr implements Iterator> { + int cursor; + + Itr() { + } + + @Override + public boolean hasNext() { + return cursor != handler.getTanks(); + } + + @Override + public ResourceView next() { + int i = cursor; + if (i >= handler.getTanks()) + throw new NoSuchElementException(); + cursor = i + 1; + return new ForgeResourceView(i); + } + + @Override + public void forEachRemaining(Consumer> action) { + Objects.requireNonNull(action); + final int size = handler.getTanks(); + int i = cursor; + if (i < size) { + for (; i < size; i++) { + action.accept(new ForgeResourceView(i)); + } + cursor = i; + } + } + } + + private class ForgeResourceView implements ResourceView { + int index; + + public ForgeResourceView(int index) { + this.index = index; + } + + @Override + public FluidStack getResource() { + return FluidStackHooksForge.fromForge(handler.getFluidInTank(index)); + } + + @Override + public long getCapacity() { + return handler.getTankCapacity(index); + } + } + } +} diff --git a/forge/src/main/java/dev/architectury/transfer/forge/TransferContextImpl.java b/forge/src/main/java/dev/architectury/transfer/forge/TransferContextImpl.java new file mode 100644 index 00000000..6b796e7b --- /dev/null +++ b/forge/src/main/java/dev/architectury/transfer/forge/TransferContextImpl.java @@ -0,0 +1,40 @@ +/* + * This file is part of architectury. + * Copyright (C) 2020, 2021 architectury + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package dev.architectury.transfer.forge; + +import dev.architectury.transfer.TransferContext; + +public enum TransferContextImpl implements TransferContext { + INSTANCE; + + public static TransferContext create() { + return TransferContextImpl.INSTANCE; + } + + @Override + public int nestingDepth() { + return 0; + } + + @Override + public void close() throws Exception { + + } +}