mirror of
https://github.com/FabricMC/fabric.git
synced 2025-04-02 02:00:14 -04:00
Transfer API improvements 4 (#2375)
* 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:
parent
2b0146fe54
commit
8f88597368
17 changed files with 396 additions and 35 deletions
fabric-transfer-api-v1/src
main/java/net/fabricmc/fabric
api/transfer/v1
context
fluid
item/base
storage
impl/transfer/item
testmod/java/net/fabricmc/fabric/test/transfer/ingame
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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() {
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
}
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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}.
|
||||
*
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Reference in a new issue