From fadc321034efeb03b9de40f7f91d4450475835a7 Mon Sep 17 00:00:00 2001 From: shedaniel Date: Mon, 6 Dec 2021 15:28:37 +0800 Subject: [PATCH] Implement most of it --- .../dev/architectury/fluid/FluidStack.java | 98 +++++++++----- .../access/BlockLookupAccessImpl.java | 121 +++++++++++++++++ .../transfer/access/ItemLookupAccessImpl.java | 70 ++++++++++ .../transfer/ApiLookupAccess.java | 48 +++++++ .../transfer/EmptyTransferHandler.java | 10 ++ .../architectury/transfer/ResourceView.java | 33 ++++- .../transfer/TransferHandler.java | 28 +--- .../architectury/transfer/TransferView.java | 74 +++++++++++ ...ckTransferAccess.java => BlockLookup.java} | 40 +++--- .../transfer/access/BlockLookupAccess.java | 35 +++++ .../access/BlockLookupRegistration.java | 55 ++++++++ ...temTransferAccess.java => ItemLookup.java} | 15 ++- .../transfer/access/ItemLookupAccess.java | 23 +--- .../ItemLookupRegistration.java} | 17 ++- .../transfer/fluid/FluidTransfer.java | 25 ++-- .../transfer/item/ItemTransfer.java | 10 +- .../fluid/fabric/FluidStackImpl.java | 113 ++++++++++++++++ .../fluid/fabric/FluidStackHooksFabric.java | 5 +- ...Access.java => BlockApiLookupWrapper.java} | 10 +- .../fabric/FabricBlockLookupRegistration.java | 96 ++++++++++++++ .../fabric/FabricStorageTransferHandler.java | 62 ++++++++- .../transfer/fabric/TransferContextImpl.java | 56 -------- .../fabric/TransferHandlerStorage.java | 121 +++++++++++++++++ .../fluid/fabric/FluidTransferImpl.java | 33 +++-- .../FabricContainerItemTransferHandler.java | 52 +++++++- .../item/fabric/ItemTransferImpl.java | 23 +++- .../fluid/forge/FluidStackImpl.java | 101 +++++++++++++++ .../fluid/forge/FluidStackHooksForge.java | 5 +- .../fluid/forge/FluidTransferImpl.java | 88 ++++++++++--- .../forge/ForgeBlockLookupRegistration.java | 122 ++++++++++++++++++ ....java => ForgeItemLookupRegistration.java} | 41 ++++-- .../transfer/item/forge/ItemTransferImpl.java | 64 ++++++--- 32 files changed, 1449 insertions(+), 245 deletions(-) create mode 100644 common/src/main/java/dev/architectury/impl/transfer/access/BlockLookupAccessImpl.java create mode 100644 common/src/main/java/dev/architectury/impl/transfer/access/ItemLookupAccessImpl.java create mode 100644 common/src/main/java/dev/architectury/transfer/ApiLookupAccess.java create mode 100644 common/src/main/java/dev/architectury/transfer/TransferView.java rename common/src/main/java/dev/architectury/transfer/access/{BlockTransferAccess.java => BlockLookup.java} (57%) create mode 100644 common/src/main/java/dev/architectury/transfer/access/BlockLookupAccess.java create mode 100644 common/src/main/java/dev/architectury/transfer/access/BlockLookupRegistration.java rename common/src/main/java/dev/architectury/transfer/access/{ItemTransferAccess.java => ItemLookup.java} (76%) rename forge/src/main/java/dev/architectury/transfer/forge/TransferContextImpl.java => common/src/main/java/dev/architectury/transfer/access/ItemLookupAccess.java (64%) rename common/src/main/java/dev/architectury/transfer/{TransferAccess.java => access/ItemLookupRegistration.java} (63%) create mode 100644 fabric/src/main/java/dev/architectury/fluid/fabric/FluidStackImpl.java rename fabric/src/main/java/dev/architectury/transfer/fabric/{FabricBlockTransferAccess.java => BlockApiLookupWrapper.java} (80%) create mode 100644 fabric/src/main/java/dev/architectury/transfer/fabric/FabricBlockLookupRegistration.java delete mode 100644 fabric/src/main/java/dev/architectury/transfer/fabric/TransferContextImpl.java create mode 100644 fabric/src/main/java/dev/architectury/transfer/fabric/TransferHandlerStorage.java create mode 100644 forge/src/main/java/dev/architectury/fluid/forge/FluidStackImpl.java create mode 100644 forge/src/main/java/dev/architectury/transfer/forge/ForgeBlockLookupRegistration.java rename forge/src/main/java/dev/architectury/transfer/forge/{ForgeBlockTransferAccess.java => ForgeItemLookupRegistration.java} (54%) diff --git a/common/src/main/java/dev/architectury/fluid/FluidStack.java b/common/src/main/java/dev/architectury/fluid/FluidStack.java index b64560c3..982eca91 100644 --- a/common/src/main/java/dev/architectury/fluid/FluidStack.java +++ b/common/src/main/java/dev/architectury/fluid/FluidStack.java @@ -20,6 +20,7 @@ package dev.architectury.fluid; import dev.architectury.hooks.fluid.FluidStackHooks; +import dev.architectury.injectables.annotations.ExpectPlatform; import dev.architectury.utils.NbtType; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; @@ -30,22 +31,56 @@ import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.chat.Component; import net.minecraft.world.level.material.Fluid; import net.minecraft.world.level.material.Fluids; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; -import java.util.Objects; +import java.util.function.Function; import java.util.function.Supplier; public final class FluidStack { private static final FluidStack EMPTY = create(Fluids.EMPTY, 0); - private long amount; - @Nullable - private CompoundTag tag; - private Supplier fluid; + private static final FluidStackAdapter ADAPTER = adapt(FluidStack::getValue, FluidStack::new); + + private Object value; private FluidStack(Supplier fluid, long amount, CompoundTag tag) { - this.fluid = Objects.requireNonNull(fluid); - this.amount = amount; - this.tag = tag == null ? null : tag.copy(); + this(ADAPTER.create(fluid, amount, tag)); + } + + private FluidStack(Object value) { + this.value = value; + } + + private Object getValue() { + return value; + } + + @ExpectPlatform + private static FluidStackAdapter adapt(Function toValue, Function fromValue) { + throw new AssertionError(); + } + + @ApiStatus.Internal + public interface FluidStackAdapter { + Object create(Supplier fluid, long amount, CompoundTag tag); + + void check(Object object); + + Supplier getRawFluidSupplier(Object object); + + Fluid getFluid(Object object); + + long getAmount(Object object); + + void setAmount(Object object, long amount); + + CompoundTag getTag(Object value); + + void setTag(Object value, CompoundTag tag); + + Object copy(Object value); + + int hashCode(Object value); } public static FluidStack empty() { @@ -82,61 +117,66 @@ public final class FluidStack { @Nullable public final Fluid getRawFluid() { - return fluid.get(); + return ADAPTER.getFluid(value); } public final Supplier getRawFluidSupplier() { - return fluid; + return ADAPTER.getRawFluidSupplier(value); } public boolean isEmpty() { - return getRawFluid() == Fluids.EMPTY || amount <= 0; + return getRawFluid() == Fluids.EMPTY || ADAPTER.getAmount(value) <= 0; } public long getAmount() { - return isEmpty() ? 0 : amount; + return isEmpty() ? 0 : ADAPTER.getAmount(value); } public void setAmount(long amount) { - this.amount = amount; + ADAPTER.setAmount(value, amount); } public void grow(long amount) { - setAmount(this.amount + amount); + setAmount(getAmount() + amount); } public void shrink(long amount) { - setAmount(this.amount - amount); + setAmount(getAmount() - amount); } public boolean hasTag() { - return tag != null; + return getTag() != null; } @Nullable public CompoundTag getTag() { - return tag; + return ADAPTER.getTag(value); } public void setTag(@Nullable CompoundTag tag) { - this.tag = tag; + ADAPTER.setTag(value, tag); } public CompoundTag getOrCreateTag() { - if (tag == null) - setTag(new CompoundTag()); + CompoundTag tag = getTag(); + if (tag == null) { + tag = new CompoundTag(); + setTag(tag); + return tag; + } return tag; } @Nullable public CompoundTag getChildTag(String childName) { + CompoundTag tag = getTag(); if (tag == null) return null; return tag.getCompound(childName); } public CompoundTag getOrCreateChildTag(String childName) { - getOrCreateTag(); + CompoundTag tag = getOrCreateTag(); var child = tag.getCompound(childName); if (!tag.contains(childName, Tag.TAG_COMPOUND)) { tag.put(childName, child); @@ -145,6 +185,7 @@ public final class FluidStack { } public void removeChildTag(String childName) { + CompoundTag tag = getTag(); if (tag != null) tag.remove(childName); } @@ -158,17 +199,12 @@ public final class FluidStack { } public FluidStack copy() { - return new FluidStack(fluid, amount, tag); + return new FluidStack(ADAPTER.copy(value)); } @Override public final int hashCode() { - var code = 1; - code = 31 * code + getFluid().hashCode(); - code = 31 * code + Long.hashCode(amount); - if (tag != null) - code = 31 * code + tag.hashCode(); - return code; + return ADAPTER.hashCode(value); } @Override @@ -188,7 +224,9 @@ public final class FluidStack { } private boolean isTagEqual(FluidStack other) { - return tag == null ? other.tag == null : other.tag != null && tag.equals(other.tag); + var tag = getTag(); + var otherTag = other.getTag(); + return tag == null ? otherTag == null : otherTag != null && tag.equals(otherTag); } public static FluidStack read(FriendlyByteBuf buf) { @@ -209,7 +247,7 @@ public final class FluidStack { public FluidStack copyWithAmount(long amount) { if (isEmpty()) return this; - return new FluidStack(fluid, amount, tag); + return new FluidStack(getRawFluidSupplier(), amount, getTag()); } @Environment(EnvType.CLIENT) diff --git a/common/src/main/java/dev/architectury/impl/transfer/access/BlockLookupAccessImpl.java b/common/src/main/java/dev/architectury/impl/transfer/access/BlockLookupAccessImpl.java new file mode 100644 index 00000000..f2b933f5 --- /dev/null +++ b/common/src/main/java/dev/architectury/impl/transfer/access/BlockLookupAccessImpl.java @@ -0,0 +1,121 @@ +/* + * 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.impl.transfer.access; + +import dev.architectury.transfer.access.BlockLookup; +import dev.architectury.transfer.access.BlockLookupAccess; +import dev.architectury.transfer.access.BlockLookupRegistration; +import net.minecraft.core.BlockPos; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; + +public class BlockLookupAccessImpl implements BlockLookupAccess { + private final List> lookups = new ArrayList<>(); + private final List> registrationHandlers = new ArrayList<>(); + + @Override + public void addQueryHandler(BlockLookup handler) { + this.lookups.add(0, handler); + } + + @Override + public void addRegistrationHandler(BlockLookupRegistration registration) { + this.registrationHandlers.add(0, registration); + } + + @Override + @Nullable + public T get(Level level, BlockPos pos, C context) { + for (BlockLookup handler : lookups) { + T result = handler.get(level, pos, context); + if (result != null) { + return result; + } + } + + return null; + } + + @Override + @Nullable + public T get(Level level, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, C context) { + for (BlockLookup handler : lookups) { + T result = handler.get(level, pos, state, blockEntity, context); + if (result != null) { + return result; + } + } + + return null; + } + + @Override + public boolean register(ResourceLocation id, BlockAccessProvider, @Nullable BlockEntity> provider) { + for (BlockLookupRegistration handler : registrationHandlers) { + if (handler.register(id, provider)) { + return true; + } + } + + return false; + } + + @Override + public boolean registerForBlocks(ResourceLocation id, BlockAccessProvider, @Nullable BlockEntity> provider, Block... blocks) { + for (BlockLookupRegistration handler : registrationHandlers) { + if (handler.registerForBlocks(id, provider, blocks)) { + return true; + } + } + + return false; + } + + @Override + public boolean registerForBlockEntities(ResourceLocation id, BlockAccessProvider, B> provider, BlockEntityType... blockEntityTypes) { + for (BlockLookupRegistration handler : registrationHandlers) { + if (handler.registerForBlockEntities(id, provider, blockEntityTypes)) { + return true; + } + } + + return false; + } + + @Override + public boolean registerForSelf(ResourceLocation id, BlockEntityType... blockEntityTypes) { + for (BlockLookupRegistration handler : registrationHandlers) { + if (handler.registerForSelf(id, blockEntityTypes)) { + return true; + } + } + + return false; + } +} diff --git a/common/src/main/java/dev/architectury/impl/transfer/access/ItemLookupAccessImpl.java b/common/src/main/java/dev/architectury/impl/transfer/access/ItemLookupAccessImpl.java new file mode 100644 index 00000000..7c53843c --- /dev/null +++ b/common/src/main/java/dev/architectury/impl/transfer/access/ItemLookupAccessImpl.java @@ -0,0 +1,70 @@ +/* + * 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.impl.transfer.access; + +import dev.architectury.transfer.access.ItemLookup; +import dev.architectury.transfer.access.ItemLookupAccess; +import dev.architectury.transfer.access.ItemLookupRegistration; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.ItemStack; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; + +public class ItemLookupAccessImpl implements ItemLookupAccess { + private final List> lookups = new ArrayList<>(); + private final List> registrationHandlers = new ArrayList<>(); + + @Override + public void addQueryHandler(ItemLookup handler) { + this.lookups.add(handler); + } + + @Override + public void addRegistrationHandler(ItemLookupRegistration registration) { + this.registrationHandlers.add(registration); + } + + @Override + @Nullable + public T get(ItemStack stack, C context) { + for (ItemLookup handler : lookups) { + T result = handler.get(stack, context); + if (result != null) { + return result; + } + } + + return null; + } + + @Override + public boolean register(ResourceLocation id, ItemAccessProvider> provider) { + for (ItemLookupRegistration handler : registrationHandlers) { + if (handler.register(id, provider)) { + return true; + } + } + + return false; + } +} diff --git a/common/src/main/java/dev/architectury/transfer/ApiLookupAccess.java b/common/src/main/java/dev/architectury/transfer/ApiLookupAccess.java new file mode 100644 index 00000000..096e9f72 --- /dev/null +++ b/common/src/main/java/dev/architectury/transfer/ApiLookupAccess.java @@ -0,0 +1,48 @@ +/* + * 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; + +/** + * The base interface for all lookup accesses. + * + * @param the type of the API + * @param the type of the query handler + * @param the type of the registration handler + */ +public interface ApiLookupAccess { + /** + * Adds a handler for querying the api, this will + * only be called by architectury mods. + *

+ * For adding interop with platform APIs, use the + * register methods for linking and attaching to fabric's + * api lookup or forge's capability system. + * + * @param handler the query handler to add + */ + void addQueryHandler(H handler); + + /** + * Adds a lookup registration. + * + * @param registration the registration handler to add + */ + void addRegistrationHandler(R registration); +} diff --git a/common/src/main/java/dev/architectury/transfer/EmptyTransferHandler.java b/common/src/main/java/dev/architectury/transfer/EmptyTransferHandler.java index 4216b3e1..3079e6ea 100644 --- a/common/src/main/java/dev/architectury/transfer/EmptyTransferHandler.java +++ b/common/src/main/java/dev/architectury/transfer/EmptyTransferHandler.java @@ -69,4 +69,14 @@ class EmptyTransferHandler implements TransferHandler { public T blank() { return blank.get(); } + + @Override + public Object saveState() { + throw new UnsupportedOperationException(); + } + + @Override + public void loadState(Object state) { + throw new UnsupportedOperationException(); + } } diff --git a/common/src/main/java/dev/architectury/transfer/ResourceView.java b/common/src/main/java/dev/architectury/transfer/ResourceView.java index c666fb78..a0a500dd 100644 --- a/common/src/main/java/dev/architectury/transfer/ResourceView.java +++ b/common/src/main/java/dev/architectury/transfer/ResourceView.java @@ -19,13 +19,44 @@ package dev.architectury.transfer; +import java.util.function.Predicate; + /** * Represents an immutable view of a resource. * * @param the type of resource */ -public interface ResourceView { +public interface ResourceView extends TransferView { + /** + * Returns the resource that this view represents. + * The returned resource is immutable. + * + * @return the resource + */ T getResource(); + /** + * Returns the capacity of this view. + * + * @return the capacity + */ long getCapacity(); + + /** + * Returns a copy of a resource with the given amount. + * + * @param resource the resource to copy + * @param amount the amount to copy + * @return the copy + */ + T copyWithAmount(T resource, long amount); + + @Override + default T extract(Predicate toExtract, long maxAmount, TransferAction action) { + if (toExtract.test(getResource())) { + return extract(copyWithAmount(getResource(), maxAmount), action); + } + + return blank(); + } } diff --git a/common/src/main/java/dev/architectury/transfer/TransferHandler.java b/common/src/main/java/dev/architectury/transfer/TransferHandler.java index bec01c03..29c87ea1 100644 --- a/common/src/main/java/dev/architectury/transfer/TransferHandler.java +++ b/common/src/main/java/dev/architectury/transfer/TransferHandler.java @@ -23,7 +23,6 @@ import dev.architectury.fluid.FluidStack; import net.minecraft.world.item.ItemStack; import org.jetbrains.annotations.ApiStatus; -import java.util.function.Predicate; import java.util.stream.Stream; /** @@ -36,7 +35,7 @@ import java.util.stream.Stream; * @param the type of resource */ @ApiStatus.NonExtendable -public interface TransferHandler { +public interface TransferHandler extends TransferView { /** * Returns an empty item transfer handler, which does nothing. * @@ -91,29 +90,4 @@ public interface TransferHandler { * @return the amount that was inserted */ long insert(T toInsert, TransferAction action); - - /** - * Extracts the given resource from the handler, returning the stack that was extracted. - * - * @param toExtract the resource to extract - * @param action whether to simulate or actually extract the resource - * @return the stack that was extracted - */ - T extract(T toExtract, TransferAction action); - - /** - * Extracts the given resource from the handler, returning the stack that was extracted. - * - * @param toExtract the predicates to use to filter the resources to extract - * @param action whether to simulate or actually extract the resource - * @return the stack that was extracted - */ - T extract(Predicate toExtract, long maxAmount, TransferAction action); - - /** - * Returns a blank resource. - * - * @return a blank resource - */ - T blank(); } diff --git a/common/src/main/java/dev/architectury/transfer/TransferView.java b/common/src/main/java/dev/architectury/transfer/TransferView.java new file mode 100644 index 00000000..e9203a3b --- /dev/null +++ b/common/src/main/java/dev/architectury/transfer/TransferView.java @@ -0,0 +1,74 @@ +/* + * 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; + +import java.util.function.Predicate; + +public interface TransferView { + /** + * Extracts the given resource from the handler, returning the stack that was extracted. + * + * @param toExtract the resource to extract + * @param action whether to simulate or actually extract the resource + * @return the stack that was extracted + */ + T extract(T toExtract, TransferAction action); + + /** + * Extracts the given resource from the handler, returning the stack that was extracted. + * + * @param toExtract the predicates to use to filter the resources to extract + * @param maxAmount the maximum amount of resources to extract + * @param action whether to simulate or actually extract the resource + * @return the stack that was extracted + */ + T extract(Predicate toExtract, long maxAmount, TransferAction action); + + /** + * Returns a blank resource. + * + * @return a blank resource + */ + T blank(); + + /** + * Returns the saved state of the handler, this method must not be called by the implementation. + * This method is used to provide support for transactions, which is only used if the handler is + * registered with the lookup. + * + * @return the saved state of the handler + * @throws UnsupportedOperationException if the handler is provided by the platform + */ + @ApiStatus.OverrideOnly + Object saveState(); + + /** + * Loads the saved state of the handler, this method must not be called by the implementation. + * This method is used to provide support for transactions, which is only used if the handler is + * registered with the lookup. + * + * @param state the saved state of the handler + * @throws UnsupportedOperationException if the handler is provided by the platform + */ + @ApiStatus.OverrideOnly + void loadState(Object state); +} diff --git a/common/src/main/java/dev/architectury/transfer/access/BlockTransferAccess.java b/common/src/main/java/dev/architectury/transfer/access/BlockLookup.java similarity index 57% rename from common/src/main/java/dev/architectury/transfer/access/BlockTransferAccess.java rename to common/src/main/java/dev/architectury/transfer/access/BlockLookup.java index 6f4007ad..3c75868b 100644 --- a/common/src/main/java/dev/architectury/transfer/access/BlockTransferAccess.java +++ b/common/src/main/java/dev/architectury/transfer/access/BlockLookup.java @@ -19,28 +19,36 @@ package dev.architectury.transfer.access; -import dev.architectury.transfer.TransferAccess; import net.minecraft.core.BlockPos; -import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import org.jetbrains.annotations.Nullable; -import java.util.function.Function; - -public interface BlockTransferAccess extends TransferAccess { +public interface BlockLookup { + /** + * Queries the api for the given block. + * If you need the block state or block entity, you must query it yourself, + * as this method will not do it for you. + * + * @param level the level + * @param pos the position of the block + * @param context the context + * @return the transfer handler, or null if none was found + */ @Nullable - T get(Level level, BlockPos pos, C context); + T get(Level level, BlockPos pos, Context context); + /** + * Queries the api for the given block. + * + * @param level the level + * @param pos the position of the block + * @param state the state of the block + * @param blockEntity the block entity, or null if none + * @param context the context + * @return the transfer handler, or null if none was found + */ @Nullable - T get(Level level, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, C context); - - void register(ResourceLocation id, BlockAccessProvider provider); - - @FunctionalInterface - interface BlockAccessProvider { - @Nullable - Function get(Level level, BlockPos pos, BlockState state, BlockEntity blockEntity); - } -} + T get(Level level, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, Context context); +} \ No newline at end of file diff --git a/common/src/main/java/dev/architectury/transfer/access/BlockLookupAccess.java b/common/src/main/java/dev/architectury/transfer/access/BlockLookupAccess.java new file mode 100644 index 00000000..72772fee --- /dev/null +++ b/common/src/main/java/dev/architectury/transfer/access/BlockLookupAccess.java @@ -0,0 +1,35 @@ +/* + * 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.access; + +import dev.architectury.impl.transfer.access.BlockLookupAccessImpl; +import dev.architectury.transfer.ApiLookupAccess; + +/** + * An API lookup for blocks. + * + * @param the type of the API + * @param the type of the context + */ +public interface BlockLookupAccess extends ApiLookupAccess, BlockLookupRegistration>, BlockLookup, BlockLookupRegistration { + static BlockLookupAccess create() { + return new BlockLookupAccessImpl<>(); + } +} diff --git a/common/src/main/java/dev/architectury/transfer/access/BlockLookupRegistration.java b/common/src/main/java/dev/architectury/transfer/access/BlockLookupRegistration.java new file mode 100644 index 00000000..5e55d70b --- /dev/null +++ b/common/src/main/java/dev/architectury/transfer/access/BlockLookupRegistration.java @@ -0,0 +1,55 @@ +/* + * 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.access; + +import net.minecraft.core.BlockPos; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Function; + +public interface BlockLookupRegistration { + /** + * Registers a lookup registration handler, this is used to provide + * interop with platform apis. + * + * @param id the id of the lookup registration handler + * @param provider the provider of the lookup registration handler + * @return true if the registration was successful + */ + boolean register(ResourceLocation id, BlockAccessProvider, @Nullable BlockEntity> provider); + + boolean registerForBlocks(ResourceLocation id, BlockAccessProvider, @Nullable BlockEntity> provider, Block... blocks); + + boolean registerForBlockEntities(ResourceLocation id, BlockAccessProvider, B> provider, BlockEntityType... blockEntityTypes); + + boolean registerForSelf(ResourceLocation id, BlockEntityType... blockEntityTypes); + + @FunctionalInterface + interface BlockAccessProvider { + @Nullable + R get(Level level, BlockPos pos, BlockState state, B blockEntity); + } +} diff --git a/common/src/main/java/dev/architectury/transfer/access/ItemTransferAccess.java b/common/src/main/java/dev/architectury/transfer/access/ItemLookup.java similarity index 76% rename from common/src/main/java/dev/architectury/transfer/access/ItemTransferAccess.java rename to common/src/main/java/dev/architectury/transfer/access/ItemLookup.java index c5b1051f..671ce33a 100644 --- a/common/src/main/java/dev/architectury/transfer/access/ItemTransferAccess.java +++ b/common/src/main/java/dev/architectury/transfer/access/ItemLookup.java @@ -19,12 +19,17 @@ package dev.architectury.transfer.access; -import dev.architectury.transfer.TransferAccess; -import dev.architectury.transfer.TransferHandler; import net.minecraft.world.item.ItemStack; import org.jetbrains.annotations.Nullable; -public interface ItemTransferAccess extends TransferAccess { +public interface ItemLookup { + /** + * Queries the api for the given item stack. + * + * @param stack the item stack + * @param context the context + * @return the transfer handler, or null if none was found + */ @Nullable - T get(ItemStack stack, C context); -} + T get(ItemStack stack, Context context); +} \ No newline at end of file diff --git a/forge/src/main/java/dev/architectury/transfer/forge/TransferContextImpl.java b/common/src/main/java/dev/architectury/transfer/access/ItemLookupAccess.java similarity index 64% rename from forge/src/main/java/dev/architectury/transfer/forge/TransferContextImpl.java rename to common/src/main/java/dev/architectury/transfer/access/ItemLookupAccess.java index 6b796e7b..5d3e45a0 100644 --- a/forge/src/main/java/dev/architectury/transfer/forge/TransferContextImpl.java +++ b/common/src/main/java/dev/architectury/transfer/access/ItemLookupAccess.java @@ -17,24 +17,13 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -package dev.architectury.transfer.forge; +package dev.architectury.transfer.access; -import dev.architectury.transfer.TransferContext; +import dev.architectury.impl.transfer.access.ItemLookupAccessImpl; +import dev.architectury.transfer.ApiLookupAccess; -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 { - +public interface ItemLookupAccess extends ApiLookupAccess, ItemLookupRegistration>, ItemLookup, ItemLookupRegistration { + static ItemLookupAccess create() { + return new ItemLookupAccessImpl<>(); } } diff --git a/common/src/main/java/dev/architectury/transfer/TransferAccess.java b/common/src/main/java/dev/architectury/transfer/access/ItemLookupRegistration.java similarity index 63% rename from common/src/main/java/dev/architectury/transfer/TransferAccess.java rename to common/src/main/java/dev/architectury/transfer/access/ItemLookupRegistration.java index af9f9ce7..d5e3352e 100644 --- a/common/src/main/java/dev/architectury/transfer/TransferAccess.java +++ b/common/src/main/java/dev/architectury/transfer/access/ItemLookupRegistration.java @@ -17,7 +17,20 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -package dev.architectury.transfer; +package dev.architectury.transfer.access; -public interface TransferAccess { +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.ItemStack; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Function; + +public interface ItemLookupRegistration { + boolean register(ResourceLocation id, ItemAccessProvider> provider); + + @FunctionalInterface + interface ItemAccessProvider { + @Nullable + R get(ItemStack stack); + } } diff --git a/common/src/main/java/dev/architectury/transfer/fluid/FluidTransfer.java b/common/src/main/java/dev/architectury/transfer/fluid/FluidTransfer.java index 2828c4cf..56408542 100644 --- a/common/src/main/java/dev/architectury/transfer/fluid/FluidTransfer.java +++ b/common/src/main/java/dev/architectury/transfer/fluid/FluidTransfer.java @@ -22,8 +22,8 @@ package dev.architectury.transfer.fluid; import dev.architectury.fluid.FluidStack; import dev.architectury.injectables.annotations.ExpectPlatform; import dev.architectury.transfer.TransferHandler; -import dev.architectury.transfer.access.BlockTransferAccess; -import dev.architectury.transfer.access.ItemTransferAccess; +import dev.architectury.transfer.access.BlockLookupAccess; +import dev.architectury.transfer.access.ItemLookupAccess; import net.minecraft.core.Direction; import net.minecraft.world.item.ItemStack; import org.jetbrains.annotations.Nullable; @@ -32,16 +32,25 @@ public class FluidTransfer { private FluidTransfer() { } - public static final BlockTransferAccess, Direction> BLOCK = instantiateBlockAccess(); - public static final ItemTransferAccess, TransferHandler> ITEM = instantiateItemAccess(); + /** + * A lookup access for fluid transfer handlers, the direction context is + * only required on fabric. + *

+ * This is the equivalent to getting the fluid transfer handler for a + * block entity on Forge, or the storage with the lookup api on Fabric. + *

+ * There are performance implications for using the architectury lookups, + * please keep your implementations as simple as possible. + */ + public static final BlockLookupAccess, Direction> BLOCK = BlockLookupAccess.create(); + // public static final ItemLookupAccess, TransferHandler> ITEM = ItemLookupAccess.create(); - @ExpectPlatform - private static BlockTransferAccess, Direction> instantiateBlockAccess() { - throw new AssertionError(); + static { + init(); } @ExpectPlatform - private static ItemTransferAccess, TransferHandler> instantiateItemAccess() { + private static void init() { throw new AssertionError(); } diff --git a/common/src/main/java/dev/architectury/transfer/item/ItemTransfer.java b/common/src/main/java/dev/architectury/transfer/item/ItemTransfer.java index 8fc125a1..35b428c3 100644 --- a/common/src/main/java/dev/architectury/transfer/item/ItemTransfer.java +++ b/common/src/main/java/dev/architectury/transfer/item/ItemTransfer.java @@ -21,16 +21,20 @@ package dev.architectury.transfer.item; import dev.architectury.injectables.annotations.ExpectPlatform; import dev.architectury.transfer.TransferHandler; -import dev.architectury.transfer.access.BlockTransferAccess; +import dev.architectury.transfer.access.BlockLookupAccess; import net.minecraft.core.Direction; import net.minecraft.world.item.ItemStack; import org.jetbrains.annotations.Nullable; public class ItemTransfer { - public static final BlockTransferAccess, Direction> BLOCK = instantiateBlockAccess(); + public static final BlockLookupAccess, Direction> BLOCK = BlockLookupAccess.create(); + + static { + init(); + } @ExpectPlatform - private static BlockTransferAccess, Direction> instantiateBlockAccess() { + private static void init() { throw new AssertionError(); } diff --git a/fabric/src/main/java/dev/architectury/fluid/fabric/FluidStackImpl.java b/fabric/src/main/java/dev/architectury/fluid/fabric/FluidStackImpl.java new file mode 100644 index 00000000..b96946a9 --- /dev/null +++ b/fabric/src/main/java/dev/architectury/fluid/fabric/FluidStackImpl.java @@ -0,0 +1,113 @@ +/* + * 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.fluid.fabric; + +import dev.architectury.fluid.FluidStack; +import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.level.material.Fluid; +import org.jetbrains.annotations.ApiStatus; + +import java.util.Objects; +import java.util.function.Function; +import java.util.function.Supplier; + +@ApiStatus.Internal +public enum FluidStackImpl implements FluidStack.FluidStackAdapter { + INSTANCE; + + public static Function toValue; + public static Function fromValue; + + public static FluidStack.FluidStackAdapter adapt(Function toValue, Function fromValue) { + FluidStackImpl.toValue = toValue; + FluidStackImpl.fromValue = fromValue; + return INSTANCE; + } + + public static class Pair { + public FluidVariant variant; + public long amount; + + public Pair(FluidVariant variant, long amount) { + this.variant = variant; + this.amount = amount; + } + } + + @Override + public Object create(Supplier fluid, long amount, CompoundTag tag) { + return new Pair(FluidVariant.of(Objects.requireNonNull(fluid).get(), tag == null ? null : tag.copy()), amount); + } + + @Override + public void check(Object object) { + if (!(object instanceof Pair)) { + throw new IllegalArgumentException("Expected FluidStackImpl.Pair, got " + object.getClass().getName()); + } + } + + @Override + public Supplier getRawFluidSupplier(Object object) { + return ((Pair) object).variant::getFluid; + } + + @Override + public Fluid getFluid(Object object) { + return ((Pair) object).variant.getFluid(); + } + + @Override + public long getAmount(Object object) { + return ((Pair) object).amount; + } + + @Override + public void setAmount(Object object, long amount) { + ((Pair) object).amount = amount; + } + + @Override + public CompoundTag getTag(Object value) { + return ((Pair) value).variant.getNbt(); + } + + @Override + public void setTag(Object value, CompoundTag tag) { + ((Pair) value).variant = FluidVariant.of(((Pair) value).variant.getFluid(), tag); + } + + @Override + public Object copy(Object value) { + return new Pair(FluidVariant.of(((Pair) value).variant.getFluid(), ((Pair) value).variant.getNbt()), ((Pair) value).amount); + } + + @Override + public int hashCode(Object value) { + var pair = (Pair) value; + var code = 1; + code = 31 * code + pair.variant.getFluid().hashCode(); + code = 31 * code + Long.hashCode(pair.amount); + var tag = pair.variant.getNbt(); + if (tag != null) + code = 31 * code + tag.hashCode(); + return code; + } +} 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 index 24b6f882..7676163d 100644 --- a/fabric/src/main/java/dev/architectury/hooks/fluid/fabric/FluidStackHooksFabric.java +++ b/fabric/src/main/java/dev/architectury/hooks/fluid/fabric/FluidStackHooksFabric.java @@ -20,6 +20,7 @@ package dev.architectury.hooks.fluid.fabric; import dev.architectury.fluid.FluidStack; +import dev.architectury.fluid.fabric.FluidStackImpl; import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant; import net.fabricmc.fabric.api.transfer.v1.storage.StorageView; @@ -32,10 +33,10 @@ public final class FluidStackHooksFabric { } public static FluidStack fromFabric(FluidVariant variant, long amount) { - return FluidStack.create(variant.getFluid(), amount, variant.getNbt()); + return FluidStackImpl.fromValue.apply(new FluidStackImpl.Pair(variant, amount)); } public static FluidVariant toFabric(FluidStack stack) { - return FluidVariant.of(stack.getFluid(), stack.getTag()); + return ((FluidStackImpl.Pair) FluidStackImpl.toValue.apply(stack)).variant; } } diff --git a/fabric/src/main/java/dev/architectury/transfer/fabric/FabricBlockTransferAccess.java b/fabric/src/main/java/dev/architectury/transfer/fabric/BlockApiLookupWrapper.java similarity index 80% rename from fabric/src/main/java/dev/architectury/transfer/fabric/FabricBlockTransferAccess.java rename to fabric/src/main/java/dev/architectury/transfer/fabric/BlockApiLookupWrapper.java index 4e2511e8..30779b26 100644 --- a/fabric/src/main/java/dev/architectury/transfer/fabric/FabricBlockTransferAccess.java +++ b/fabric/src/main/java/dev/architectury/transfer/fabric/BlockApiLookupWrapper.java @@ -20,7 +20,7 @@ package dev.architectury.transfer.fabric; import dev.architectury.transfer.TransferHandler; -import dev.architectury.transfer.access.BlockTransferAccess; +import dev.architectury.transfer.access.BlockLookup; import net.fabricmc.fabric.api.lookup.v1.block.BlockApiLookup; import net.minecraft.core.BlockPos; import net.minecraft.world.level.Level; @@ -30,11 +30,11 @@ import org.jetbrains.annotations.Nullable; import java.util.function.Function; -public class FabricBlockTransferAccess implements BlockTransferAccess, C> { +public class BlockApiLookupWrapper implements BlockLookup, C> { private final BlockApiLookup lookup; - private final Function> wrapper; + private final Function<@Nullable F, @Nullable TransferHandler> wrapper; - public FabricBlockTransferAccess(BlockApiLookup lookup, Function> wrapper) { + public BlockApiLookupWrapper(BlockApiLookup lookup, Function<@Nullable F, @Nullable TransferHandler> wrapper) { this.lookup = lookup; this.wrapper = wrapper; } @@ -49,7 +49,7 @@ public class FabricBlockTransferAccess implements BlockTransferAccess get(Level level, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, C context) { if (blockEntity != null) { - return wrapper.apply(lookup.find(level, pos, blockEntity.getBlockState(), blockEntity, context)); + return wrapper.apply(lookup.find(level, pos, state, blockEntity, context)); } else { return get(level, pos, context); } diff --git a/fabric/src/main/java/dev/architectury/transfer/fabric/FabricBlockLookupRegistration.java b/fabric/src/main/java/dev/architectury/transfer/fabric/FabricBlockLookupRegistration.java new file mode 100644 index 00000000..24487b4c --- /dev/null +++ b/fabric/src/main/java/dev/architectury/transfer/fabric/FabricBlockLookupRegistration.java @@ -0,0 +1,96 @@ +/* + * 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.access.BlockLookupRegistration; +import net.fabricmc.fabric.api.lookup.v1.block.BlockApiLookup; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Function; +import java.util.function.Predicate; + +public class FabricBlockLookupRegistration implements BlockLookupRegistration { + private final Function unwrapper; + private final BlockApiLookup lookup; + + public static FabricBlockLookupRegistration create(BlockApiLookup lookup, Function unwrapper) { + return new FabricBlockLookupRegistration<>(unwrapper, lookup); + } + + private FabricBlockLookupRegistration(Function unwrapper, BlockApiLookup lookup) { + this.unwrapper = unwrapper; + this.lookup = lookup; + } + + public BlockApiLookup.BlockApiProvider provider(BlockAccessProvider, BlockEntity> provider) { + return (level, pos, state, blockEntity, context) -> { + Function function = provider.get(level, pos, state, blockEntity); + if (function != null) { + return unwrapper.apply(function.apply(context)); + } + + return null; + + }; + } + + public BlockApiLookup.BlockEntityApiProvider provider(Predicate<@Nullable BlockEntityType> beTypePredicate, BlockAccessProvider, B> provider) { + return (blockEntity, context) -> { + if (!beTypePredicate.test(blockEntity == null ? null : blockEntity.getType())) { + return null; + } + + Function function = provider.get(blockEntity.getLevel(), blockEntity.getBlockPos(), blockEntity.getBlockState(), (B) blockEntity); + if (function != null) { + return unwrapper.apply(function.apply(context)); + } + + return null; + }; + } + + @Override + public boolean register(ResourceLocation id, BlockAccessProvider, @Nullable BlockEntity> provider) { + lookup.registerFallback(provider(provider)); + return true; + } + + @Override + public boolean registerForBlocks(ResourceLocation id, BlockAccessProvider, @Nullable BlockEntity> provider, Block... blocks) { + lookup.registerForBlocks(provider(provider), blocks); + return true; + } + + @Override + public boolean registerForBlockEntities(ResourceLocation id, BlockAccessProvider, B> provider, BlockEntityType... blockEntityTypes) { + lookup.registerForBlockEntities(provider(type -> true, provider), blockEntityTypes); + return true; + } + + @Override + public boolean registerForSelf(ResourceLocation id, BlockEntityType... blockEntityTypes) { + lookup.registerSelf(blockEntityTypes); + return false; + } +} diff --git a/fabric/src/main/java/dev/architectury/transfer/fabric/FabricStorageTransferHandler.java b/fabric/src/main/java/dev/architectury/transfer/fabric/FabricStorageTransferHandler.java index ef614884..6adcf58e 100644 --- a/fabric/src/main/java/dev/architectury/transfer/fabric/FabricStorageTransferHandler.java +++ b/fabric/src/main/java/dev/architectury/transfer/fabric/FabricStorageTransferHandler.java @@ -48,6 +48,10 @@ public class FabricStorageTransferHandler implements TransferHandler { this.typeAdapter = typeAdapter; } + public Storage getStorage() { + return storage; + } + @Override public Stream> getContents() { Transaction transaction = Transaction.openNested(this.transaction); @@ -135,6 +139,16 @@ public class FabricStorageTransferHandler implements TransferHandler { return typeAdapter.blank.get(); } + @Override + public Object saveState() { + throw new UnsupportedOperationException(); + } + + @Override + public void loadState(Object state) { + throw new UnsupportedOperationException(); + } + private boolean isEmpty(S stack) { return typeAdapter.isEmpty.test(stack); } @@ -179,15 +193,51 @@ public class FabricStorageTransferHandler implements TransferHandler { public long getCapacity() { return view.getCapacity(); } + + @Override + public S copyWithAmount(S resource, long amount) { + return FabricStorageTransferHandler.this.copyWithAmount(resource, amount); + } + + @Override + public S extract(S toExtract, TransferAction action) { + if (isEmpty(toExtract)) return blank(); + long extracted; + + try (Transaction nested = Transaction.openNested(FabricStorageTransferHandler.this.transaction)) { + extracted = this.view.extract(toFabric(toExtract), getAmount(toExtract), nested); + + if (action == TransferAction.ACT) { + nested.commit(); + } + } + + return copyWithAmount(toExtract, extracted); + } + + @Override + public S blank() { + return null; + } + + @Override + public Object saveState() { + throw new UnsupportedOperationException(); + } + + @Override + public void loadState(Object state) { + throw new UnsupportedOperationException(); + } } public static class TypeAdapter { - private final Function toFabric; - private final FunctionWithAmount fromFabric; - private final FunctionWithAmount copyWithAmount; - private final Supplier blank; - private final Predicate isEmpty; - private final ToLongFunction toAmount; + final Function toFabric; + final FunctionWithAmount fromFabric; + final FunctionWithAmount copyWithAmount; + final Supplier blank; + final Predicate isEmpty; + final ToLongFunction toAmount; public TypeAdapter(Function toFabric, FunctionWithAmount fromFabric, FunctionWithAmount copyWithAmount, Supplier blank, Predicate isEmpty, ToLongFunction toAmount) { this.toFabric = toFabric; diff --git a/fabric/src/main/java/dev/architectury/transfer/fabric/TransferContextImpl.java b/fabric/src/main/java/dev/architectury/transfer/fabric/TransferContextImpl.java deleted file mode 100644 index e90939bb..00000000 --- a/fabric/src/main/java/dev/architectury/transfer/fabric/TransferContextImpl.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * 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/fabric/TransferHandlerStorage.java b/fabric/src/main/java/dev/architectury/transfer/fabric/TransferHandlerStorage.java new file mode 100644 index 00000000..176d065f --- /dev/null +++ b/fabric/src/main/java/dev/architectury/transfer/fabric/TransferHandlerStorage.java @@ -0,0 +1,121 @@ +/* + * 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.ResourceView; +import dev.architectury.transfer.TransferAction; +import dev.architectury.transfer.TransferHandler; +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.TransactionContext; +import net.fabricmc.fabric.api.transfer.v1.transaction.base.SnapshotParticipant; + +import java.util.Iterator; +import java.util.stream.Stream; + +public class TransferHandlerStorage extends SnapshotParticipant implements Storage { + private final TransferHandler handler; + private final FabricStorageTransferHandler.TypeAdapter typeAdapter; + + public TransferHandlerStorage(TransferHandler handler, FabricStorageTransferHandler.TypeAdapter typeAdapter) { + this.handler = handler; + this.typeAdapter = typeAdapter; + } + + @Override + public Iterator> iterator(TransactionContext transaction) { + Stream> stream = this.handler.getContents() + .map(view -> new FabricStorageView(view, typeAdapter)); + transaction.addCloseCallback((t, result) -> { + stream.close(); + }); + return stream.iterator(); + } + + @Override + public long insert(F resource, long maxAmount, TransactionContext transaction) { + updateSnapshots(transaction); + return this.handler.insert(typeAdapter.fromFabric.apply(resource, maxAmount), TransferAction.ACT); + } + + @Override + public long extract(F resource, long maxAmount, TransactionContext transaction) { + updateSnapshots(transaction); + S extracted = this.handler.extract(typeAdapter.fromFabric.apply(resource, maxAmount), TransferAction.ACT); + return typeAdapter.toAmount.applyAsLong(extracted); + } + + @Override + protected Object createSnapshot() { + return this.handler.saveState(); + } + + @Override + protected void readSnapshot(Object snapshot) { + this.handler.loadState(snapshot); + } + + private static class FabricStorageView extends SnapshotParticipant implements StorageView { + private final ResourceView storage; + private final FabricStorageTransferHandler.TypeAdapter typeAdapter; + + private FabricStorageView(ResourceView view, FabricStorageTransferHandler.TypeAdapter typeAdapter) { + this.storage = view; + this.typeAdapter = typeAdapter; + } + + @Override + public long extract(F resource, long maxAmount, TransactionContext transaction) { + updateSnapshots(transaction); + S extracted = this.storage.extract(typeAdapter.fromFabric.apply(resource, maxAmount), TransferAction.ACT); + return typeAdapter.toAmount.applyAsLong(extracted); + } + + @Override + public boolean isResourceBlank() { + return getAmount() <= 0; + } + + @Override + public F getResource() { + return typeAdapter.toFabric.apply(storage.getResource()); + } + + @Override + public long getAmount() { + return typeAdapter.toAmount.applyAsLong(storage.getResource()); + } + + @Override + public long getCapacity() { + return storage.getCapacity(); + } + + @Override + protected Object createSnapshot() { + return storage.saveState(); + } + + @Override + protected void readSnapshot(Object snapshot) { + storage.loadState(snapshot); + } + } +} 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 index 5a089715..abb15a7d 100644 --- a/fabric/src/main/java/dev/architectury/transfer/fluid/fabric/FluidTransferImpl.java +++ b/fabric/src/main/java/dev/architectury/transfer/fluid/fabric/FluidTransferImpl.java @@ -22,10 +22,11 @@ package dev.architectury.transfer.fluid.fabric; import dev.architectury.fluid.FluidStack; import dev.architectury.hooks.fluid.fabric.FluidStackHooksFabric; import dev.architectury.transfer.TransferHandler; -import dev.architectury.transfer.access.BlockTransferAccess; -import dev.architectury.transfer.access.ItemTransferAccess; -import dev.architectury.transfer.fabric.FabricBlockTransferAccess; +import dev.architectury.transfer.fabric.BlockApiLookupWrapper; +import dev.architectury.transfer.fabric.FabricBlockLookupRegistration; import dev.architectury.transfer.fabric.FabricStorageTransferHandler; +import dev.architectury.transfer.fabric.TransferHandlerStorage; +import dev.architectury.transfer.fluid.FluidTransfer; import net.fabricmc.fabric.api.transfer.v1.context.ContainerItemContext; import net.fabricmc.fabric.api.transfer.v1.fluid.FluidStorage; import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant; @@ -34,7 +35,6 @@ import net.fabricmc.fabric.api.transfer.v1.storage.Storage; import net.fabricmc.fabric.api.transfer.v1.storage.base.SingleSlotStorage; import net.fabricmc.fabric.api.transfer.v1.storage.base.SingleVariantStorage; import net.fabricmc.fabric.api.transfer.v1.transaction.TransactionContext; -import net.minecraft.core.Direction; import net.minecraft.world.item.ItemStack; import org.jetbrains.annotations.Nullable; @@ -64,18 +64,23 @@ public class FluidTransferImpl { } } - public static BlockTransferAccess, Direction> instantiateBlockAccess() { - return new FabricBlockTransferAccess<>(FluidStorage.SIDED, FluidTransferImpl::wrap); + @Nullable + public static Storage unwrap(@Nullable TransferHandler handler) { + if (handler == null) return null; + + if (handler instanceof FabricStorageTransferHandler) { + return ((FabricStorageTransferHandler) handler).getStorage(); + } else { + return new TransferHandlerStorage<>(handler, TYPE_ADAPTER); + } } - public static ItemTransferAccess, TransferHandler> instantiateItemAccess() { - return new ItemTransferAccess, TransferHandler>() { - @Override - @Nullable - public TransferHandler get(ItemStack stack, TransferHandler context) { - return wrap(FluidStorage.ITEM.find(stack, fromTransfer(stack, context))); - } - }; + public static void init() { + FluidTransfer.BLOCK.addQueryHandler(new BlockApiLookupWrapper<>(FluidStorage.SIDED, FluidTransferImpl::wrap)); + FluidTransfer.BLOCK.addRegistrationHandler(FabricBlockLookupRegistration.create(FluidStorage.SIDED, FluidTransferImpl::unwrap)); +// FluidTransfer.ITEM.addQueryHandler((stack, context) -> { +// return wrap(FluidStorage.ITEM.find(stack, fromTransfer(stack, context))); +// }); } public static ContainerItemContext fromTransfer(ItemStack stack, TransferHandler transferHandler) { diff --git a/fabric/src/main/java/dev/architectury/transfer/item/fabric/FabricContainerItemTransferHandler.java b/fabric/src/main/java/dev/architectury/transfer/item/fabric/FabricContainerItemTransferHandler.java index e2ec5164..e690421a 100644 --- a/fabric/src/main/java/dev/architectury/transfer/item/fabric/FabricContainerItemTransferHandler.java +++ b/fabric/src/main/java/dev/architectury/transfer/item/fabric/FabricContainerItemTransferHandler.java @@ -46,6 +46,10 @@ public class FabricContainerItemTransferHandler implements TransferHandler> getContents() { return Stream.concat(Stream.of(context.getMainSlot()), context.getAdditionalSlots().stream()) @@ -118,7 +122,17 @@ public class FabricContainerItemTransferHandler implements TransferHandler { + @Override + public Object saveState() { + throw new UnsupportedOperationException(); + } + + @Override + public void loadState(Object state) { + throw new UnsupportedOperationException(); + } + + private class FabricResourceView implements ResourceView { private final SingleSlotStorage storage; private FabricResourceView(SingleSlotStorage storage) { @@ -134,5 +148,41 @@ public class FabricContainerItemTransferHandler implements TransferHandler, Direction> instantiateBlockAccess() { - return new FabricBlockTransferAccess<>(ItemStorage.SIDED, ItemTransferImpl::wrap); + @Nullable + public static Storage unwrap(@Nullable TransferHandler handler) { + if (handler == null) return null; + + if (handler instanceof FabricStorageTransferHandler) { + return ((FabricStorageTransferHandler) handler).getStorage(); + } else { + return new TransferHandlerStorage<>(handler, TYPE_ADAPTER); + } + } + + public static void init() { + ItemTransfer.BLOCK.addQueryHandler(new BlockApiLookupWrapper<>(ItemStorage.SIDED, ItemTransferImpl::wrap)); + ItemTransfer.BLOCK.addRegistrationHandler(FabricBlockLookupRegistration.create(ItemStorage.SIDED, ItemTransferImpl::unwrap)); } } diff --git a/forge/src/main/java/dev/architectury/fluid/forge/FluidStackImpl.java b/forge/src/main/java/dev/architectury/fluid/forge/FluidStackImpl.java new file mode 100644 index 00000000..ed49d60d --- /dev/null +++ b/forge/src/main/java/dev/architectury/fluid/forge/FluidStackImpl.java @@ -0,0 +1,101 @@ +/* + * 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.fluid.forge; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.level.material.Fluid; +import net.minecraftforge.fluids.FluidStack; +import org.jetbrains.annotations.ApiStatus; + +import java.util.function.Function; +import java.util.function.Supplier; + +@ApiStatus.Internal +public enum FluidStackImpl implements dev.architectury.fluid.FluidStack.FluidStackAdapter { + INSTANCE; + + public static Function toValue; + public static Function fromValue; + + public static dev.architectury.fluid.FluidStack.FluidStackAdapter adapt(Function toValue, Function fromValue) { + FluidStackImpl.toValue = toValue; + FluidStackImpl.fromValue = fromValue; + return INSTANCE; + } + + @Override + public Object create(Supplier fluid, long amount, CompoundTag tag) { + return new FluidStack(fluid.get(), (int) amount, tag); + } + + @Override + public void check(Object object) { + if (!(object instanceof FluidStack)) { + throw new IllegalArgumentException("Expected FluidStack, got " + object.getClass().getName()); + } + } + + @Override + public Supplier getRawFluidSupplier(Object object) { + return ((FluidStack) object).getRawFluid().delegate; + } + + @Override + public Fluid getFluid(Object object) { + return ((FluidStack) object).getFluid(); + } + + @Override + public long getAmount(Object object) { + return ((FluidStack) object).getAmount(); + } + + @Override + public void setAmount(Object object, long amount) { + ((FluidStack) object).setAmount((int) amount); + } + + @Override + public CompoundTag getTag(Object value) { + return ((FluidStack) value).getTag(); + } + + @Override + public void setTag(Object value, CompoundTag tag) { + ((FluidStack) value).setTag(tag); + } + + @Override + public Object copy(Object value) { + return ((FluidStack) value).copy(); + } + + @Override + public int hashCode(Object value) { + var stack = (FluidStack) value; + var code = 1; + code = 31 * code + stack.getFluid().hashCode(); + code = 31 * code + stack.getAmount(); + var tag = stack.getTag(); + if (tag != null) + code = 31 * code + tag.hashCode(); + return code; + } +} diff --git a/forge/src/main/java/dev/architectury/hooks/fluid/forge/FluidStackHooksForge.java b/forge/src/main/java/dev/architectury/hooks/fluid/forge/FluidStackHooksForge.java index c1963e6e..f9e01595 100644 --- a/forge/src/main/java/dev/architectury/hooks/fluid/forge/FluidStackHooksForge.java +++ b/forge/src/main/java/dev/architectury/hooks/fluid/forge/FluidStackHooksForge.java @@ -20,16 +20,17 @@ package dev.architectury.hooks.fluid.forge; import dev.architectury.fluid.FluidStack; +import dev.architectury.fluid.forge.FluidStackImpl; public final class FluidStackHooksForge { private FluidStackHooksForge() { } public static FluidStack fromForge(net.minecraftforge.fluids.FluidStack stack) { - return FluidStack.create(stack.getFluid().delegate, stack.getAmount(), stack.getTag()); + return FluidStackImpl.fromValue.apply(stack); } public static net.minecraftforge.fluids.FluidStack toForge(FluidStack stack) { - return new net.minecraftforge.fluids.FluidStack(stack.getRawFluid(), (int) stack.getAmount(), stack.getTag()); + return (net.minecraftforge.fluids.FluidStack) FluidStackImpl.toValue.apply(stack); } } 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 index e6157864..7350da2f 100644 --- a/forge/src/main/java/dev/architectury/transfer/fluid/forge/FluidTransferImpl.java +++ b/forge/src/main/java/dev/architectury/transfer/fluid/forge/FluidTransferImpl.java @@ -24,9 +24,11 @@ import dev.architectury.hooks.fluid.forge.FluidStackHooksForge; import dev.architectury.transfer.ResourceView; import dev.architectury.transfer.TransferAction; import dev.architectury.transfer.TransferHandler; -import dev.architectury.transfer.access.BlockTransferAccess; -import dev.architectury.transfer.access.ItemTransferAccess; -import dev.architectury.transfer.forge.ForgeBlockTransferAccess; +import dev.architectury.transfer.access.BlockLookup; +import dev.architectury.transfer.access.ItemLookup; +import dev.architectury.transfer.fluid.FluidTransfer; +import dev.architectury.transfer.forge.ForgeBlockLookupRegistration; +import dev.architectury.transfer.forge.ForgeItemLookupRegistration; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.world.item.ItemStack; @@ -35,10 +37,10 @@ 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.common.capabilities.Capability; import net.minecraftforge.fluids.IFluidBlock; import net.minecraftforge.fluids.capability.CapabilityFluidHandler; import net.minecraftforge.fluids.capability.IFluidHandler; +import net.minecraftforge.fluids.capability.IFluidHandlerItem; import net.minecraftforge.fluids.capability.wrappers.BucketPickupHandlerWrapper; import net.minecraftforge.fluids.capability.wrappers.FluidBlockWrapper; import org.jetbrains.annotations.NotNull; @@ -65,8 +67,17 @@ public class FluidTransferImpl { } } - public static BlockTransferAccess, Direction> instantiateBlockAccess() { - return new ForgeBlockTransferAccess, IFluidHandler>() { + public static void init() { + FluidTransfer.BLOCK.addQueryHandler(instantiateBlockLookup()); + FluidTransfer.BLOCK.addRegistrationHandler(ForgeBlockLookupRegistration.create(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, + (level, pos, state, blockEntity) -> (direction, handler) -> new ArchFluidHandler(handler))); +// FluidTransfer.ITEM.addQueryHandler(instantiateItemLookup()); +// FluidTransfer.ITEM.addRegistrationHandler(ForgeItemLookupRegistration.create(CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY, +// stack -> (direction, handler) -> new ArchFluidHandlerItem(handler, stack))); + } + + public static BlockLookup, Direction> instantiateBlockLookup() { + return new BlockLookup, Direction>() { @Override @Nullable public TransferHandler get(Level level, BlockPos pos, Direction direction) { @@ -92,21 +103,11 @@ public class FluidTransferImpl { } return wrap(handler); } - - @Override - public Capability getCapability() { - return CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY; - } - - @Override - public IFluidHandler from(TransferHandler handler) { - return new ArchFluidHandler(handler); - } }; } - public static ItemTransferAccess, TransferHandler> instantiateItemAccess() { - return new ItemTransferAccess, TransferHandler>() { + public static ItemLookup, TransferHandler> instantiateItemLookup() { + return new ItemLookup, TransferHandler>() { @Override @Nullable public TransferHandler get(ItemStack stack, TransferHandler context) { @@ -163,6 +164,21 @@ public class FluidTransferImpl { } } + public static class ArchFluidHandlerItem extends ArchFluidHandler implements IFluidHandlerItem { + private final ItemStack stack; + + public ArchFluidHandlerItem(TransferHandler handler, ItemStack stack) { + super(handler); + this.stack = stack; + } + + @NotNull + @Override + public ItemStack getContainer() { + return stack; + } + } + private static class ForgeTransferHandler implements TransferHandler { private IFluidHandler handler; @@ -217,6 +233,16 @@ public class FluidTransferImpl { return FluidStack.empty(); } + @Override + public Object saveState() { + throw new UnsupportedOperationException(); + } + + @Override + public void loadState(Object state) { + throw new UnsupportedOperationException(); + } + private class Itr implements Iterator> { int cursor; @@ -267,6 +293,32 @@ public class FluidTransferImpl { public long getCapacity() { return handler.getTankCapacity(index); } + + @Override + public FluidStack extract(FluidStack toExtract, TransferAction action) { + // TODO: implement + return null; + } + + @Override + public FluidStack blank() { + return FluidStack.empty(); + } + + @Override + public FluidStack copyWithAmount(FluidStack resource, long amount) { + return resource.copyWithAmount(amount); + } + + @Override + public Object saveState() { + throw new UnsupportedOperationException(); + } + + @Override + public void loadState(Object state) { + throw new UnsupportedOperationException(); + } } } diff --git a/forge/src/main/java/dev/architectury/transfer/forge/ForgeBlockLookupRegistration.java b/forge/src/main/java/dev/architectury/transfer/forge/ForgeBlockLookupRegistration.java new file mode 100644 index 00000000..d0921b45 --- /dev/null +++ b/forge/src/main/java/dev/architectury/transfer/forge/ForgeBlockLookupRegistration.java @@ -0,0 +1,122 @@ +/* + * 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.access.BlockLookupRegistration; +import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.capabilities.ICapabilityProvider; +import net.minecraftforge.common.util.LazyOptional; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.function.BiFunction; +import java.util.function.Function; + +public interface ForgeBlockLookupRegistration extends BlockLookupRegistration { + static ForgeBlockLookupRegistration create(Capability capability, BlockAccessProvider, BlockEntity> transformer) { + return new ForgeBlockLookupRegistration() { + @Override + public Capability getCapability() { + return capability; + } + + @Override + public Cap from(Level level, BlockPos blockPos, BlockState blockState, BlockEntity blockEntity, Direction direction, T handler) { + return transformer.get(level, blockPos, blockState, blockEntity).apply(direction, handler); + } + }; + } + + Capability getCapability(); + + Cap from(Level level, BlockPos blockPos, BlockState blockState, BlockEntity blockEntity, Direction direction, T handler); + + @Override + default boolean registerForBlocks(ResourceLocation id, BlockAccessProvider, @Nullable BlockEntity> provider, Block... blocks) { + ReferenceOpenHashSet set = new ReferenceOpenHashSet<>(blocks); + return register(id, (level, pos, state, blockEntity) -> { + if (set.contains(state.getBlock())) { + return provider.get(level, pos, state, blockEntity); + } + + return null; + }); + } + + @Override + default boolean registerForBlockEntities(ResourceLocation id, BlockAccessProvider, B> provider, BlockEntityType... blockEntityTypes) { + ReferenceOpenHashSet> set = new ReferenceOpenHashSet<>(blockEntityTypes); + return register(id, (level, pos, state, blockEntity) -> { + if (set.contains(blockEntity.getType())) { + return provider.get(level, pos, state, (B) blockEntity); + } + + return null; + }); + } + + @Override + default boolean registerForSelf(ResourceLocation id, BlockEntityType... blockEntityTypes) { + ReferenceOpenHashSet> set = new ReferenceOpenHashSet<>(blockEntityTypes); + return register(id, (level, pos, state, blockEntity) -> { + if (set.contains(blockEntity.getType())) { + return direction -> (T) blockEntity; + } + + return null; + }); + } + + @Override + default boolean register(ResourceLocation id, BlockAccessProvider, @Nullable BlockEntity> provider) { + CapabilitiesAttachListeners.add(event -> { + if (event.getObject() instanceof BlockEntity) { + BlockEntity blockEntity = (BlockEntity) event.getObject(); + Function applicator = provider.get(blockEntity.getLevel(), blockEntity.getBlockPos(), blockEntity.getBlockState(), blockEntity); + if (applicator != null) { + event.addCapability(id, new ICapabilityProvider() { + @NotNull + @Override + public LazyOptional getCapability(@NotNull Capability capability, @Nullable Direction arg) { + if (capability == ForgeBlockLookupRegistration.this.getCapability()) { + T handler = applicator.apply(arg); + + return handler == null ? LazyOptional.empty() : LazyOptional.of(() -> from(blockEntity.getLevel(), blockEntity.getBlockPos(), blockEntity.getBlockState(), blockEntity, arg, handler)).cast(); + } + + return LazyOptional.empty(); + } + }); + } + } + }); + + return true; + } +} diff --git a/forge/src/main/java/dev/architectury/transfer/forge/ForgeBlockTransferAccess.java b/forge/src/main/java/dev/architectury/transfer/forge/ForgeItemLookupRegistration.java similarity index 54% rename from forge/src/main/java/dev/architectury/transfer/forge/ForgeBlockTransferAccess.java rename to forge/src/main/java/dev/architectury/transfer/forge/ForgeItemLookupRegistration.java index 243ed4bc..7d1176a9 100644 --- a/forge/src/main/java/dev/architectury/transfer/forge/ForgeBlockTransferAccess.java +++ b/forge/src/main/java/dev/architectury/transfer/forge/ForgeItemLookupRegistration.java @@ -19,38 +19,53 @@ package dev.architectury.transfer.forge; -import dev.architectury.transfer.access.BlockTransferAccess; +import dev.architectury.transfer.access.ItemLookupRegistration; import net.minecraft.core.Direction; import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.item.ItemStack; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.capabilities.ICapabilityProvider; import net.minecraftforge.common.util.LazyOptional; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.function.BiFunction; import java.util.function.Function; -public interface ForgeBlockTransferAccess extends BlockTransferAccess { - Capability getCapability(); +public interface ForgeItemLookupRegistration extends ItemLookupRegistration { + static ForgeItemLookupRegistration create(Capability capability, ItemAccessProvider> transformer) { + return new ForgeItemLookupRegistration() { + @Override + public Capability getCapability() { + return capability; + } + + @Override + public C from(ItemStack stack, @Nullable Direction arg, T handler) { + return transformer.get(stack).apply(arg, handler); + } + }; + } - C from(T handler); + Capability getCapability(); + + Cap from(ItemStack stack, @Nullable Direction arg, T handler); @Override - default void register(ResourceLocation id, BlockAccessProvider provider) { + default boolean register(ResourceLocation id, ItemAccessProvider> provider) { CapabilitiesAttachListeners.add(event -> { - if (event.getObject() instanceof BlockEntity) { - BlockEntity blockEntity = (BlockEntity) event.getObject(); - Function applicator = provider.get(blockEntity.getLevel(), blockEntity.getBlockPos(), blockEntity.getBlockState(), blockEntity); + if (event.getObject() instanceof ItemStack) { + ItemStack stack = (ItemStack) event.getObject(); + Function applicator = provider.get(stack); if (applicator != null) { event.addCapability(id, new ICapabilityProvider() { @NotNull @Override public LazyOptional getCapability(@NotNull Capability capability, @Nullable Direction arg) { - if (capability == ForgeBlockTransferAccess.this.getCapability()) { - T handler = applicator.apply(arg); + if (capability == ForgeItemLookupRegistration.this.getCapability()) { + T handler = applicator.apply(null); - return LazyOptional.of(() -> from(handler)).cast(); + return handler == null ? LazyOptional.empty() : LazyOptional.of(() -> from(stack, arg, handler)).cast(); } return LazyOptional.empty(); @@ -59,5 +74,7 @@ public interface ForgeBlockTransferAccess extends BlockTransferAccess, Direction> instantiateBlockAccess() { - return new ForgeBlockTransferAccess, IItemHandler>() { + public static void init() { + ItemTransfer.BLOCK.addQueryHandler(instantiateBlockLookup()); + ItemTransfer.BLOCK.addRegistrationHandler(ForgeBlockLookupRegistration.create(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, + (level, pos, state, blockEntity) -> (direction, handler) -> new ArchItemHandler(handler))); + } + + public static BlockLookup, Direction> instantiateBlockLookup() { + return new BlockLookup, Direction>() { @Override @Nullable public TransferHandler get(Level level, BlockPos pos, Direction direction) { @@ -79,16 +86,6 @@ public class ItemTransferImpl { } return wrap(handler); } - - @Override - public Capability getCapability() { - return CapabilityItemHandler.ITEM_HANDLER_CAPABILITY; - } - - @Override - public IItemHandler from(TransferHandler handler) { - return new ArchItemHandler(handler); - } }; } @@ -166,11 +163,13 @@ public class ItemTransferImpl { @Override public ItemStack extract(ItemStack toExtract, TransferAction action) { + // TODO: implement return null; } @Override public ItemStack extract(Predicate toExtract, long maxAmount, TransferAction action) { + // TODO: implement return null; } @@ -179,6 +178,16 @@ public class ItemTransferImpl { return ItemStack.EMPTY; } + @Override + public Object saveState() { + throw new UnsupportedOperationException(); + } + + @Override + public void loadState(Object state) { + throw new UnsupportedOperationException(); + } + private class ForgeResourceView implements ResourceView { int index; @@ -195,6 +204,31 @@ public class ItemTransferImpl { public long getCapacity() { return handler.getSlotLimit(index); } + + @Override + public ItemStack extract(ItemStack toExtract, TransferAction action) { + return handler.extractItem(index, toExtract.getCount(), action == TransferAction.SIMULATE); + } + + @Override + public ItemStack blank() { + return ItemStack.EMPTY; + } + + @Override + public ItemStack copyWithAmount(ItemStack resource, long amount) { + return ItemStackHooks.copyWithCount(resource, (int) amount); + } + + @Override + public Object saveState() { + throw new UnsupportedOperationException(); + } + + @Override + public void loadState(Object state) { + throw new UnsupportedOperationException(); + } } } }