Re-add fluid variants

The implementations in FluidStack regarding components is a stab for what the future api could be, and will definitely change.

Signed-off-by: shedaniel <daniel@shedaniel.me>
This commit is contained in:
shedaniel
2024-03-02 04:14:46 +09:00
parent 7b65d8da73
commit 8d0fdbdbd1
8 changed files with 281 additions and 190 deletions

View File

@@ -19,29 +19,38 @@
package dev.architectury.fluid;
import com.google.common.collect.Iterators;
import com.mojang.serialization.Codec;
import dev.architectury.hooks.fluid.FluidStackHooks;
import dev.architectury.injectables.annotations.ExpectPlatform;
import net.minecraft.core.Holder;
import net.minecraft.core.component.*;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.Tag;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.chat.Component;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.world.level.material.Fluid;
import net.minecraft.world.level.material.Fluids;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.function.UnaryOperator;
public final class FluidStack {
public final class FluidStack implements DataComponentHolder {
private static final FluidStackAdapter<Object> ADAPTER = adapt(FluidStack::getValue, FluidStack::new);
private static final FluidStack EMPTY = create(Fluids.EMPTY, 0);
public static final Codec<FluidStack> CODEC = ADAPTER.codec();
public static final StreamCodec<RegistryFriendlyByteBuf, FluidStack> STREAM_CODEC = ADAPTER.streamCodec();
private Object value;
private final Object value;
private FluidStack(Supplier<Fluid> fluid, long amount, CompoundTag tag) {
this(ADAPTER.create(fluid, amount, tag));
private FluidStack(Supplier<Fluid> fluid, long amount, DataComponentPatch patch) {
this(ADAPTER.create(fluid, amount, patch));
}
private FluidStack(Object value) {
@@ -57,9 +66,103 @@ public final class FluidStack {
throw new AssertionError();
}
@Override
public DataComponentMap getComponents() {
return new DataComponentMap() {
@Nullable
@Override
public <T> T get(DataComponentType<? extends T> type) {
return getPatch().get(type).orElse(null);
}
@Override
public Set<DataComponentType<?>> keySet() {
return new AbstractSet<>() {
@Override
public Iterator<DataComponentType<?>> iterator() {
return Iterators.transform(getPatch().entrySet().iterator(), Map.Entry::getKey);
}
@Override
public int size() {
return getPatch().entrySet().size();
}
@Override
public boolean contains(Object o) {
if (!(o instanceof DataComponentType<?> type)) return false;
return getPatch().get(type).isPresent();
}
};
}
};
}
public <T> T set(DataComponentType<? super T> dataComponentType, @Nullable T object) {
T previous = (T) get(dataComponentType);
DataComponentPatch.Builder builder = DataComponentPatch.builder();
for (TypedDataComponent<?> component : getComponents()) {
if (component.type() != dataComponentType) {
builder.set(component);
}
}
if (object != null) {
builder.set(dataComponentType, object);
}
setPatch(builder.build());
return previous;
}
@Nullable
public <T, U> T update(DataComponentType<T> dataComponentType, T object, U object2, BiFunction<T, U, T> biFunction) {
return this.set(dataComponentType, biFunction.apply(this.getOrDefault(dataComponentType, object), object2));
}
@Nullable
public <T> T update(DataComponentType<T> dataComponentType, T object, UnaryOperator<T> unaryOperator) {
return this.set(dataComponentType, unaryOperator.apply(this.getOrDefault(dataComponentType, object)));
}
@Nullable
public <T> T remove(DataComponentType<? extends T> dataComponentType) {
return this.set(dataComponentType, null);
}
public void applyComponents(DataComponentPatch dataComponentPatch) {
DataComponentPatch.Builder builder = DataComponentPatch.builder();
for (TypedDataComponent<?> component : getComponents()) {
builder.set(component);
}
for (Map.Entry<DataComponentType<?>, Optional<?>> entry : dataComponentPatch.entrySet()) {
if (entry.getValue().isPresent()) {
//noinspection rawtypes
builder.set((DataComponentType) entry.getKey(), entry.getValue().get());
} else {
builder.remove(entry.getKey());
}
}
setPatch(builder.build());
}
public void applyComponents(DataComponentMap dataComponentMap) {
DataComponentPatch.Builder builder = DataComponentPatch.builder();
for (TypedDataComponent<?> component : getComponents()) {
builder.set(component);
}
for (TypedDataComponent<?> entry : dataComponentMap) {
if (entry.value() != null) {
//noinspection rawtypes
builder.set((DataComponentType) entry.type(), entry.value());
} else {
builder.remove(entry.type());
}
}
setPatch(builder.build());
}
@ApiStatus.Internal
public interface FluidStackAdapter<T> {
T create(Supplier<Fluid> fluid, long amount, CompoundTag tag);
T create(Supplier<Fluid> fluid, long amount, @Nullable DataComponentPatch patch);
Supplier<Fluid> getRawFluidSupplier(T object);
@@ -69,37 +172,51 @@ public final class FluidStack {
void setAmount(T object, long amount);
CompoundTag getTag(T value);
DataComponentPatch getPatch(T value);
void setTag(T value, CompoundTag tag);
void setPatch(T value, DataComponentPatch patch);
T copy(T value);
int hashCode(T value);
Codec<FluidStack> codec();
StreamCodec<RegistryFriendlyByteBuf, FluidStack> streamCodec();
}
public static FluidStack empty() {
return EMPTY;
}
public static FluidStack create(Fluid fluid, long amount, @Nullable CompoundTag tag) {
return create(() -> fluid, amount, tag);
public static FluidStack create(Fluid fluid, long amount, DataComponentPatch patch) {
if (fluid == Fluids.EMPTY || amount <= 0) return empty();
return create(() -> fluid, amount, patch);
}
public static FluidStack create(Fluid fluid, long amount) {
return create(fluid, amount, null);
return create(fluid, amount, DataComponentPatch.EMPTY);
}
public static FluidStack create(Supplier<Fluid> fluid, long amount, @Nullable CompoundTag tag) {
return new FluidStack(fluid, amount, tag);
public static FluidStack create(Supplier<Fluid> fluid, long amount, DataComponentPatch patch) {
if (amount <= 0) return empty();
return new FluidStack(fluid, amount, patch);
}
public static FluidStack create(Supplier<Fluid> fluid, long amount) {
return create(fluid, amount, null);
return create(fluid, amount, DataComponentPatch.EMPTY);
}
public static FluidStack create(Holder<Fluid> fluid, long amount, DataComponentPatch patch) {
return create(fluid.value(), amount, patch);
}
public static FluidStack create(Holder<Fluid> fluid, long amount) {
return create(fluid.value(), amount, DataComponentPatch.EMPTY);
}
public static FluidStack create(FluidStack stack, long amount) {
return create(stack.getRawFluidSupplier(), amount, stack.getTag());
return create(stack.getRawFluidSupplier(), amount, stack.getPatch());
}
public static long bucketAmount() {
@@ -139,50 +256,12 @@ public final class FluidStack {
setAmount(getAmount() - amount);
}
public boolean hasTag() {
return getTag() != null;
public DataComponentPatch getPatch() {
return ADAPTER.getPatch(value);
}
@Nullable
public CompoundTag getTag() {
return ADAPTER.getTag(value);
}
public void setTag(@Nullable CompoundTag tag) {
ADAPTER.setTag(value, tag);
}
public CompoundTag getOrCreateTag() {
CompoundTag tag = getTag();
if (tag == null) {
tag = new CompoundTag();
setTag(tag);
return tag;
}
return tag;
}
@Nullable
public CompoundTag getChildTag(String childName) {
CompoundTag tag = getTag();
if (tag == null)
return null;
return tag.getCompound(childName);
}
public CompoundTag getOrCreateChildTag(String childName) {
CompoundTag tag = getOrCreateTag();
var child = tag.getCompound(childName);
if (!tag.contains(childName, Tag.TAG_COMPOUND)) {
tag.put(childName, child);
}
return child;
}
public void removeChildTag(String childName) {
CompoundTag tag = getTag();
if (tag != null)
tag.remove(childName);
public void setPatch(DataComponentPatch patch) {
ADAPTER.setPatch(value, patch);
}
public Component getName() {
@@ -211,17 +290,17 @@ public final class FluidStack {
}
public boolean isFluidStackEqual(FluidStack other) {
return getFluid() == other.getFluid() && getAmount() == other.getAmount() && isTagEqual(other);
return getFluid() == other.getFluid() && getAmount() == other.getAmount() && isComponentEqual(other);
}
public boolean isFluidEqual(FluidStack other) {
return getFluid() == other.getFluid();
}
public boolean isTagEqual(FluidStack other) {
var tag = getTag();
var otherTag = other.getTag();
return Objects.equals(tag, otherTag);
public boolean isComponentEqual(FluidStack other) {
var patch = getPatch();
var otherPatch = other.getPatch();
return Objects.equals(patch, otherPatch);
}
public static FluidStack read(FriendlyByteBuf buf) {
@@ -242,7 +321,7 @@ public final class FluidStack {
public FluidStack copyWithAmount(long amount) {
if (isEmpty()) return this;
return new FluidStack(getRawFluidSupplier(), amount, getTag());
return new FluidStack(getRawFluidSupplier(), amount, getPatch());
}
@ApiStatus.Internal