diff --git a/Common/src/main/java/at/petrak/hexcasting/api/block/circle/BlockEntityAbstractImpetus.java b/Common/src/main/java/at/petrak/hexcasting/api/block/circle/BlockEntityAbstractImpetus.java index 012cc418..31fd43a9 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/block/circle/BlockEntityAbstractImpetus.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/block/circle/BlockEntityAbstractImpetus.java @@ -68,6 +68,8 @@ public abstract class BlockEntityAbstractImpetus extends HexBlockEntity implemen @Nullable private Component lastMishap = null; + private static final int MAX_CAPACITY = 2_000_000_000; + private int mana = 0; public BlockEntityAbstractImpetus(BlockEntityType pType, BlockPos pWorldPosition, BlockState pBlockState) { @@ -519,11 +521,7 @@ public abstract class BlockEntityAbstractImpetus extends HexBlockEntity implemen @Override public void setItem(int index, ItemStack stack) { - var manamount = ManaHelper.extractMana(stack, -1, true, false); - if (manamount > 0) { - this.mana += manamount; - this.sync(); - } + insertMana(stack); } @Override @@ -533,7 +531,7 @@ public abstract class BlockEntityAbstractImpetus extends HexBlockEntity implemen @Override public boolean canPlaceItem(int index, ItemStack stack) { - var manamount = ManaHelper.extractMana(stack, -1, true, true); + var manamount = extractMana(stack, true); return manamount > 0; } @@ -543,4 +541,20 @@ public abstract class BlockEntityAbstractImpetus extends HexBlockEntity implemen this.stopCasting(); this.sync(); } + + public int extractMana(ItemStack stack, boolean simulate) { + return ManaHelper.extractMana(stack, remainingManaCapacity(), true, false); + } + + public void insertMana(ItemStack stack) { + var manamount = extractMana(stack, false); + if (manamount > 0) { + this.mana += manamount; + this.sync(); + } + } + + public int remainingManaCapacity() { + return MAX_CAPACITY - this.mana; + } } diff --git a/Fabric/src/main/java/at/petrak/hexcasting/fabric/FabricHexInitializer.kt b/Fabric/src/main/java/at/petrak/hexcasting/fabric/FabricHexInitializer.kt index 72ae2f3d..479fb8b8 100644 --- a/Fabric/src/main/java/at/petrak/hexcasting/fabric/FabricHexInitializer.kt +++ b/Fabric/src/main/java/at/petrak/hexcasting/fabric/FabricHexInitializer.kt @@ -17,6 +17,7 @@ import at.petrak.hexcasting.common.recipe.HexRecipeSerializers import at.petrak.hexcasting.fabric.event.VillagerConversionCallback import at.petrak.hexcasting.fabric.network.FabricPacketHandler import at.petrak.hexcasting.fabric.recipe.FabricUnsealedIngredient +import at.petrak.hexcasting.fabric.storage.FabricImpetusStorage import at.petrak.hexcasting.interop.HexInterop import io.github.tropheusj.serialization_hooks.ingredient.IngredientDeserializer import net.fabricmc.api.ModInitializer @@ -51,6 +52,7 @@ object FabricHexInitializer : ModInitializer { HexAdvancementTriggers.registerTriggers() HexComposting.setup() HexStrippables.init() + FabricImpetusStorage.registerStorage() HexInterop.init() } diff --git a/Fabric/src/main/java/at/petrak/hexcasting/fabric/storage/FabricImpetusStorage.kt b/Fabric/src/main/java/at/petrak/hexcasting/fabric/storage/FabricImpetusStorage.kt new file mode 100644 index 00000000..b1edda89 --- /dev/null +++ b/Fabric/src/main/java/at/petrak/hexcasting/fabric/storage/FabricImpetusStorage.kt @@ -0,0 +1,68 @@ +package at.petrak.hexcasting.fabric.storage + +import at.petrak.hexcasting.api.block.circle.BlockEntityAbstractImpetus +import at.petrak.hexcasting.common.lib.HexBlocks +import net.fabricmc.fabric.api.transfer.v1.item.ItemStorage +import net.fabricmc.fabric.api.transfer.v1.item.ItemVariant +import net.fabricmc.fabric.api.transfer.v1.storage.base.SingleSlotStorage +import net.fabricmc.fabric.api.transfer.v1.transaction.TransactionContext +import net.minecraft.world.item.ItemStack + +@Suppress("UnstableApiUsage") +class FabricImpetusStorage(val impetus: BlockEntityAbstractImpetus) : SingleSlotStorage { + companion object { + fun registerStorage() { + ItemStorage.SIDED.registerForBlocks({ _, _, _, blockEntity, _ -> + (blockEntity as? BlockEntityAbstractImpetus)?.let(::FabricImpetusStorage) + }, HexBlocks.IMPETUS_RIGHTCLICK, HexBlocks.IMPETUS_LOOK, HexBlocks.IMPETUS_STOREDPLAYER) + } + } + + override fun insert(resource: ItemVariant, maxAmount: Long, transaction: TransactionContext): Long { + val stackCount = maxAmount / 64 + val remainder = (maxAmount % 64).toInt() + var manaToTake = impetus.remainingManaCapacity() + var itemsConsumed = 0L + + fun insertStack(stack: ItemStack, transaction: TransactionContext) { + val copied = stack.copy() + val extractable = impetus.extractMana(stack, false) + manaToTake -= extractable + val taken = 64 - stack.count + itemsConsumed += taken.toLong() + copied.count = taken + + if (taken > 0) { + transaction.addOuterCloseCallback { + if (it.wasCommitted()) { + impetus.insertMana(copied) + } + } + } + } + for (i in 0 until stackCount) { + val stack = resource.toStack(64) + insertStack(stack, transaction) + if (manaToTake <= 0) { + return itemsConsumed + } + } + if (remainder > 0) { + val remainderStack = resource.toStack(remainder) + insertStack(remainderStack, transaction) + } + return itemsConsumed + } + + override fun supportsExtraction(): Boolean = false + + override fun extract(resource: ItemVariant, maxAmount: Long, transaction: TransactionContext): Long = 0 + + override fun isResourceBlank(): Boolean = true + + override fun getResource(): ItemVariant = ItemVariant.blank() + + override fun getAmount(): Long = 0 + + override fun getCapacity(): Long = 64 +} diff --git a/Fabric/src/main/java/at/petrak/hexcasting/fabric/xplat/FabricXplatImpl.java b/Fabric/src/main/java/at/petrak/hexcasting/fabric/xplat/FabricXplatImpl.java index 02a68844..959a943a 100644 --- a/Fabric/src/main/java/at/petrak/hexcasting/fabric/xplat/FabricXplatImpl.java +++ b/Fabric/src/main/java/at/petrak/hexcasting/fabric/xplat/FabricXplatImpl.java @@ -28,9 +28,16 @@ import net.fabricmc.fabric.api.item.v1.FabricItemSettings; import net.fabricmc.fabric.api.networking.v1.PlayerLookup; import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder; +import net.fabricmc.fabric.api.transfer.v1.context.ContainerItemContext; +import net.fabricmc.fabric.api.transfer.v1.fluid.FluidConstants; +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.StorageUtil; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.advancements.critereon.ItemPredicate; import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; import net.minecraft.core.Registry; import net.minecraft.network.protocol.Packet; import net.minecraft.resources.ResourceLocation; @@ -235,8 +242,11 @@ public class FabricXplatImpl implements IXplatAbstractions { } @Override + @SuppressWarnings("UnstableApiUsage") public boolean tryPlaceFluid(Level level, InteractionHand hand, BlockPos pos, ItemStack stack, Fluid fluid) { - return false; + Storage target = FluidStorage.SIDED.find(level, pos, Direction.UP); + Storage emptyFrom = FluidStorage.ITEM.find(stack, ContainerItemContext.withInitial(stack)); + return StorageUtil.move(emptyFrom, target, (f) -> true, FluidConstants.BUCKET, null) > 0; } @Override diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/ForgeHexInitializer.java b/Forge/src/main/java/at/petrak/hexcasting/forge/ForgeHexInitializer.java index afadcaf7..e1a281ca 100644 --- a/Forge/src/main/java/at/petrak/hexcasting/forge/ForgeHexInitializer.java +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/ForgeHexInitializer.java @@ -35,6 +35,7 @@ import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Mob; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraftforge.common.ForgeConfigSpec; import net.minecraftforge.common.MinecraftForge; @@ -202,6 +203,7 @@ public class ForgeHexInitializer { // Caps are cardinal components on farbc modBus.addListener(ForgeCapabilityHandler::registerCaps); evBus.addGenericListener(ItemStack.class, ForgeCapabilityHandler::attachItemCaps); + evBus.addGenericListener(BlockEntity.class, ForgeCapabilityHandler::attachBlockEntityCaps); modBus.register(HexForgeDataGenerators.class); modBus.register(ForgeCapabilityHandler.class); diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/cap/ForgeCapabilityHandler.java b/Forge/src/main/java/at/petrak/hexcasting/forge/cap/ForgeCapabilityHandler.java index c9feb344..e6227acd 100644 --- a/Forge/src/main/java/at/petrak/hexcasting/forge/cap/ForgeCapabilityHandler.java +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/cap/ForgeCapabilityHandler.java @@ -4,6 +4,7 @@ import at.petrak.hexcasting.api.addldata.Colorizer; import at.petrak.hexcasting.api.addldata.DataHolder; import at.petrak.hexcasting.api.addldata.HexHolder; import at.petrak.hexcasting.api.addldata.ManaHolder; +import at.petrak.hexcasting.api.block.circle.BlockEntityAbstractImpetus; import at.petrak.hexcasting.api.item.ColorizerItem; import at.petrak.hexcasting.api.item.DataHolderItem; import at.petrak.hexcasting.api.item.HexHolderItem; @@ -17,6 +18,7 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; +import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.phys.Vec3; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.capabilities.ICapabilityProvider; @@ -24,11 +26,13 @@ import net.minecraftforge.common.capabilities.RegisterCapabilitiesEvent; import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.common.util.NonNullSupplier; import net.minecraftforge.event.AttachCapabilitiesEvent; +import net.minecraftforge.items.CapabilityItemHandler; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.UUID; +import java.util.function.BooleanSupplier; import java.util.function.Function; import java.util.function.Supplier; @@ -40,6 +44,8 @@ public class ForgeCapabilityHandler { private static final ResourceLocation SPELL_HOLDER_CAPABILITY = new ResourceLocation("hexcasting", "spell_item"); private static final ResourceLocation COLORIZER_CAPABILITY = new ResourceLocation("hexcasting", "colorizer"); + private static final ResourceLocation IMPETUS_HANDLER = new ResourceLocation("hexcasting", "impetus_items"); + public static void registerCaps(RegisterCapabilitiesEvent evt) { evt.register(ManaHolder.class); evt.register(DataHolder.class); @@ -78,18 +84,32 @@ public class ForgeCapabilityHandler { () -> new ItemBasedColorizer(colorizer, stack))); } - private static SimpleProvider provide(ItemStack stack, Capability capability, NonNullSupplier supplier) { - return new SimpleProvider<>(stack, capability, LazyOptional.of(supplier)); + public static void attachBlockEntityCaps(AttachCapabilitiesEvent evt) { + if (evt.getObject() instanceof BlockEntityAbstractImpetus impetus) + evt.addCapability(IMPETUS_HANDLER, provide(impetus, CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, + () -> new ForgeImpetusCapability(impetus))); } - private record SimpleProvider(ItemStack stack, + private static SimpleProvider provide(BlockEntity be, Capability capability, NonNullSupplier supplier) { + return provide(be::isRemoved, capability, supplier); + } + + private static SimpleProvider provide(ItemStack stack, Capability capability, NonNullSupplier supplier) { + return provide(stack::isEmpty, capability, supplier); + } + + private static SimpleProvider provide(BooleanSupplier invalidated, Capability capability, NonNullSupplier supplier) { + return new SimpleProvider<>(invalidated, capability, LazyOptional.of(supplier)); + } + + private record SimpleProvider(BooleanSupplier invalidated, Capability capability, LazyOptional instance) implements ICapabilityProvider { @NotNull @Override public LazyOptional getCapability(@NotNull Capability cap, @Nullable Direction side) { - if (stack.isEmpty()) + if (invalidated.getAsBoolean()) return LazyOptional.empty(); return cap == capability ? instance.cast() : LazyOptional.empty(); diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/cap/ForgeImpetusCapability.java b/Forge/src/main/java/at/petrak/hexcasting/forge/cap/ForgeImpetusCapability.java new file mode 100644 index 00000000..c05f03a7 --- /dev/null +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/cap/ForgeImpetusCapability.java @@ -0,0 +1,53 @@ +package at.petrak.hexcasting.forge.cap; + +import at.petrak.hexcasting.api.block.circle.BlockEntityAbstractImpetus; +import net.minecraft.world.item.ItemStack; +import net.minecraftforge.items.IItemHandler; +import org.jetbrains.annotations.NotNull; + +public record ForgeImpetusCapability(BlockEntityAbstractImpetus impetus) implements IItemHandler { + @Override + public int getSlots() { + return 1; + } + + @NotNull + @Override + public ItemStack getStackInSlot(int slot) { + return ItemStack.EMPTY; + } + + @NotNull + @Override + public ItemStack insertItem(int slot, @NotNull ItemStack originalStack, boolean simulate) { + if (!isItemValid(slot, originalStack)) { + return originalStack; + } + + ItemStack stack = originalStack.copy(); + + if (!simulate) { + impetus.insertMana(stack); + } else { + impetus.extractMana(stack, false); // Mana goes nowhere, since nothing is actually being done + } + + return stack; + } + + @NotNull + @Override + public ItemStack extractItem(int slot, int amount, boolean simulate) { + return ItemStack.EMPTY; + } + + @Override + public int getSlotLimit(int slot) { + return 64; + } + + @Override + public boolean isItemValid(int slot, @NotNull ItemStack stack) { + return impetus.canPlaceItem(slot, stack); + } +} diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/xplat/ForgeXplatImpl.java b/Forge/src/main/java/at/petrak/hexcasting/forge/xplat/ForgeXplatImpl.java index 2e8be57f..ba437cf9 100644 --- a/Forge/src/main/java/at/petrak/hexcasting/forge/xplat/ForgeXplatImpl.java +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/xplat/ForgeXplatImpl.java @@ -27,6 +27,7 @@ import at.petrak.hexcasting.xplat.IXplatAbstractions; import at.petrak.hexcasting.xplat.IXplatTags; import at.petrak.hexcasting.xplat.Platform; import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; import net.minecraft.core.NonNullList; import net.minecraft.core.Registry; import net.minecraft.nbt.CompoundTag; @@ -63,10 +64,10 @@ import net.minecraftforge.common.ForgeMod; import net.minecraftforge.common.TierSortingRegistry; import net.minecraftforge.common.ToolActions; import net.minecraftforge.common.loot.CanToolPerformAction; -import net.minecraftforge.fluids.FluidActionResult; import net.minecraftforge.fluids.FluidAttributes; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.FluidUtil; +import net.minecraftforge.fluids.capability.IFluidHandler; import net.minecraftforge.fml.ModList; import net.minecraftforge.fml.loading.FMLLoader; import net.minecraftforge.network.NetworkDirection; @@ -76,6 +77,7 @@ import virtuoel.pehkui.api.ScaleTypes; import java.util.ArrayList; import java.util.List; +import java.util.Optional; import java.util.function.BiFunction; public class ForgeXplatImpl implements IXplatAbstractions { @@ -305,8 +307,13 @@ public class ForgeXplatImpl implements IXplatAbstractions { @Override public boolean tryPlaceFluid(Level level, InteractionHand hand, BlockPos pos, ItemStack stack, Fluid fluid) { + Optional handler = FluidUtil.getFluidHandler(level, pos, Direction.UP).resolve(); + if (handler.isPresent() && + FluidUtil.tryEmptyContainer(stack, handler.get(), FluidAttributes.BUCKET_VOLUME, null, true).isSuccess()) { + return true; + } return FluidUtil.tryPlaceFluid(null, level, hand, pos, stack, new FluidStack( - fluid, FluidAttributes.BUCKET_VOLUME)) != FluidActionResult.FAILURE; + fluid, FluidAttributes.BUCKET_VOLUME)).isSuccess(); } @Override