mirror of
https://github.com/FabricMC/fabric.git
synced 2024-11-26 17:46:25 -05:00
Transfer API improvements and breaking changes for 1.19 (#2139)
* Remove deprecated APIs * Remove the transaction requirement for storage iteration * Remove useless TransactionContext parameters in StorageUtil * Improve SnapshotParticipant javadoc * Fix tests * Allow client-side SIDED item/fluid storage queries with a few caveats * Add SidedStorageBlockEntity for easier block entity hierarchy registration
This commit is contained in:
parent
ec94c6f636
commit
50e8465e2e
21 changed files with 181 additions and 404 deletions
|
@ -32,8 +32,6 @@ import net.fabricmc.api.Environment;
|
|||
import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRenderHandler;
|
||||
import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRenderHandlerRegistry;
|
||||
import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant;
|
||||
import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariantAttributes;
|
||||
import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariantAttributeHandler;
|
||||
|
||||
/**
|
||||
* Defines how {@linkplain FluidVariant fluid variants} of a given Fluid should be displayed to clients.
|
||||
|
@ -45,15 +43,6 @@ import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariantAttributeHandler;
|
|||
@ApiStatus.Experimental
|
||||
@Environment(EnvType.CLIENT)
|
||||
public interface FluidVariantRenderHandler {
|
||||
/**
|
||||
* @deprecated Implement {@link FluidVariantAttributeHandler#getName} instead.
|
||||
* This function will be removed in a future iteration of the API.
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
default Text getName(FluidVariant fluidVariant) {
|
||||
return FluidVariantAttributes.getName(fluidVariant);
|
||||
}
|
||||
|
||||
/**
|
||||
* Append additional tooltips to the passed list if additional information is contained in the fluid variant.
|
||||
*
|
||||
|
@ -83,26 +72,6 @@ public interface FluidVariantRenderHandler {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use and implement {@linkplain #getSprites(FluidVariant) the other more general overload}.
|
||||
* This one will be removed in a future iteration of the API.
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
@Nullable
|
||||
default Sprite getSprite(FluidVariant fluidVariant) {
|
||||
Sprite[] sprites = getSprites(fluidVariant);
|
||||
return sprites != null ? sprites[0] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use and implement {@linkplain #getColor(FluidVariant, BlockRenderView, BlockPos) the other more general overload}.
|
||||
* This one will be removed in a future iteration of the API.
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
default int getColor(FluidVariant fluidVariant) {
|
||||
return getColor(fluidVariant, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the color to use when rendering {@linkplain #getSprite the sprite} of this fluid variant.
|
||||
* Transparency (alpha) will generally be taken into account and should be specified as well.
|
||||
|
@ -122,14 +91,4 @@ public interface FluidVariantRenderHandler {
|
|||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Implement {@link FluidVariantAttributeHandler#isLighterThanAir(FluidVariant)} instead.
|
||||
* This function will be removed in a future iteration of the API.
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
default boolean fillsFromTop(FluidVariant fluidVariant) {
|
||||
// By default, only fluids lighter than air should be filled from top.
|
||||
return FluidVariantAttributes.isLighterThanAir(fluidVariant);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,15 +76,6 @@ public class FluidVariantRendering {
|
|||
return handler == null ? DEFAULT_HANDLER : handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the passed fluid variant.
|
||||
* @deprecated use {@link FluidVariantAttributes#getName} instead.
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
public static Text getName(FluidVariant fluidVariant) {
|
||||
return getHandlerOrDefault(fluidVariant.getFluid()).getName(fluidVariant);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a mutable list: the tooltip for the passed fluid variant, including the name and additional lines if available
|
||||
* and the id of the fluid if advanced tooltips are enabled.
|
||||
|
@ -103,7 +94,7 @@ public class FluidVariantRendering {
|
|||
List<Text> tooltip = new ArrayList<>();
|
||||
|
||||
// Name first
|
||||
tooltip.add(getName(fluidVariant));
|
||||
tooltip.add(FluidVariantAttributes.getName(fluidVariant));
|
||||
|
||||
// Additional tooltip information
|
||||
getHandlerOrDefault(fluidVariant.getFluid()).appendTooltip(fluidVariant, tooltip, context);
|
||||
|
@ -156,13 +147,4 @@ public class FluidVariantRendering {
|
|||
public static int getColor(FluidVariant fluidVariant, @Nullable BlockRenderView view, @Nullable BlockPos pos) {
|
||||
return getHandlerOrDefault(fluidVariant.getFluid()).getColor(fluidVariant, view, pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return {@code true} if this fluid variant should be rendered as filling tanks from the top.
|
||||
* @deprecated use {@link FluidVariantAttributes#isLighterThanAir} instead.
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
public static boolean fillsFromTop(FluidVariant fluidVariant) {
|
||||
return getHandlerOrDefault(fluidVariant.getFluid()).fillsFromTop(fluidVariant);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
package net.fabricmc.fabric.api.transfer.v1.fluid;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
|
@ -34,6 +33,7 @@ import net.minecraft.util.math.Direction;
|
|||
import net.fabricmc.fabric.api.event.Event;
|
||||
import net.fabricmc.fabric.api.lookup.v1.block.BlockApiLookup;
|
||||
import net.fabricmc.fabric.api.lookup.v1.item.ItemApiLookup;
|
||||
import net.fabricmc.fabric.api.transfer.v1.storage.base.SidedStorageBlockEntity;
|
||||
import net.fabricmc.fabric.api.transfer.v1.context.ContainerItemContext;
|
||||
import net.fabricmc.fabric.api.transfer.v1.fluid.base.EmptyItemFluidStorage;
|
||||
import net.fabricmc.fabric.api.transfer.v1.fluid.base.FullItemFluidStorage;
|
||||
|
@ -58,11 +58,15 @@ public final class FluidStorage {
|
|||
* The {@code Direction} parameter may never be null.
|
||||
* Refer to {@link BlockApiLookup} for documentation on how to use this field.
|
||||
*
|
||||
* <p>A simple way to expose fluid variant storages for a block entity hierarchy is to extend {@link SidedStorageBlockEntity}.
|
||||
*
|
||||
* <p>When the operations supported by a storage change,
|
||||
* that is if the return value of {@link Storage#supportsInsertion} or {@link Storage#supportsExtraction} changes,
|
||||
* the storage should notify its neighbors with a block update so that they can refresh their connections if necessary.
|
||||
*
|
||||
* <p>May only be queried on the logical server thread, never client-side or from another thread!
|
||||
* <p>This may be queried safely both on the logical server and on the logical client threads.
|
||||
* On the server thread (i.e. with a server world), all transfer functionality is always supported.
|
||||
* On the client thread (i.e. with a client world), contents of queried Storages are unreliable and should not be modified.
|
||||
*/
|
||||
public static final BlockApiLookup<Storage<FluidVariant>, Direction> SIDED =
|
||||
BlockApiLookup.get(new Identifier("fabric:sided_fluid_storage"), Storage.asClass(), Direction.class);
|
||||
|
@ -129,15 +133,18 @@ public final class FluidStorage {
|
|||
}
|
||||
|
||||
static {
|
||||
// Ensure that the lookup is only queried on the server side.
|
||||
FluidStorage.SIDED.registerFallback((world, pos, state, blockEntity, context) -> {
|
||||
Preconditions.checkArgument(!world.isClient(), "Sided fluid storage may only be queried for a server world.");
|
||||
return null;
|
||||
});
|
||||
|
||||
// Initialize vanilla cauldron wrappers
|
||||
CauldronFluidContent.getForFluid(Fluids.WATER);
|
||||
|
||||
// Support for SidedStorageBlockEntity.
|
||||
FluidStorage.SIDED.registerFallback((world, pos, state, blockEntity, direction) -> {
|
||||
if (blockEntity instanceof SidedStorageBlockEntity sidedStorageBlockEntity) {
|
||||
return sidedStorageBlockEntity.getFluidStorage(direction);
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
|
||||
// Register combined fallback
|
||||
FluidStorage.ITEM.registerFallback((stack, context) -> GENERAL_COMBINED_PROVIDER.invoker().find(context));
|
||||
// Register empty bucket storage
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package net.fabricmc.fabric.api.transfer.v1.fluid.base;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
@ -31,7 +32,6 @@ import net.fabricmc.fabric.api.transfer.v1.storage.StoragePreconditions;
|
|||
import net.fabricmc.fabric.api.transfer.v1.storage.StorageView;
|
||||
import net.fabricmc.fabric.api.transfer.v1.storage.base.BlankVariantView;
|
||||
import net.fabricmc.fabric.api.transfer.v1.storage.base.InsertionOnlyStorage;
|
||||
import net.fabricmc.fabric.api.transfer.v1.storage.base.SingleViewIterator;
|
||||
import net.fabricmc.fabric.api.transfer.v1.transaction.TransactionContext;
|
||||
|
||||
/**
|
||||
|
@ -66,6 +66,7 @@ public final class EmptyItemFluidStorage implements InsertionOnlyStorage<FluidVa
|
|||
private final Function<ItemVariant, ItemVariant> emptyToFullMapping;
|
||||
private final Fluid insertableFluid;
|
||||
private final long insertableAmount;
|
||||
private final List<StorageView<FluidVariant>> blankView;
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
|
@ -98,6 +99,7 @@ public final class EmptyItemFluidStorage implements InsertionOnlyStorage<FluidVa
|
|||
this.emptyToFullMapping = emptyToFullMapping;
|
||||
this.insertableFluid = insertableFluid;
|
||||
this.insertableAmount = insertableAmount;
|
||||
this.blankView = List.of(new BlankVariantView<>(FluidVariant.blank(), insertableAmount));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -122,7 +124,7 @@ public final class EmptyItemFluidStorage implements InsertionOnlyStorage<FluidVa
|
|||
}
|
||||
|
||||
@Override
|
||||
public Iterator<StorageView<FluidVariant>> iterator(TransactionContext transaction) {
|
||||
return SingleViewIterator.create(new BlankVariantView<>(FluidVariant.blank(), insertableAmount), transaction);
|
||||
public Iterator<StorageView<FluidVariant>> iterator() {
|
||||
return blankView.iterator();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,146 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.api.transfer.v1.fluid.base;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant;
|
||||
import net.fabricmc.fabric.api.transfer.v1.storage.StoragePreconditions;
|
||||
import net.fabricmc.fabric.api.transfer.v1.storage.base.ResourceAmount;
|
||||
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.fabricmc.fabric.api.transfer.v1.transaction.base.SnapshotParticipant;
|
||||
|
||||
/**
|
||||
* @deprecated Superseded by {@link SingleVariantStorage}. Will be removed in a future iteration of the API.
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
@Deprecated(forRemoval = true)
|
||||
public abstract class SingleFluidStorage extends SnapshotParticipant<ResourceAmount<FluidVariant>> implements SingleSlotStorage<FluidVariant> {
|
||||
public FluidVariant fluidVariant = FluidVariant.blank();
|
||||
public long amount;
|
||||
|
||||
/**
|
||||
* Implement if you want.
|
||||
*/
|
||||
protected void markDirty() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code true} if the passed non-blank fluid variant can be inserted, {@code false} otherwise.
|
||||
*/
|
||||
protected boolean canInsert(FluidVariant fluidVariant) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code true} if the passed non-blank fluid variant can be extracted, {@code false} otherwise.
|
||||
*/
|
||||
protected boolean canExtract(FluidVariant fluidVariant) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The maximum capacity of this storage for the passed fluid variant.
|
||||
* If the passed fluid variant is blank, an estimate should be returned.
|
||||
*/
|
||||
protected abstract long getCapacity(FluidVariant fluidVariant);
|
||||
|
||||
@Override
|
||||
public final boolean isResourceBlank() {
|
||||
return fluidVariant.isBlank();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final FluidVariant getResource() {
|
||||
return fluidVariant;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final long getAmount() {
|
||||
return fluidVariant.isBlank() ? 0 : amount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final long getCapacity() {
|
||||
return getCapacity(fluidVariant);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final long insert(FluidVariant insertedFluid, long maxAmount, TransactionContext transaction) {
|
||||
StoragePreconditions.notBlankNotNegative(insertedFluid, maxAmount);
|
||||
|
||||
if ((insertedFluid.equals(fluidVariant) || fluidVariant.isBlank()) && canInsert(insertedFluid)) {
|
||||
long insertedAmount = Math.min(maxAmount, getCapacity(insertedFluid) - amount);
|
||||
|
||||
if (insertedAmount > 0) {
|
||||
updateSnapshots(transaction);
|
||||
|
||||
// Just in case.
|
||||
if (fluidVariant.isBlank()) {
|
||||
amount = 0;
|
||||
}
|
||||
|
||||
amount += insertedAmount;
|
||||
fluidVariant = insertedFluid;
|
||||
}
|
||||
|
||||
return insertedAmount;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final long extract(FluidVariant extractedFluid, long maxAmount, TransactionContext transaction) {
|
||||
StoragePreconditions.notBlankNotNegative(extractedFluid, maxAmount);
|
||||
|
||||
if (extractedFluid.equals(fluidVariant) && canExtract(extractedFluid)) {
|
||||
long extractedAmount = Math.min(maxAmount, amount);
|
||||
|
||||
if (extractedAmount > 0) {
|
||||
updateSnapshots(transaction);
|
||||
amount -= extractedAmount;
|
||||
|
||||
if (amount == 0) {
|
||||
fluidVariant = FluidVariant.blank();
|
||||
}
|
||||
}
|
||||
|
||||
return extractedAmount;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final ResourceAmount<FluidVariant> createSnapshot() {
|
||||
return new ResourceAmount<>(fluidVariant, amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final void readSnapshot(ResourceAmount<FluidVariant> snapshot) {
|
||||
this.fluidVariant = snapshot.resource();
|
||||
this.amount = snapshot.amount();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final void onFinalCommit() {
|
||||
markDirty();
|
||||
}
|
||||
}
|
|
@ -18,7 +18,6 @@ package net.fabricmc.fabric.api.transfer.v1.item;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import net.minecraft.block.Blocks;
|
||||
|
@ -32,6 +31,7 @@ import net.minecraft.util.Identifier;
|
|||
import net.minecraft.util.math.Direction;
|
||||
|
||||
import net.fabricmc.fabric.api.lookup.v1.block.BlockApiLookup;
|
||||
import net.fabricmc.fabric.api.transfer.v1.storage.base.SidedStorageBlockEntity;
|
||||
import net.fabricmc.fabric.api.transfer.v1.item.base.SingleStackStorage;
|
||||
import net.fabricmc.fabric.api.transfer.v1.storage.Storage;
|
||||
import net.fabricmc.fabric.api.transfer.v1.storage.base.CombinedStorage;
|
||||
|
@ -72,6 +72,12 @@ public final class ItemStorage {
|
|||
* <li>{@link SingleStackStorage} can also be used for more flexibility. Multiple of them can be combined with {@link CombinedStorage}.</li>
|
||||
* <li>Directly providing a custom implementation of {@code Storage<ItemVariant>} is also possible.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>A simple way to expose item variant storages for a block entity hierarchy is to extend {@link SidedStorageBlockEntity}.
|
||||
*
|
||||
* <p>This may be queried safely both on the logical server and on the logical client threads.
|
||||
* On the server thread (i.e. with a server world), all transfer functionality is always supported.
|
||||
* On the client thread (i.e. with a client world), contents of queried Storages are unreliable and should not be modified.
|
||||
*/
|
||||
public static final BlockApiLookup<Storage<ItemVariant>, Direction> SIDED =
|
||||
BlockApiLookup.get(new Identifier("fabric:sided_item_storage"), Storage.asClass(), Direction.class);
|
||||
|
@ -80,15 +86,18 @@ public final class ItemStorage {
|
|||
}
|
||||
|
||||
static {
|
||||
// Ensure that the lookup is only queried on the server side.
|
||||
ItemStorage.SIDED.registerFallback((world, pos, state, blockEntity, context) -> {
|
||||
Preconditions.checkArgument(!world.isClient(), "Sided item storage may only be queried for a server world.");
|
||||
return null;
|
||||
});
|
||||
|
||||
// Composter support.
|
||||
ItemStorage.SIDED.registerForBlocks((world, pos, state, blockEntity, direction) -> ComposterWrapper.get(world, pos, direction), Blocks.COMPOSTER);
|
||||
|
||||
// Support for SidedStorageBlockEntity.
|
||||
ItemStorage.SIDED.registerFallback((world, pos, state, blockEntity, direction) -> {
|
||||
if (blockEntity instanceof SidedStorageBlockEntity sidedStorageBlockEntity) {
|
||||
return sidedStorageBlockEntity.getItemStorage(direction);
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
|
||||
// Register Inventory fallback.
|
||||
ItemStorage.SIDED.registerFallback((world, pos, state, blockEntity, direction) -> {
|
||||
Inventory inventoryToWrap = null;
|
||||
|
|
|
@ -25,7 +25,6 @@ import net.fabricmc.fabric.api.transfer.v1.storage.base.CombinedStorage;
|
|||
import net.fabricmc.fabric.api.transfer.v1.storage.base.ExtractionOnlyStorage;
|
||||
import net.fabricmc.fabric.api.transfer.v1.storage.base.InsertionOnlyStorage;
|
||||
import net.fabricmc.fabric.api.transfer.v1.storage.base.SingleVariantStorage;
|
||||
import net.fabricmc.fabric.api.transfer.v1.storage.base.SingleViewIterator;
|
||||
import net.fabricmc.fabric.api.transfer.v1.transaction.Transaction;
|
||||
import net.fabricmc.fabric.api.transfer.v1.transaction.TransactionContext;
|
||||
import net.fabricmc.fabric.impl.transfer.TransferApiImpl;
|
||||
|
@ -45,7 +44,6 @@ import net.fabricmc.fabric.impl.transfer.TransferApiImpl;
|
|||
* <ul>
|
||||
* <li>{@link CombinedStorage} can be used to combine multiple instances, for example to combine multiple "slots" in one big storage.</li>
|
||||
* <li>{@link ExtractionOnlyStorage} and {@link InsertionOnlyStorage} can be used when only extraction or insertion is needed.</li>
|
||||
* <li>{@link SingleViewIterator} can be used to wrap a single view for use with {@link #iterator}.</li>
|
||||
* <li>Resource-specific base implementations may also be available.
|
||||
* For example, Fabric API provides {@link SingleVariantStorage} to accelerate implementations of transfer variant storages.</li>
|
||||
* </ul>
|
||||
|
@ -65,7 +63,7 @@ import net.fabricmc.fabric.impl.transfer.TransferApiImpl;
|
|||
* The transfer API is a complex addition, and we want to be able to correct possible design mistakes.
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
public interface Storage<T> {
|
||||
public interface Storage<T> extends Iterable<StorageView<T>> {
|
||||
/**
|
||||
* Return an empty storage.
|
||||
*/
|
||||
|
@ -137,38 +135,21 @@ public interface Storage<T> {
|
|||
}
|
||||
|
||||
/**
|
||||
* Iterate through the contents of this storage, for the scope of the passed transaction.
|
||||
* Iterate through the contents of this storage.
|
||||
* Every visited {@link StorageView} represents a stored resource and an amount.
|
||||
* The iterator doesn't guarantee that a single resource only occurs once during an iteration.
|
||||
* Calling {@linkplain Iterator#remove remove} on the iterator is not allowed.
|
||||
*
|
||||
* <p>The returned iterator and any view it returns are only valid for the scope of to the passed transaction.
|
||||
* They should not be used once that transaction is closed.
|
||||
* Using the iterator or any view once the transaction is closed is undefined behavior.
|
||||
*
|
||||
* <p>{@link #insert} and {@link #extract} may be called safely during iteration.
|
||||
* Extractions should be visible to an open iterator, but insertions are not required to.
|
||||
* In particular, inventories with a fixed amount of slots may wish to make insertions visible to iterators,
|
||||
* but inventories with a dynamic or very large amount of slots should not do that to ensure timely termination of
|
||||
* the iteration.
|
||||
*
|
||||
* @param transaction The transaction to which the scope of the returned iterator is tied.
|
||||
* @return An iterator over the contents of this storage. Calling remove on the iterator is not allowed.
|
||||
*/
|
||||
Iterator<? extends StorageView<T>> iterator(TransactionContext transaction);
|
||||
|
||||
/**
|
||||
* Iterate through the contents of this storage, for the scope of the passed transaction.
|
||||
* This function follows the semantics of {@link #iterator}, but returns an {@code Iterable} for use in {@code for} loops.
|
||||
*
|
||||
* @param transaction The transaction to which the scope of the returned iterator is tied.
|
||||
* @return An iterable over the contents of this storage.
|
||||
* @see #iterator
|
||||
*/
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
default Iterable<? extends StorageView<T>> iterable(TransactionContext transaction) {
|
||||
return () -> (Iterator) iterator(transaction);
|
||||
}
|
||||
@Override
|
||||
Iterator<StorageView<T>> iterator();
|
||||
|
||||
/**
|
||||
* Return a view over this storage, for a specific resource, or {@code null} if none is quickly available.
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package net.fabricmc.fabric.api.transfer.v1.storage;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
@ -78,12 +79,13 @@ public final class StorageUtil {
|
|||
* @throws IllegalStateException If no transaction is passed and a transaction is already active on the current thread.
|
||||
*/
|
||||
public static <T> long move(@Nullable Storage<T> from, @Nullable Storage<T> to, Predicate<T> filter, long maxAmount, @Nullable TransactionContext transaction) {
|
||||
Objects.requireNonNull(filter, "Filter may not be null");
|
||||
if (from == null || to == null) return 0;
|
||||
|
||||
long totalMoved = 0;
|
||||
|
||||
try (Transaction iterationTransaction = Transaction.openNested(transaction)) {
|
||||
for (StorageView<T> view : from.iterable(iterationTransaction)) {
|
||||
for (StorageView<T> view : from) {
|
||||
if (view.isResourceBlank()) continue;
|
||||
T resource = view.getResource();
|
||||
if (!filter.test(resource)) continue;
|
||||
|
@ -148,12 +150,12 @@ public final class StorageUtil {
|
|||
/**
|
||||
* Attempt to find a resource stored in the passed storage.
|
||||
*
|
||||
* @see #findStoredResource(Storage, Predicate, TransactionContext)
|
||||
* @see #findStoredResource(Storage, Predicate)
|
||||
* @return A non-blank resource stored in the storage, or {@code null} if none could be found.
|
||||
*/
|
||||
@Nullable
|
||||
public static <T> T findStoredResource(@Nullable Storage<T> storage, @Nullable TransactionContext transaction) {
|
||||
return findStoredResource(storage, r -> true, transaction);
|
||||
public static <T> T findStoredResource(@Nullable Storage<T> storage) {
|
||||
return findStoredResource(storage, r -> true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -161,26 +163,15 @@ public final class StorageUtil {
|
|||
*
|
||||
* @param storage The storage to inspect, may be null.
|
||||
* @param filter The filter. Only a resource for which this filter returns {@code true} will be returned.
|
||||
* @param transaction The current transaction, or {@code null} if a transaction should be opened for this query.
|
||||
* @param <T> The type of the stored resources.
|
||||
* @return A non-blank resource stored in the storage that matches the filter, or {@code null} if none could be found.
|
||||
*/
|
||||
@Nullable
|
||||
public static <T> T findStoredResource(@Nullable Storage<T> storage, Predicate<T> filter, @Nullable TransactionContext transaction) {
|
||||
public static <T> T findStoredResource(@Nullable Storage<T> storage, Predicate<T> filter) {
|
||||
Objects.requireNonNull(filter, "Filter may not be null");
|
||||
if (storage == null) return null;
|
||||
|
||||
if (transaction == null) {
|
||||
try (Transaction outer = Transaction.openOuter()) {
|
||||
return findStoredResourceInner(storage, filter, outer);
|
||||
}
|
||||
} else {
|
||||
return findStoredResourceInner(storage, filter, transaction);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static <T> T findStoredResourceInner(Storage<T> storage, Predicate<T> filter, TransactionContext transaction) {
|
||||
for (StorageView<T> view : storage.iterable(transaction)) {
|
||||
for (StorageView<T> view : storage) {
|
||||
if (!view.isResourceBlank() && filter.test(view.getResource())) {
|
||||
return view.getResource();
|
||||
}
|
||||
|
@ -211,10 +202,11 @@ public final class StorageUtil {
|
|||
*/
|
||||
@Nullable
|
||||
public static <T> T findExtractableResource(@Nullable Storage<T> storage, Predicate<T> filter, @Nullable TransactionContext transaction) {
|
||||
Objects.requireNonNull(filter, "Filter may not be null");
|
||||
if (storage == null) return null;
|
||||
|
||||
try (Transaction nested = Transaction.openNested(transaction)) {
|
||||
for (StorageView<T> view : storage.iterable(nested)) {
|
||||
for (StorageView<T> view : storage) {
|
||||
// Extract below could change the resource, so we have to query it before extracting.
|
||||
T resource = view.getResource();
|
||||
|
||||
|
@ -269,28 +261,17 @@ public final class StorageUtil {
|
|||
* Compute the comparator output for a storage, similar to {@link ScreenHandler#calculateComparatorOutput(Inventory)}.
|
||||
*
|
||||
* @param storage The storage for which the comparator level should be computed.
|
||||
* @param transaction The current transaction, or {@code null} if a transaction should be opened for this computation.
|
||||
* @param <T> The type of the stored resources.
|
||||
* @return An integer between 0 and 15 (inclusive): the comparator output for the passed storage.
|
||||
*/
|
||||
public static <T> int calculateComparatorOutput(@Nullable Storage<T> storage, @Nullable TransactionContext transaction) {
|
||||
public static <T> int calculateComparatorOutput(@Nullable Storage<T> storage) {
|
||||
if (storage == null) return 0;
|
||||
|
||||
if (transaction == null) {
|
||||
try (Transaction outer = Transaction.openOuter()) {
|
||||
return calculateComparatorOutputInner(storage, outer);
|
||||
}
|
||||
} else {
|
||||
return calculateComparatorOutputInner(storage, transaction);
|
||||
}
|
||||
}
|
||||
|
||||
private static <T> int calculateComparatorOutputInner(Storage<T> storage, TransactionContext transaction) {
|
||||
double fillPercentage = 0;
|
||||
int viewCount = 0;
|
||||
boolean hasNonEmptyView = false;
|
||||
|
||||
for (StorageView<T> view : storage.iterable(transaction)) {
|
||||
for (StorageView<T> view : storage) {
|
||||
viewCount++;
|
||||
|
||||
if (view.getAmount() > 0) {
|
||||
|
|
|
@ -26,7 +26,6 @@ import net.fabricmc.fabric.api.transfer.v1.storage.Storage;
|
|||
import net.fabricmc.fabric.api.transfer.v1.storage.StoragePreconditions;
|
||||
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.Transaction;
|
||||
|
||||
/**
|
||||
* A {@link Storage} wrapping multiple storages.
|
||||
|
@ -96,37 +95,29 @@ public class CombinedStorage<T, S extends Storage<T>> implements Storage<T> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Iterator<StorageView<T>> iterator(TransactionContext transaction) {
|
||||
return new CombinedIterator(transaction);
|
||||
public Iterator<StorageView<T>> iterator() {
|
||||
return new CombinedIterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* The combined iterator for multiple storages.
|
||||
*/
|
||||
private class CombinedIterator implements Iterator<StorageView<T>>, Transaction.CloseCallback {
|
||||
boolean open = true;
|
||||
final TransactionContext transaction;
|
||||
private class CombinedIterator implements Iterator<StorageView<T>> {
|
||||
final Iterator<S> partIterator = parts.iterator();
|
||||
// Always holds the next StorageView<T>, except during next() while the iterator is being advanced.
|
||||
Iterator<? extends StorageView<T>> currentPartIterator = null;
|
||||
|
||||
CombinedIterator(TransactionContext transaction) {
|
||||
this.transaction = transaction;
|
||||
CombinedIterator() {
|
||||
advanceCurrentPartIterator();
|
||||
transaction.addCloseCallback(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return open && currentPartIterator != null && currentPartIterator.hasNext();
|
||||
return currentPartIterator != null && currentPartIterator.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public StorageView<T> next() {
|
||||
if (!open) {
|
||||
throw new NoSuchElementException("The transaction for this iterator was closed.");
|
||||
}
|
||||
|
||||
if (!hasNext()) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
@ -143,18 +134,12 @@ public class CombinedStorage<T, S extends Storage<T>> implements Storage<T> {
|
|||
|
||||
private void advanceCurrentPartIterator() {
|
||||
while (partIterator.hasNext()) {
|
||||
this.currentPartIterator = partIterator.next().iterator(transaction);
|
||||
this.currentPartIterator = partIterator.next().iterator();
|
||||
|
||||
if (this.currentPartIterator.hasNext()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(TransactionContext transaction, Transaction.Result result) {
|
||||
// As soon as the transaction is closed, this iterator is not valid anymore.
|
||||
open = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -161,8 +161,8 @@ public abstract class FilteringStorage<T> implements Storage<T> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Iterator<StorageView<T>> iterator(TransactionContext transaction) {
|
||||
return Iterators.transform(backingStorage.get().iterator(transaction), FilteringStorageView::new);
|
||||
public Iterator<StorageView<T>> iterator() {
|
||||
return Iterators.transform(backingStorage.get().iterator(), FilteringStorageView::new);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.api.transfer.v1.storage.base;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.minecraft.util.math.Direction;
|
||||
|
||||
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.item.ItemStorage;
|
||||
import net.fabricmc.fabric.api.transfer.v1.item.ItemVariant;
|
||||
import net.fabricmc.fabric.api.transfer.v1.storage.Storage;
|
||||
|
||||
/**
|
||||
* <b>Optional</b> helper class that can be implemented on block entities that wish to provide a {@linkplain FluidStorage#SIDED sided fluid storage}
|
||||
* and/or a {@linkplain ItemStorage#SIDED sided item storage} without having to register a provider for each block entity type.
|
||||
*
|
||||
* <p>How it works is that fabric registers fallback providers for instances of this interface.
|
||||
* This can be used for convenient Storage registration, but please always use the SIDED lookups for queries:
|
||||
* <pre>{@code
|
||||
* Storage<FluidStorage> maybeFluidStorage = FluidStorage.SIDED.find(world, pos, direction);
|
||||
* if (maybeFluidStorage != null) {
|
||||
* // use it
|
||||
* }
|
||||
* Storage<ItemStorage> maybeItemStorage = ItemStorage.SIDED.find(world, pos, direction);
|
||||
* if (maybeItemStorage != null) {
|
||||
* // use it
|
||||
* }
|
||||
* }</pre>
|
||||
*/
|
||||
public interface SidedStorageBlockEntity {
|
||||
/**
|
||||
* Return a fluid storage if available on the queried side, or null otherwise.
|
||||
*/
|
||||
@ApiStatus.OverrideOnly
|
||||
@Nullable
|
||||
default Storage<FluidVariant> getFluidStorage(Direction side) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an item storage if available on the queried side, or null otherwise.
|
||||
*/
|
||||
@ApiStatus.OverrideOnly
|
||||
@Nullable
|
||||
default Storage<ItemVariant> getItemStorage(Direction side) {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -22,7 +22,7 @@ import org.jetbrains.annotations.ApiStatus;
|
|||
|
||||
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.impl.transfer.TransferApiImpl;
|
||||
|
||||
/**
|
||||
* A storage that is also its only storage view.
|
||||
|
@ -36,7 +36,7 @@ import net.fabricmc.fabric.api.transfer.v1.transaction.TransactionContext;
|
|||
@ApiStatus.Experimental
|
||||
public interface SingleSlotStorage<T> extends Storage<T>, StorageView<T> {
|
||||
@Override
|
||||
default Iterator<StorageView<T>> iterator(TransactionContext transaction) {
|
||||
return SingleViewIterator.create(this, transaction);
|
||||
default Iterator<StorageView<T>> iterator() {
|
||||
return TransferApiImpl.singletonIterator(this);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,84 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.api.transfer.v1.storage.base;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import net.fabricmc.fabric.api.transfer.v1.storage.Storage;
|
||||
import net.fabricmc.fabric.api.transfer.v1.storage.StorageView;
|
||||
import net.fabricmc.fabric.api.transfer.v1.transaction.Transaction;
|
||||
import net.fabricmc.fabric.api.transfer.v1.transaction.TransactionContext;
|
||||
|
||||
/**
|
||||
* An iterator for a single {@link StorageView}, tied to a transaction. Instances can be created with {@link #create}.
|
||||
*
|
||||
* <p>This class should only be used by implementors of {@link Storage#iterator}, that wish to expose a single storage view.
|
||||
* In that case, usage of this class is recommended, as it will ensure that the storage view can't be accessed after the transaction is closed.
|
||||
*
|
||||
* @param <T> The type of the stored resource.
|
||||
*
|
||||
* <b>Experimental feature</b>, we reserve the right to remove or change it without further notice.
|
||||
* The transfer API is a complex addition, and we want to be able to correct possible design mistakes.
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
public final class SingleViewIterator<T> implements Iterator<StorageView<T>>, Transaction.CloseCallback {
|
||||
/**
|
||||
* Create a new iterator for the passed storage view, tied to the passed transaction.
|
||||
*
|
||||
* <p>The iterator will ensure that it can only be used as long as the transaction is open.
|
||||
*/
|
||||
public static <T> Iterator<StorageView<T>> create(StorageView<T> view, TransactionContext transaction) {
|
||||
SingleViewIterator<T> it = new SingleViewIterator<>(view);
|
||||
transaction.addCloseCallback(it);
|
||||
return it;
|
||||
}
|
||||
|
||||
private boolean open = true;
|
||||
private boolean hasNext = true;
|
||||
private final StorageView<T> view;
|
||||
|
||||
private SingleViewIterator(StorageView<T> view) {
|
||||
this.view = view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return open && hasNext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StorageView<T> next() {
|
||||
if (!open) {
|
||||
throw new NoSuchElementException("The transaction for this iterator was closed.");
|
||||
}
|
||||
|
||||
if (!hasNext()) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
||||
hasNext = false;
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(TransactionContext transaction, Transaction.Result result) {
|
||||
open = false;
|
||||
}
|
||||
}
|
|
@ -29,6 +29,19 @@ import net.fabricmc.fabric.api.transfer.v1.transaction.TransactionContext;
|
|||
* A base participant implementation that modifies itself during transactions,
|
||||
* saving snapshots of its state in objects of type {@code T} in case it needs to revert to a previous state.
|
||||
*
|
||||
* <h3>How to use from subclasses</h3>
|
||||
* <ul>
|
||||
* <li>Call {@link #updateSnapshots} right before the state of your subclass is modified in a transaction.</li>
|
||||
* <li>Override {@link #createSnapshot}: it is called when necessary to create an object representing the state of your subclass.</li>
|
||||
* <li>Override {@link #readSnapshot}: it is called when necessary to revert to a previous state of your subclass.</li>
|
||||
* <li>You may optionally override {@link #onFinalCommit}: it is called at the of a transaction that modified the state.
|
||||
* For example, it could contain a call to {@code markDirty()}.</li>
|
||||
* <li>(Advanced!) You may optionally override {@link #releaseSnapshot}: it is called once a snapshot object will not be used,
|
||||
* for example you may wish to pool expensive state objects.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <h3>More technical explanation</h3>
|
||||
*
|
||||
* <p>{@link #updateSnapshots} should be called before any modification.
|
||||
* This will save the state of this participant using {@link #createSnapshot} if no state was already saved for that transaction.
|
||||
* When the transaction is aborted and changes need to be rolled back, {@link #readSnapshot} will be called
|
||||
|
|
|
@ -18,6 +18,7 @@ package net.fabricmc.fabric.impl.transfer;
|
|||
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -53,7 +54,7 @@ public class TransferApiImpl {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Iterator<StorageView> iterator(TransactionContext transaction) {
|
||||
public Iterator<StorageView> iterator() {
|
||||
return Collections.emptyIterator();
|
||||
}
|
||||
|
||||
|
@ -67,4 +68,25 @@ public class TransferApiImpl {
|
|||
* Not null when writing to an inventory in a transaction, null otherwise.
|
||||
*/
|
||||
public static final ThreadLocal<Object> SUPPRESS_SPECIAL_LOGIC = new ThreadLocal<>();
|
||||
|
||||
public static <T> Iterator<T> singletonIterator(T it) {
|
||||
return new Iterator<T>() {
|
||||
boolean hasNext = true;
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return hasNext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T next() {
|
||||
if (!hasNext) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
||||
hasNext = false;
|
||||
return it;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package net.fabricmc.fabric.impl.transfer.fluid;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.Items;
|
||||
|
@ -29,7 +30,6 @@ import net.fabricmc.fabric.api.transfer.v1.storage.StoragePreconditions;
|
|||
import net.fabricmc.fabric.api.transfer.v1.storage.StorageView;
|
||||
import net.fabricmc.fabric.api.transfer.v1.storage.base.BlankVariantView;
|
||||
import net.fabricmc.fabric.api.transfer.v1.storage.base.InsertionOnlyStorage;
|
||||
import net.fabricmc.fabric.api.transfer.v1.storage.base.SingleViewIterator;
|
||||
import net.fabricmc.fabric.api.transfer.v1.transaction.TransactionContext;
|
||||
import net.fabricmc.fabric.mixin.transfer.BucketItemAccessor;
|
||||
|
||||
|
@ -38,6 +38,7 @@ import net.fabricmc.fabric.mixin.transfer.BucketItemAccessor;
|
|||
*/
|
||||
public class EmptyBucketStorage implements InsertionOnlyStorage<FluidVariant> {
|
||||
private final ContainerItemContext context;
|
||||
private final List<StorageView<FluidVariant>> blankView = List.of(new BlankVariantView<>(FluidVariant.blank(), FluidConstants.BUCKET));
|
||||
|
||||
public EmptyBucketStorage(ContainerItemContext context) {
|
||||
this.context = context;
|
||||
|
@ -66,7 +67,7 @@ public class EmptyBucketStorage implements InsertionOnlyStorage<FluidVariant> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Iterator<StorageView<FluidVariant>> iterator(TransactionContext transaction) {
|
||||
return SingleViewIterator.create(new BlankVariantView<>(FluidVariant.blank(), FluidConstants.BUCKET), transaction);
|
||||
public Iterator<StorageView<FluidVariant>> iterator() {
|
||||
return blankView.iterator();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -154,7 +154,7 @@ public class ComposterWrapper extends SnapshotParticipant<Float> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Iterator<StorageView<ItemVariant>> iterator(TransactionContext transaction) {
|
||||
public Iterator<StorageView<ItemVariant>> iterator() {
|
||||
return Collections.emptyIterator();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ public class TrashingStorage<T extends TransferVariant<?>> implements InsertionO
|
|||
}
|
||||
|
||||
@Override
|
||||
public Iterator<StorageView<T>> iterator(TransactionContext transaction) {
|
||||
public Iterator<StorageView<T>> iterator() {
|
||||
return Collections.emptyIterator();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,9 +70,9 @@ public class BaseStorageTests {
|
|||
// Extraction should also fail.
|
||||
assertEquals(0L, noWater.simulateExtract(water, BUCKET, null));
|
||||
// The fluid should be visible.
|
||||
assertEquals(water, StorageUtil.findStoredResource(noWater, null));
|
||||
assertEquals(water, StorageUtil.findStoredResource(noWater));
|
||||
// Test the filter.
|
||||
assertEquals(null, StorageUtil.findStoredResource(noWater, fv -> fv.isOf(Fluids.LAVA), null));
|
||||
assertEquals(null, StorageUtil.findStoredResource(noWater, fv -> fv.isOf(Fluids.LAVA)));
|
||||
// But it can't be extracted, even through a storage view.
|
||||
assertEquals(null, StorageUtil.findExtractableResource(noWater, null));
|
||||
assertEquals(null, StorageUtil.findExtractableContent(noWater, null));
|
||||
|
|
|
@ -165,7 +165,7 @@ class FluidItemTests {
|
|||
PotionUtil.setPotion(testInventory.getStack(0), Potions.LUCK);
|
||||
Storage<FluidVariant> luckyStorage = new InventoryContainerItem(testInventory, 0).find(FluidStorage.ITEM);
|
||||
|
||||
if (StorageUtil.findStoredResource(luckyStorage, null) != null) {
|
||||
if (StorageUtil.findStoredResource(luckyStorage) != null) {
|
||||
throw new AssertionError("Found a resource in an unhandled potion.");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -90,7 +90,7 @@ class ItemTests {
|
|||
private static void testInventoryWrappers() {
|
||||
ItemVariant emptyBucket = ItemVariant.of(Items.BUCKET);
|
||||
TestSidedInventory testInventory = new TestSidedInventory();
|
||||
checkComparatorOutput(testInventory, null);
|
||||
checkComparatorOutput(testInventory);
|
||||
|
||||
// Create a few wrappers.
|
||||
InventoryStorage unsidedWrapper = InventoryStorage.of(testInventory, null);
|
||||
|
@ -126,7 +126,7 @@ class ItemTests {
|
|||
if (!testInventory.getStack(0).isEmpty()) throw new AssertionError("Slot 0 should have been empty.");
|
||||
if (!testInventory.getStack(1).isOf(Items.BUCKET) || testInventory.getStack(1).getCount() != 1) throw new AssertionError("Slot 1 should have been a bucket.");
|
||||
|
||||
checkComparatorOutput(testInventory, null);
|
||||
checkComparatorOutput(testInventory);
|
||||
}
|
||||
|
||||
private static boolean stackEquals(ItemStack stack, Item item, int count) {
|
||||
|
@ -179,7 +179,7 @@ class ItemTests {
|
|||
throw new AssertionError("Only 6 diamonds should have been inserted.");
|
||||
}
|
||||
|
||||
checkComparatorOutput(inventory, transaction);
|
||||
checkComparatorOutput(inventory);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -197,7 +197,7 @@ class ItemTests {
|
|||
throw new AssertionError("Only 5 pickaxes should have been inserted.");
|
||||
}
|
||||
|
||||
checkComparatorOutput(inventory, transaction);
|
||||
checkComparatorOutput(inventory);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -216,11 +216,11 @@ class ItemTests {
|
|||
}
|
||||
}
|
||||
|
||||
private static void checkComparatorOutput(Inventory inventory, @Nullable Transaction transaction) {
|
||||
private static void checkComparatorOutput(Inventory inventory) {
|
||||
Storage<ItemVariant> storage = InventoryStorage.of(inventory, null);
|
||||
|
||||
int vanillaOutput = ScreenHandler.calculateComparatorOutput(inventory);
|
||||
int transferApiOutput = StorageUtil.calculateComparatorOutput(storage, transaction);
|
||||
int transferApiOutput = StorageUtil.calculateComparatorOutput(storage);
|
||||
|
||||
if (vanillaOutput != transferApiOutput) {
|
||||
String error = String.format(
|
||||
|
|
Loading…
Reference in a new issue