Transfer API improvements 4 ()

* Transfer API improvements 4

* Actually copy the nbt in `copyOrCreateNbt`

Co-authored-by: Juuxel <6596629+Juuxel@users.noreply.github.com>

* Add SingleFluidStorage.withFixedCapacity

* Remove unneeded iterator() overrides

* Add temporary workaround for bottle sounds

* Address review comments

* Change parameter name from compound to nbt

Co-authored-by: Juuxel <6596629+Juuxel@users.noreply.github.com>
This commit is contained in:
Technici4n 2022-09-11 15:20:47 +02:00 committed by GitHub
parent 2b0146fe54
commit 8f88597368
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 396 additions and 35 deletions

View file

@ -88,7 +88,21 @@ import net.fabricmc.fabric.impl.transfer.context.SingleSlotContainerItemContext;
@ApiStatus.Experimental
public interface ContainerItemContext {
/**
* Return a context for the passed player's hand. This is recommended for item use interactions.
* Returns a context for interaction with a player's hand. This is recommended for item use interactions.
*
* <p>In creative mode, {@link #withInitial(ItemStack)} is used to avoid modifying the item in hand.
* Otherwise, {@link #ofPlayerHand} is used.
*/
static ContainerItemContext forPlayerInteraction(PlayerEntity player, Hand hand) {
if (player.getAbilities().creativeMode) {
return withInitial(player.getStackInHand(hand));
} else {
return ofPlayerHand(player, hand);
}
}
/**
* Return a context for the passed player's hand.
*/
static ContainerItemContext ofPlayerHand(PlayerEntity player, Hand hand) {
return new PlayerContainerItemContext(player, hand);

View file

@ -117,7 +117,7 @@ public final class FluidStorage {
* This means that per-item combined providers registered through {@code combinedItemApiProvider} DO NOT prevent these general providers from running,
* however regular providers registered through {@code ItemApiLookup#register...} that return a non-null API instance DO prevent it.
*/
public static Event<CombinedItemApiProvider> GENERAL_COMBINED_PROVIDER = CombinedProvidersImpl.createEvent(false);
public static final Event<CombinedItemApiProvider> GENERAL_COMBINED_PROVIDER = CombinedProvidersImpl.createEvent(false);
@FunctionalInterface
public interface CombinedItemApiProvider {

View file

@ -0,0 +1,109 @@
/*
* 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;
import org.jetbrains.annotations.ApiStatus;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.fluid.Fluids;
import net.minecraft.item.Item;
import net.minecraft.item.Items;
import net.minecraft.sound.SoundCategory;
import net.minecraft.sound.SoundEvent;
import net.minecraft.sound.SoundEvents;
import net.minecraft.util.Hand;
import net.fabricmc.fabric.api.transfer.v1.context.ContainerItemContext;
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;
/**
* Helper functions to work with fluid storages.
*
* <p><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 FluidStorageUtil {
/**
* Try to make the item in a player hand "interact" with a fluid storage.
* This can be used when a player right-clicks a tank, for example.
*
* <p>More specifically, this function tries to find a fluid storing item in the player's hand.
* Then, it tries to fill that item from the storage. If that fails, it tries to fill the storage from that item.
*
* <p>Only up to one fluid variant will be moved, and the corresponding emptying/filling sound will be played.
* In creative mode, the player's inventory will not be modified.
*
* @param storage The storage that the player is interacting with.
* @param player The player.
* @param hand The hand that the player used.
* @return True if some fluid was moved.
*/
public static boolean interactWithFluidStorage(Storage<FluidVariant> storage, PlayerEntity player, Hand hand) {
// Check if hand is a fluid container.
Storage<FluidVariant> handStorage = ContainerItemContext.forPlayerInteraction(player, hand).find(FluidStorage.ITEM);
if (handStorage == null) return false;
// Try to fill hand first, otherwise try to empty it.
Item handItem = player.getStackInHand(hand).getItem();
return moveWithSound(storage, handStorage, player, true, handItem) || moveWithSound(handStorage, storage, player, false, handItem);
}
private static boolean moveWithSound(Storage<FluidVariant> from, Storage<FluidVariant> to, PlayerEntity player, boolean fill, Item handItem) {
for (StorageView<FluidVariant> view : from) {
if (view.isResourceBlank()) continue;
FluidVariant resource = view.getResource();
long maxExtracted;
// check how much can be extracted
try (Transaction extractionTestTransaction = Transaction.openOuter()) {
maxExtracted = view.extract(resource, Long.MAX_VALUE, extractionTestTransaction);
extractionTestTransaction.abort();
}
try (Transaction transferTransaction = Transaction.openOuter()) {
// check how much can be inserted
long accepted = to.insert(resource, maxExtracted, transferTransaction);
// extract it, or rollback if the amounts don't match
if (accepted > 0 && view.extract(resource, accepted, transferTransaction) == accepted) {
transferTransaction.commit();
SoundEvent sound = fill ? FluidVariantAttributes.getFillSound(resource) : FluidVariantAttributes.getEmptySound(resource);
// Temporary workaround to use the correct sound for water bottles.
// TODO: Look into providing a proper item-aware fluid sound API.
if (resource.isOf(Fluids.WATER)) {
if (fill && handItem == Items.GLASS_BOTTLE) sound = SoundEvents.ITEM_BOTTLE_FILL;
if (!fill && handItem == Items.POTION) sound = SoundEvents.ITEM_BOTTLE_EMPTY;
}
player.playSound(sound, SoundCategory.BLOCKS, 1, 1);
return true;
}
}
}
return false;
}
private FluidStorageUtil() {
}
}

View file

@ -21,12 +21,15 @@ import java.util.Optional;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
import net.minecraft.block.Blocks;
import net.minecraft.fluid.FlowableFluid;
import net.minecraft.fluid.Fluid;
import net.minecraft.fluid.Fluids;
import net.minecraft.sound.SoundEvent;
import net.minecraft.sound.SoundEvents;
import net.minecraft.text.Style;
import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
import net.minecraft.world.World;
import net.fabricmc.fabric.api.lookup.v1.custom.ApiProviderMap;
@ -42,6 +45,7 @@ import net.fabricmc.fabric.impl.transfer.TransferApiImpl;
public final class FluidVariantAttributes {
private static final ApiProviderMap<Fluid, FluidVariantAttributeHandler> HANDLERS = ApiProviderMap.create();
private static final FluidVariantAttributeHandler DEFAULT_HANDLER = new FluidVariantAttributeHandler() { };
private static volatile boolean coloredVanillaFluidNames = false;
private FluidVariantAttributes() {
}
@ -55,6 +59,13 @@ public final class FluidVariantAttributes {
}
}
/**
* Enable blue- and red-colored names for water and lava respectively.
*/
public static void enableColoredVanillaFluidNames() {
coloredVanillaFluidNames = true;
}
/**
* Return the attribute handler for the passed fluid, if available, and {@code null} otherwise.
*/
@ -157,12 +168,30 @@ public final class FluidVariantAttributes {
static {
register(Fluids.WATER, new FluidVariantAttributeHandler() {
@Override
public Text getName(FluidVariant fluidVariant) {
if (coloredVanillaFluidNames) {
return Blocks.WATER.getName().setStyle(Style.EMPTY.withColor(Formatting.BLUE));
} else {
return FluidVariantAttributeHandler.super.getName(fluidVariant);
}
}
@Override
public Optional<SoundEvent> getEmptySound(FluidVariant variant) {
return Optional.of(SoundEvents.ITEM_BUCKET_EMPTY);
}
});
register(Fluids.LAVA, new FluidVariantAttributeHandler() {
@Override
public Text getName(FluidVariant fluidVariant) {
if (coloredVanillaFluidNames) {
return Blocks.LAVA.getName().setStyle(Style.EMPTY.withColor(Formatting.RED));
} else {
return FluidVariantAttributeHandler.super.getName(fluidVariant);
}
}
@Override
public Optional<SoundEvent> getFillSound(FluidVariant variant) {
return Optional.of(SoundEvents.ITEM_BUCKET_FILL_LAVA);

View file

@ -0,0 +1,78 @@
/*
* 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 java.util.Objects;
import org.jetbrains.annotations.ApiStatus;
import net.minecraft.nbt.NbtCompound;
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.SingleVariantStorage;
/**
* A storage that can store a single fluid variant at any given time.
* Implementors should at least override {@link #getCapacity(FluidVariant)},
* and probably {@link #onFinalCommit} as well for {@code markDirty()} and similar calls.
*
* <p>This is a convenient specialization of {@link SingleVariantStorage} for fluids that additionally offers methods
* to read the contents of the storage from NBT.
*
* <p><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 abstract class SingleFluidStorage extends SingleVariantStorage<FluidVariant> {
/**
* Create a fluid storage with a fixed capacity and a change handler.
*
* @param capacity Fixed capacity of the fluid storage. Must be nonnegative.
* @param onChange Change handler, generally for {@code markDirty()} or similar calls. May not be null.
*/
public static SingleFluidStorage withFixedCapacity(long capacity, Runnable onChange) {
StoragePreconditions.notNegative(capacity);
Objects.requireNonNull(onChange, "onChange may not be null");
return new SingleFluidStorage() {
@Override
protected long getCapacity(FluidVariant variant) {
return capacity;
}
@Override
protected void onFinalCommit() {
onChange.run();
}
};
}
@Override
protected final FluidVariant getBlankVariant() {
return FluidVariant.blank();
}
/**
* Simple implementation of reading from NBT, to match what is written by {@link #writeNbt}.
* Other formats are allowed, this is just a suggestion.
*/
public void readNbt(NbtCompound nbt) {
variant = FluidVariant.fromNbt(nbt.getCompound("variant"));
amount = nbt.getLong("amount");
}
}

View file

@ -0,0 +1,52 @@
/*
* 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.item.base;
import org.jetbrains.annotations.ApiStatus;
import net.minecraft.nbt.NbtCompound;
import net.fabricmc.fabric.api.transfer.v1.item.ItemVariant;
import net.fabricmc.fabric.api.transfer.v1.storage.base.SingleVariantStorage;
/**
* A storage that can store a single item variant at any given time.
* Implementors should at least override {@link #getCapacity(ItemVariant)},
* and probably {@link #onFinalCommit} as well for {@code markDirty()} and similar calls.
*
* <p>This is a convenient specialization of {@link SingleVariantStorage} for items that additionally offers methods
* to read the contents of the storage from NBT.
*
* <p><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 abstract class SingleItemStorage extends SingleVariantStorage<ItemVariant> {
@Override
protected final ItemVariant getBlankVariant() {
return ItemVariant.blank();
}
/**
* Simple implementation of reading from NBT, to match what is written by {@link #writeNbt}.
* Other formats are allowed, this is just a suggestion.
*/
public void readNbt(NbtCompound nbt) {
variant = ItemVariant.fromNbt(nbt.getCompound("variant"));
amount = nbt.getLong("amount");
}
}

View file

@ -159,18 +159,23 @@ public interface Storage<T> extends Iterable<StorageView<T>> {
* If returning the requested view would require iteration through a potentially large number of views,
* {@code null} should be returned instead.
*
* <p>The returned view is tied to the passed transaction,
* and may never be used once the passed transaction has been closed.
*
* @param transaction The transaction to which the scope of the returned storage view is tied.
* @param resource The resource for which a storage view is requested. May be blank, for example to estimate capacity.
* @return A view over this storage for the passed resource, or {@code null} if none is quickly available.
*/
@Nullable
default StorageView<T> exactView(TransactionContext transaction, T resource) {
default StorageView<T> exactView(T resource) {
return null;
}
/**
* @deprecated Use and implement the overload without the transaction parameter.
*/
@Deprecated(forRemoval = true)
@Nullable
default StorageView<T> exactView(TransactionContext transaction, T resource) {
return exactView(resource);
}
/**
* Return an integer representing the current version of this storage instance to allow for fast change detection:
* if the version hasn't changed since the last time, <b>and the storage instance is the same</b>, the storage has the same contents.

View file

@ -23,8 +23,6 @@ import net.fabricmc.fabric.api.transfer.v1.transaction.TransactionContext;
/**
* A view of a single stored resource in a {@link Storage}, for use with {@link Storage#iterator} or {@link Storage#exactView}.
*
* <p>A view is always tied to a specific transaction, and should not be accessed outside of it.
*
* @param <T> The type of the stored resource.
*
* <b>Experimental feature</b>, we reserve the right to remove or change it without further notice.

View file

@ -92,6 +92,14 @@ public interface TransferVariant<O> {
return nbt == null ? null : nbt.copy();
}
/**
* Return a copy of the tag of this variant, or a new compound if this variant doesn't have a tag.
*/
default NbtCompound copyOrCreateNbt() {
NbtCompound nbt = getNbt();
return nbt == null ? new NbtCompound() : nbt.copy();
}
/**
* Save this variant into an NBT compound tag. Subinterfaces should have a matching static {@code fromNbt}.
*

View file

@ -165,6 +165,19 @@ public abstract class FilteringStorage<T> implements Storage<T> {
return Iterators.transform(backingStorage.get().iterator(), FilteringStorageView::new);
}
@Override
@Nullable
public StorageView<T> exactView(T resource) {
StorageView<T> exact = backingStorage.get().exactView(resource);
if (exact != null) {
return new FilteringStorageView(exact);
} else {
return null;
}
}
@Deprecated(forRemoval = true)
@Override
@Nullable
public StorageView<T> exactView(TransactionContext transaction, T resource) {

View file

@ -16,13 +16,17 @@
package net.fabricmc.fabric.api.transfer.v1.storage.base;
import java.util.Collections;
import java.util.Iterator;
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;
/**
* A {@link Storage} that supports insertion, and not extraction.
* A {@link Storage} that supports insertion, and not extraction. By default, it doesn't have any storage view either.
*
* <p><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.
@ -38,4 +42,9 @@ public interface InsertionOnlyStorage<T> extends Storage<T> {
default long extract(T resource, long maxAmount, TransactionContext transaction) {
return 0;
}
@Override
default Iterator<StorageView<T>> iterator() {
return Collections.emptyIterator();
}
}

View file

@ -18,6 +18,8 @@ package net.fabricmc.fabric.api.transfer.v1.storage.base;
import org.jetbrains.annotations.ApiStatus;
import net.minecraft.nbt.NbtCompound;
import net.fabricmc.fabric.api.transfer.v1.storage.StoragePreconditions;
import net.fabricmc.fabric.api.transfer.v1.storage.TransferVariant;
import net.fabricmc.fabric.api.transfer.v1.transaction.TransactionContext;
@ -34,6 +36,9 @@ import net.fabricmc.fabric.api.transfer.v1.transaction.base.SnapshotParticipant;
*
* <p><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.
*
* @see net.fabricmc.fabric.api.transfer.v1.fluid.base.SingleFluidStorage SingleFluidStorage for fluid variants.
* @see net.fabricmc.fabric.api.transfer.v1.item.base.SingleItemStorage SingleItemStorage for item variants.
*/
@ApiStatus.Experimental
public abstract class SingleVariantStorage<T extends TransferVariant<?>> extends SnapshotParticipant<ResourceAmount<T>> implements SingleSlotStorage<T> {
@ -65,6 +70,15 @@ public abstract class SingleVariantStorage<T extends TransferVariant<?>> extends
return true;
}
/**
* Simple implementation of writing to NBT. Other formats are allowed, this is just a convenient suggestion.
*/
// Reading from NBT is not provided because it would need to call the static FluidVariant/ItemVariant.fromNbt
public void writeNbt(NbtCompound nbt) {
nbt.put("variant", variant.toNbt());
nbt.putLong("amount", amount);
}
@Override
public long insert(T insertedVariant, long maxAmount, TransactionContext transaction) {
StoragePreconditions.notBlankNotNegative(insertedVariant, maxAmount);

View file

@ -18,8 +18,6 @@ package net.fabricmc.fabric.impl.transfer.item;
import static net.minecraft.util.math.Direction.UP;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
@ -39,7 +37,6 @@ import net.minecraft.world.WorldEvents;
import net.fabricmc.fabric.api.transfer.v1.item.ItemVariant;
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.storage.base.ExtractionOnlyStorage;
import net.fabricmc.fabric.api.transfer.v1.storage.base.InsertionOnlyStorage;
import net.fabricmc.fabric.api.transfer.v1.storage.base.SingleSlotStorage;
@ -152,11 +149,6 @@ public class ComposterWrapper extends SnapshotParticipant<Float> {
increaseProbability = insertedIncreaseProbability;
return 1;
}
@Override
public Iterator<StorageView<ItemVariant>> iterator() {
return Collections.emptyIterator();
}
}
private class BottomStorage implements ExtractionOnlyStorage<ItemVariant>, SingleSlotStorage<ItemVariant> {

View file

@ -26,12 +26,20 @@ import net.minecraft.block.ShapeContext;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.block.entity.BlockEntityTicker;
import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.text.Text;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.shape.VoxelShape;
import net.minecraft.util.shape.VoxelShapes;
import net.minecraft.world.BlockView;
import net.minecraft.world.World;
import net.fabricmc.fabric.api.transfer.v1.fluid.FluidStorageUtil;
import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariantAttributes;
public class FluidChuteBlock extends Block implements BlockEntityProvider {
public FluidChuteBlock() {
super(Settings.of(Material.METAL));
@ -55,4 +63,20 @@ public class FluidChuteBlock extends Block implements BlockEntityProvider {
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
return SHAPE;
}
@Override
public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) {
if (!world.isClient() && world.getBlockEntity(pos) instanceof FluidChuteBlockEntity chute) {
if (!FluidStorageUtil.interactWithFluidStorage(chute.storage, player, hand)) {
player.sendMessage(
Text.literal("Fluid: ")
.append(FluidVariantAttributes.getName(chute.storage.variant))
.append(", amount: " + chute.storage.amount),
false
);
}
}
return ActionResult.success(world.isClient());
}
}

View file

@ -18,16 +18,18 @@ package net.fabricmc.fabric.test.transfer.ingame;
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
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.fluid.base.SingleFluidStorage;
import net.fabricmc.fabric.api.transfer.v1.storage.StorageUtil;
import net.fabricmc.fabric.api.transfer.v1.storage.Storage;
public class FluidChuteBlockEntity extends BlockEntity {
final SingleFluidStorage storage = SingleFluidStorage.withFixedCapacity(FluidConstants.BUCKET * 4, this::markDirty);
private int tickCounter = 0;
public FluidChuteBlockEntity(BlockPos pos, BlockState state) {
@ -37,12 +39,32 @@ public class FluidChuteBlockEntity extends BlockEntity {
@SuppressWarnings("ConstantConditions")
public void tick() {
if (!world.isClient() && tickCounter++ % 20 == 0) {
Storage<FluidVariant> top = FluidStorage.SIDED.find(world, pos.offset(Direction.UP), Direction.DOWN);
Storage<FluidVariant> bottom = FluidStorage.SIDED.find(world, pos.offset(Direction.DOWN), Direction.UP);
if (top != null && bottom != null) {
StorageUtil.move(top, bottom, fluid -> true, FluidConstants.BUCKET, null);
}
StorageUtil.move(
FluidStorage.SIDED.find(world, pos.offset(Direction.UP), Direction.DOWN),
storage,
fluid -> true,
FluidConstants.BUCKET,
null
);
StorageUtil.move(
storage,
FluidStorage.SIDED.find(world, pos.offset(Direction.DOWN), Direction.UP),
fluid -> true,
FluidConstants.BUCKET,
null
);
}
}
@Override
protected void writeNbt(NbtCompound nbt) {
super.writeNbt(nbt);
storage.writeNbt(nbt);
}
@Override
public void readNbt(NbtCompound nbt) {
super.readNbt(nbt);
storage.readNbt(nbt);
}
}

View file

@ -16,12 +16,8 @@
package net.fabricmc.fabric.test.transfer.ingame;
import java.util.Collections;
import java.util.Iterator;
import net.fabricmc.fabric.api.transfer.v1.item.ItemVariant;
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.TransferVariant;
import net.fabricmc.fabric.api.transfer.v1.storage.base.InsertionOnlyStorage;
import net.fabricmc.fabric.api.transfer.v1.transaction.TransactionContext;
@ -36,9 +32,4 @@ public class TrashingStorage<T extends TransferVariant<?>> implements InsertionO
// Insertion always succeeds.
return maxAmount;
}
@Override
public Iterator<StorageView<T>> iterator() {
return Collections.emptyIterator();
}
}

View file

@ -40,6 +40,7 @@ import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback;
import net.fabricmc.fabric.api.transfer.v1.client.fluid.FluidVariantRendering;
import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant;
import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariantAttributes;
/**
* Renders the water sprite in the top left of the screen, to make sure that it correctly depends on the position.
@ -47,6 +48,8 @@ import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant;
public class FluidVariantRenderTest implements ClientModInitializer {
@Override
public void onInitializeClient() {
FluidVariantAttributes.enableColoredVanillaFluidNames();
HudRenderCallback.EVENT.register((matrices, tickDelta) -> {
PlayerEntity player = MinecraftClient.getInstance().player;
if (player == null) return;