From c0c2bd8d259b9ccc55d2111d806220753b9d89bd Mon Sep 17 00:00:00 2001 From: shedaniel Date: Sun, 27 Jun 2021 16:38:33 +0800 Subject: Fix #572 & add getDraggableAcceptingBounds --- .../rei/api/client/favorites/FavoriteEntry.java | 28 ++++++- .../api/client/favorites/FavoriteEntryType.java | 22 ++++- .../api/client/gui/drag/DraggableStackVisitor.java | 97 ++++++++++++++++++++-- .../gui/drag/DraggableStackVisitorWidget.java | 67 ++++++++++++--- .../shedaniel/rei/api/common/entry/EntryStack.java | 10 ++- .../me/shedaniel/rei/impl/ClientInternals.java | 9 +- 6 files changed, 205 insertions(+), 28 deletions(-) (limited to 'api/src/main/java/me') diff --git a/api/src/main/java/me/shedaniel/rei/api/client/favorites/FavoriteEntry.java b/api/src/main/java/me/shedaniel/rei/api/client/favorites/FavoriteEntry.java index 336a80088..856cea841 100644 --- a/api/src/main/java/me/shedaniel/rei/api/client/favorites/FavoriteEntry.java +++ b/api/src/main/java/me/shedaniel/rei/api/client/favorites/FavoriteEntry.java @@ -23,6 +23,8 @@ package me.shedaniel.rei.api.client.favorites; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.Lifecycle; import me.shedaniel.rei.api.client.gui.Renderer; import me.shedaniel.rei.api.common.entry.EntryStack; import me.shedaniel.rei.impl.ClientInternals; @@ -44,16 +46,29 @@ public abstract class FavoriteEntry { private final UUID uuid = UUID.randomUUID(); public static FavoriteEntry delegate(Supplier supplier, @Nullable Supplier toJson) { + return delegateResult(() -> DataResult.success(supplier.get(), Lifecycle.stable()), toJson); + } + + public static FavoriteEntry delegateResult(Supplier> supplier, @Nullable Supplier toJson) { return ClientInternals.delegateFavoriteEntry(supplier, toJson); } @Nullable public static FavoriteEntry read(CompoundTag object) { + return readResult(object).result().orElse(null); + } + + public static DataResult readResult(CompoundTag object) { return ClientInternals.favoriteEntryFromJson(object); } + public static FavoriteEntry readDelegated(CompoundTag object) { + CompoundTag copy = object.copy(); + return delegateResult(() -> readResult(object), () -> copy); + } + public static FavoriteEntry fromEntryStack(EntryStack stack) { - return delegate(() -> FavoriteEntryType.registry().get(FavoriteEntryType.ENTRY_STACK).fromArgs(stack), null); + return delegateResult(() -> FavoriteEntryType.registry().get(FavoriteEntryType.ENTRY_STACK).fromArgsResult(stack), null); } public static boolean isEntryInvalid(@Nullable FavoriteEntry entry) { @@ -89,9 +104,14 @@ public abstract class FavoriteEntry { public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof FavoriteEntry that)) return false; - FavoriteEntry unwrapped = getUnwrapped(); - FavoriteEntry thatUnwrapped = that.getUnwrapped(); - return unwrapped == thatUnwrapped || unwrapped.isSame(thatUnwrapped); + try { + FavoriteEntry unwrapped = getUnwrapped(); + FavoriteEntry thatUnwrapped = that.getUnwrapped(); + return unwrapped == thatUnwrapped || unwrapped.isSame(thatUnwrapped); + } catch (Throwable throwable) { + throwable.printStackTrace(); + return false; + } } @Override diff --git a/api/src/main/java/me/shedaniel/rei/api/client/favorites/FavoriteEntryType.java b/api/src/main/java/me/shedaniel/rei/api/client/favorites/FavoriteEntryType.java index fd05c2bbd..7c60253b9 100644 --- a/api/src/main/java/me/shedaniel/rei/api/client/favorites/FavoriteEntryType.java +++ b/api/src/main/java/me/shedaniel/rei/api/client/favorites/FavoriteEntryType.java @@ -23,6 +23,8 @@ package me.shedaniel.rei.api.client.favorites; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.Lifecycle; import me.shedaniel.rei.api.client.plugins.REIClientPlugin; import me.shedaniel.rei.api.common.entry.EntryStack; import me.shedaniel.rei.api.common.plugins.PluginManager; @@ -48,9 +50,25 @@ public interface FavoriteEntryType { return PluginManager.getClientInstance().get(FavoriteEntryType.Registry.class); } - T read(CompoundTag object); + @ApiStatus.ScheduledForRemoval + @Deprecated + default T read(CompoundTag object) { + throw new UnsupportedOperationException("Implementation of FavoriteEntryType must override #read or #readResult"); + } + + default DataResult readResult(CompoundTag object) { + return DataResult.success(read(object), Lifecycle.stable()); + } - T fromArgs(Object... args); + @ApiStatus.ScheduledForRemoval + @Deprecated + default T fromArgs(Object... args) { + throw new UnsupportedOperationException("Implementation of FavoriteEntryType must override #fromArgs or #fromArgsResult"); + } + + default DataResult fromArgsResult(Object... args) { + return DataResult.success(fromArgs(args), Lifecycle.stable()); + } CompoundTag save(T entry, CompoundTag tag); diff --git a/api/src/main/java/me/shedaniel/rei/api/client/gui/drag/DraggableStackVisitor.java b/api/src/main/java/me/shedaniel/rei/api/client/gui/drag/DraggableStackVisitor.java index a3eeebdbf..ae973be16 100644 --- a/api/src/main/java/me/shedaniel/rei/api/client/gui/drag/DraggableStackVisitor.java +++ b/api/src/main/java/me/shedaniel/rei/api/client/gui/drag/DraggableStackVisitor.java @@ -23,10 +23,16 @@ package me.shedaniel.rei.api.client.gui.drag; +import me.shedaniel.math.Rectangle; import net.minecraft.client.gui.screens.Screen; +import net.minecraft.world.phys.shapes.Shapes; +import net.minecraft.world.phys.shapes.VoxelShape; +import org.jetbrains.annotations.ApiStatus; import java.util.Optional; import java.util.function.Supplier; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; /** * A visitor for accepting {@link DraggableStack} to the screen. @@ -45,19 +51,60 @@ public interface DraggableStackVisitor extends Comparable visitDraggedStack(DraggingContext context, DraggableStack stack) { + public boolean acceptDraggedStack(DraggingContext context, DraggableStack stack) { for (DraggableStackVisitor visitor : visitors.get()) { if (visitor.isHandingScreen(context.getScreen())) { - Optional acceptor = visitor.visitDraggedStack(context, stack); - if (acceptor.isPresent()) return acceptor; + boolean visited = visitor.acceptDraggedStack(context, stack); + if (visited) return true; } } - return Optional.empty(); + return false; + } + + @Override + public Stream getDraggableAcceptingBounds(DraggingContext context, DraggableStack stack) { + return StreamSupport.stream(visitors.get().spliterator(), false) + .filter(visitor -> visitor.isHandingScreen(context.getScreen())) + .flatMap(visitor -> visitor.getDraggableAcceptingBounds(context, stack)); } }; } - Optional visitDraggedStack(DraggingContext context, DraggableStack stack); + @Deprecated(forRemoval = true) + @ApiStatus.ScheduledForRemoval + default Optional visitDraggedStack(DraggingContext context, DraggableStack stack) { + return Optional.empty(); + } + + /** + * Accepts a dragged stack, implementations of this function should check if the {@code context} is within + * boundaries of the accepting boundaries. + * + * @param context the context of the current dragged stack on the overlay + * @param stack the stack being dragged + * @return whether the stack is accepted by the visitor + */ + default boolean acceptDraggedStack(DraggingContext context, DraggableStack stack) { + Optional acceptor = visitDraggedStack(context, stack); + if (acceptor.isPresent()) { + acceptor.get().accept(stack); + return true; + } else { + return false; + } + } + + /** + * Returns the accepting bounds for the dragging stack, this should only be called once on drag. + * The bounds are used to overlay to indicate to the users that the area is accepting entries. + * + * @param context the context of the current dragged stack on the overlay + * @param stack the stack being dragged + * @return the accepting bounds for the dragging stack in a stream + */ + default Stream getDraggableAcceptingBounds(DraggingContext context, DraggableStack stack) { + return Stream.empty(); + } boolean isHandingScreen(R screen); @@ -83,4 +130,44 @@ public interface DraggableStackVisitor extends Comparable bounds) { + VoxelShape shape = StreamSupport.stream(bounds.spliterator(), false) + .map(BoundsProvider::fromRectangle) + .reduce(Shapes.empty(), Shapes::or); + return ofShape(shape); + } + + static BoundsProvider ofShape(VoxelShape shape) { + return () -> shape; + } + + static BoundsProvider ofShapes(Iterable shapes) { + VoxelShape shape = StreamSupport.stream(shapes.spliterator(), false) + .reduce(Shapes.empty(), Shapes::or); + return ofShape(shape); + } + + static BoundsProvider empty() { + return Shapes::empty; + } + + static BoundsProvider concat(Iterable providers) { + return () -> StreamSupport.stream(providers.spliterator(), false) + .map(BoundsProvider::bounds) + .reduce(Shapes.empty(), Shapes::or); + } + + VoxelShape bounds(); + } } diff --git a/api/src/main/java/me/shedaniel/rei/api/client/gui/drag/DraggableStackVisitorWidget.java b/api/src/main/java/me/shedaniel/rei/api/client/gui/drag/DraggableStackVisitorWidget.java index e1cd311d4..7bb813d4d 100644 --- a/api/src/main/java/me/shedaniel/rei/api/client/gui/drag/DraggableStackVisitorWidget.java +++ b/api/src/main/java/me/shedaniel/rei/api/client/gui/drag/DraggableStackVisitorWidget.java @@ -24,37 +24,79 @@ package me.shedaniel.rei.api.client.gui.drag; import net.minecraft.client.gui.screens.Screen; +import org.jetbrains.annotations.ApiStatus; import java.util.Optional; import java.util.function.Function; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; /** * An interface to be implemented on {@link me.shedaniel.rei.api.client.gui.widgets.Widget} to accept * incoming {@link DraggableStack}. */ -@FunctionalInterface public interface DraggableStackVisitorWidget { static DraggableStackVisitorWidget from(Function, Iterable> providers) { - return (context, stack) -> { - for (DraggableStackVisitorWidget visitor : providers.apply(context)) { - Optional acceptor = visitor.visitDraggedStack(context, stack); - if (acceptor.isPresent()) return acceptor; + return new DraggableStackVisitorWidget() { + @Override + public boolean acceptDraggedStack(DraggingContext context, DraggableStack stack) { + return StreamSupport.stream(providers.apply(context).spliterator(), false) + .anyMatch(visitor -> visitor.acceptDraggedStack(context, stack)); + } + + @Override + public Stream getDraggableAcceptingBounds(DraggingContext context, DraggableStack stack) { + return StreamSupport.stream(providers.apply(context).spliterator(), false) + .flatMap(visitor -> visitor.getDraggableAcceptingBounds(context, stack)); } - return Optional.empty(); }; } - Optional visitDraggedStack(DraggingContext context, DraggableStack stack); + @ApiStatus.ScheduledForRemoval + @Deprecated(forRemoval = true) + default Optional visitDraggedStack(DraggingContext context, DraggableStack stack) { + return Optional.empty(); + } + + /** + * Accepts a dragged stack, implementations of this function should check if the {@code context} is within + * boundaries of the widget. + * + * @param context the context of the current dragged stack on the overlay + * @param stack the stack being dragged + * @return whether the stack is accepted by the widget + */ + default boolean acceptDraggedStack(DraggingContext context, DraggableStack stack) { + Optional acceptor = visitDraggedStack(context, stack); + if (acceptor.isPresent()) { + acceptor.get().accept(stack); + return true; + } else { + return false; + } + } + + /** + * Returns the accepting bounds for the dragging stack, this should only be called once on drag. + * The bounds are used to overlay to indicate to the users that the widget is accepting entries. + * + * @param context the context of the current dragged stack on the overlay + * @param stack the stack being dragged + * @return the accepting bounds for the dragging stack in a stream + */ + default Stream getDraggableAcceptingBounds(DraggingContext context, DraggableStack stack) { + return Stream.empty(); + } static DraggableStackVisitor toVisitor(DraggableStackVisitorWidget widget) { return toVisitor(widget, 0.0); } static DraggableStackVisitor toVisitor(DraggableStackVisitorWidget widget, double priority) { - return new DraggableStackVisitor() { + return new DraggableStackVisitor<>() { @Override - public Optional visitDraggedStack(DraggingContext context, DraggableStack stack) { - return widget.visitDraggedStack(context, stack); + public boolean acceptDraggedStack(DraggingContext context, DraggableStack stack) { + return widget.acceptDraggedStack(context, stack); } @Override @@ -62,6 +104,11 @@ public interface DraggableStackVisitorWidget { return true; } + @Override + public Stream getDraggableAcceptingBounds(DraggingContext context, DraggableStack stack) { + return widget.getDraggableAcceptingBounds(context, stack); + } + @Override public double getPriority() { return priority; diff --git a/api/src/main/java/me/shedaniel/rei/api/common/entry/EntryStack.java b/api/src/main/java/me/shedaniel/rei/api/common/entry/EntryStack.java index 9ac571bdb..76ff50f98 100644 --- a/api/src/main/java/me/shedaniel/rei/api/common/entry/EntryStack.java +++ b/api/src/main/java/me/shedaniel/rei/api/common/entry/EntryStack.java @@ -77,15 +77,19 @@ public interface EntryStack extends TextRepresentable, Renderer { @Nullable default CompoundTag save() { - EntrySerializer serializer = getDefinition().getSerializer(); - if (serializer != null && serializer.supportSaving()) { - CompoundTag tag = serializer.save(this, getValue()); + if (supportSaving()) { + CompoundTag tag = getDefinition().getSerializer().save(this, getValue()); tag.putString("type", getType().getId().toString()); return tag; } throw new UnsupportedOperationException(getType().getId() + " does not support serialization!"); } + default boolean supportSaving() { + EntrySerializer serializer = getDefinition().getSerializer(); + return serializer != null && serializer.supportSaving(); + } + @Nullable @Environment(EnvType.CLIENT) Tooltip getTooltip(Point mouse, boolean appendModName); diff --git a/api/src/main/java/me/shedaniel/rei/impl/ClientInternals.java b/api/src/main/java/me/shedaniel/rei/impl/ClientInternals.java index daccb744d..d9cb5eaa8 100644 --- a/api/src/main/java/me/shedaniel/rei/impl/ClientInternals.java +++ b/api/src/main/java/me/shedaniel/rei/impl/ClientInternals.java @@ -23,6 +23,7 @@ package me.shedaniel.rei.impl; +import com.mojang.serialization.DataResult; import me.shedaniel.math.Point; import me.shedaniel.math.Rectangle; import me.shedaniel.rei.api.client.ClientHelper; @@ -60,8 +61,8 @@ public final class ClientInternals { private static Supplier viewSearchBuilder = ClientInternals::throwNotSetup; private static Supplier> clientPluginManager = ClientInternals::throwNotSetup; private static Supplier> emptyEntryRenderer = ClientInternals::throwNotSetup; - private static BiFunction, Supplier, FavoriteEntry> delegateFavoriteEntry = (supplier, toJson) -> throwNotSetup(); - private static Function favoriteEntryFromJson = (object) -> throwNotSetup(); + private static BiFunction>, Supplier, FavoriteEntry> delegateFavoriteEntry = (supplier, toJson) -> throwNotSetup(); + private static Function> favoriteEntryFromJson = (object) -> throwNotSetup(); private static Function clickAreaHandlerResult = (result) -> throwNotSetup(); private static BiConsumer, TooltipComponent> clientTooltipComponentProvider = (tooltip, result) -> throwNotSetup(); private static BiFunction<@Nullable Point, Collection, Tooltip> tooltipProvider = (point, texts) -> throwNotSetup(); @@ -130,11 +131,11 @@ public final class ClientInternals { return tooltipEntryProvider.apply(component); } - public static FavoriteEntry delegateFavoriteEntry(Supplier supplier, Supplier toJoin) { + public static FavoriteEntry delegateFavoriteEntry(Supplier> supplier, Supplier toJoin) { return delegateFavoriteEntry.apply(supplier, toJoin); } - public static FavoriteEntry favoriteEntryFromJson(CompoundTag tag) { + public static DataResult favoriteEntryFromJson(CompoundTag tag) { return favoriteEntryFromJson.apply(tag); } -- cgit