diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/base/drawable/IKey.java b/src/main/java/com/gregtechceu/gtceu/api/mui/base/drawable/IKey.java index b08bbf96a4b..5c1394a32b7 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/base/drawable/IKey.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/base/drawable/IKey.java @@ -160,6 +160,21 @@ static IKey comp(@NotNull IKey... keys) { * @return dynamic text key */ static IKey dynamic(@NotNull Supplier<@NotNull Component> getter) { + Component c = getter.get(); + if (c instanceof MutableComponent m) { + return dynamicKey(() -> IKey.lang(m)); + } else { + return dynamicKey(() -> IKey.lang(c.copy())); + } + } + + /** + * Creates a dynamic text key. + * + * @param getter key supplier + * @return dynamic text key + */ + static IKey dynamicKey(@NotNull Supplier<@NotNull IKey> getter) { return new DynamicKey(getter); } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/base/value/ISyncOrValue.java b/src/main/java/com/gregtechceu/gtceu/api/mui/base/value/ISyncOrValue.java new file mode 100644 index 00000000000..9ab9466ac16 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/base/value/ISyncOrValue.java @@ -0,0 +1,126 @@ +package com.gregtechceu.gtceu.api.mui.base.value; + +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * An interface that is implemented on {@link IValue} and {@link com.gregtechceu.gtceu.api.mui.value.sync.SyncHandler + * SyncHandler} for easier + * validation and setters. + */ +@ApiStatus.NonExtendable +public interface ISyncOrValue { + + /** + * A sync handler or value representing null. + */ + ISyncOrValue EMPTY = new ISyncOrValue() { + + @Override + public @Nullable T castNullable(Class type) { + return null; + } + + @Override + public boolean isTypeOrEmpty(Class type) { + return true; + } + }; + + /** + * Returns the given sync handler or value or {@link #EMPTY} if null. + * + * @param syncOrValue sync handler or value + * @return a non-null representation of the given sync handler or value + */ + @NotNull + static ISyncOrValue orEmpty(@Nullable ISyncOrValue syncOrValue) { + return syncOrValue != null ? syncOrValue : EMPTY; + } + + /** + * Returns if this sync handler or value is an instance of the given type or if this represents null. This is + * useful, when the value or + * sync handler can be null in the widget. + * + * @param type type to check for + * @return if this sync handler or value is an instance of the type or empty + */ + default boolean isTypeOrEmpty(Class type) { + return type.isAssignableFrom(getClass()); + } + + /** + * Casts this sync handler or value to the given type or null if this isn't a subtype of the given type. + * + * @param type type to cast this sync handle or value to + * @param type to cast to + * @return this cast sync handler or value + */ + @Nullable + @SuppressWarnings("unchecked") + default T castNullable(Class type) { + return type.isAssignableFrom(getClass()) ? (T) this : null; + } + + /** + * Casts this sync handler or value to a {@link IValue IValue<V>} if it is a value handler and the containing + * value is of type + * {@link V} else null. + * + * @param valueType expected type of the containing value + * @param expected type of the containing value + * @return a {@link IValue IValue<V>} if types match or null + */ + @Nullable + default IValue castValueNullable(Class valueType) { + return null; + } + + /** + * Casts this sync handler or value to the given type or throws an exception if this isn't a subtype of the given + * type. + * + * @param type type to cast this sync handle or value to + * @param type to cast to + * @return this cast sync handler or value + * @throws IllegalStateException if this is not a subtype of the given type + */ + default T castOrThrow(Class type) { + T t = castNullable(type); + if (t == null) { + if (!isSyncHandler() && !isValueHandler()) { + throw new IllegalStateException("Empty sync handler or value can't be used for anything."); + } + String self = isSyncHandler() ? "sync handler" : "value"; + throw new IllegalStateException("Can't cast " + self + " of type '" + getClass().getSimpleName() + + "' to type '" + type.getSimpleName() + "'."); + } + return t; + } + + /** + * Returns if the containing value of this is of the given type. If this is not a value it will always return false. + * + * @param type expected value type + * @return if the containing value of this is of the given type + */ + default boolean isValueOfType(Class type) { + return false; + } + + /** + * @return if this is a sync handler (false if this represents null) + */ + default boolean isSyncHandler() { + return false; + } + + /** + * @return if this is a value handler (false if this represents null) + */ + default boolean isValueHandler() { + return false; + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/base/value/IValue.java b/src/main/java/com/gregtechceu/gtceu/api/mui/base/value/IValue.java index e607f6e7a97..2e3e0f9fe77 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/base/value/IValue.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/base/value/IValue.java @@ -5,7 +5,7 @@ * * @param value type */ -public interface IValue { +public interface IValue extends ISyncOrValue { /** * Gets the current value. @@ -20,4 +20,21 @@ public interface IValue { * @param value new value */ void setValue(T value); + + Class getValueType(); + + default boolean isValueOfType(Class type) { + return type.isAssignableFrom(getValueType()); + } + + @SuppressWarnings("unchecked") + @Override + default IValue castValueNullable(Class valueType) { + return isValueOfType(valueType) ? (IValue) this : null; + } + + @Override + default boolean isValueHandler() { + return true; + } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/base/widget/ISynced.java b/src/main/java/com/gregtechceu/gtceu/api/mui/base/widget/ISynced.java index 7140b2710f5..56324bacff7 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/base/widget/ISynced.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/base/widget/ISynced.java @@ -1,9 +1,11 @@ package com.gregtechceu.gtceu.api.mui.base.widget; +import com.gregtechceu.gtceu.api.mui.base.value.ISyncOrValue; import com.gregtechceu.gtceu.api.mui.value.sync.GenericSyncValue; import com.gregtechceu.gtceu.api.mui.value.sync.ModularSyncManager; import com.gregtechceu.gtceu.api.mui.value.sync.SyncHandler; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -28,25 +30,58 @@ default W getThis() { * Called when this widget gets initialised or when this widget is added to the gui * * @param syncManager sync manager - * @param late true if this is called some time after the widget tree of the parent has been initialised + * @param late if this is called at any point after the panel this widget belongs to opened */ void initialiseSyncHandler(ModularSyncManager syncManager, boolean late); /** - * Checks if the received sync handler is valid for this widget. - * Synced widgets must override this! - * - * @param syncHandler received sync handler - * @return true if sync handler is valid + * @deprecated use {@link #isValidSyncOrValue(ISyncOrValue)} */ + @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") + @Deprecated default boolean isValidSyncHandler(SyncHandler syncHandler) { return false; } + /** + * Returns if the given value or sync handler is valid for this widget. This is usually a call to + * {@link ISyncOrValue#isTypeOrEmpty(Class)}. If the widget must specify a value (disallow null) instanceof check + * can be used. You can + * check for primitive types which don't have a dedicated {@link com.gregtechceu.gtceu.api.mui.base.value.IValue + * IValue} interface with + * {@link ISyncOrValue#isValueOfType(Class)}. + * + * @param syncOrValue a sync handler or a value, but never null + * @return if the value or sync handler is valid for this class + */ + default boolean isValidSyncOrValue(@NotNull ISyncOrValue syncOrValue) { + return !(syncOrValue instanceof SyncHandler syncHandler) || isValidSyncHandler(syncHandler); + } + + /** + * Checks if the given sync handler is valid for this widget and throws an exception if not. + * Override {@link #isValidSyncHandler(SyncHandler)} + * + * @param syncHandler given sync handler + * @throws IllegalStateException if the given sync handler is invalid for this widget. + */ + @ApiStatus.NonExtendable + default void checkValidSyncOrValue(ISyncOrValue syncHandler) { + if (!isValidSyncOrValue(syncHandler)) { + throw new IllegalStateException( + "SyncHandler of type '" + syncHandler.getClass().getSimpleName() + "' is not valid " + + "for widget '" + this + "'."); + } + } + + @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") + @Deprecated default T castIfTypeElseNull(SyncHandler syncHandler, Class clazz) { return castIfTypeElseNull(syncHandler, clazz, null); } + @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") + @Deprecated @SuppressWarnings("unchecked") default T castIfTypeElseNull(SyncHandler syncHandler, Class clazz, @Nullable Consumer setup) { if (syncHandler != null && clazz.isAssignableFrom(syncHandler.getClass())) { @@ -57,10 +92,14 @@ default T castIfTypeElseNull(SyncHandler syncHandler, Class clazz, @Nulla return null; } + @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") + @Deprecated default GenericSyncValue castIfTypeGenericElseNull(SyncHandler syncHandler, Class clazz) { return castIfTypeGenericElseNull(syncHandler, clazz, null); } + @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") + @Deprecated default GenericSyncValue castIfTypeGenericElseNull(SyncHandler syncHandler, Class clazz, @Nullable Consumer> setup) { if (syncHandler instanceof GenericSyncValue genericSyncValue && genericSyncValue.isOfType(clazz)) { diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/base/widget/IWidget.java b/src/main/java/com/gregtechceu/gtceu/api/mui/base/widget/IWidget.java index a21924ecd10..a9af3f54904 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/base/widget/IWidget.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/base/widget/IWidget.java @@ -107,7 +107,7 @@ default void draw(ModularGuiContext context) { void drawForeground(ModularGuiContext context); default void transform(IViewportStack stack) { - stack.translate(getArea().rx, getArea().ry, getArea().getPanelLayer() * 20); + stack.translate(getArea().rx, getArea().ry, 0); } default Object getAdditionalHoverInfo(IViewportStack viewportStack, int mouseX, int mouseY) { diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/drawable/text/DynamicKey.java b/src/main/java/com/gregtechceu/gtceu/api/mui/drawable/text/DynamicKey.java index a3292564774..abb02fb4648 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/drawable/text/DynamicKey.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/drawable/text/DynamicKey.java @@ -1,29 +1,41 @@ package com.gregtechceu.gtceu.api.mui.drawable.text; -import net.minecraft.network.chat.Component; +import com.gregtechceu.gtceu.api.mui.base.drawable.IKey; + import net.minecraft.network.chat.MutableComponent; -import java.util.Objects; +import org.jetbrains.annotations.Nullable; + import java.util.function.Supplier; public class DynamicKey extends BaseKey { - private final Supplier supplier; - - public DynamicKey(Supplier supplier) { - Objects.requireNonNull(supplier.get(), "IKey returns a null string!"); - this.supplier = () -> { - Component c = supplier.get(); - if (c instanceof MutableComponent m) { - return m; - } else { - return c.copy(); - } - }; + private final Supplier supplier; + + public DynamicKey(Supplier supplier) { + // Objects.requireNonNull(supplier.get(), "IKey returns a null string!"); + this.supplier = supplier; } @Override public MutableComponent get() { - return this.supplier.get(); + return toString(false, null); + } + + @Override + public MutableComponent getFormatted(@Nullable FormattingState parentFormatting) { + // formatting is prepended to each key + return toString(true, parentFormatting); + } + + private MutableComponent toString(boolean formatted, @Nullable FormattingState parentFormatting) { + IKey key = this.supplier.get(); + if (key == null) key = IKey.EMPTY; + if (formatted) { + // merge parent formatting and this formatting to no lose info + return key.getFormatted(FormattingState.merge(parentFormatting, getFormatting())); + } else { + return key.get(); + } } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/drawable/text/TextRenderer.java b/src/main/java/com/gregtechceu/gtceu/api/mui/drawable/text/TextRenderer.java index 5c3a0e7494a..ab9a0f9902a 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/drawable/text/TextRenderer.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/drawable/text/TextRenderer.java @@ -244,7 +244,7 @@ protected int getStartY(float height) { protected int getStartY(float maxHeight, float height) { if (this.alignment.y > 0 && maxHeight > 0 && height != maxHeight) { - return (int) (this.y + (maxHeight * this.alignment.y) - height * this.alignment.y); + return this.y + Math.round(maxHeight * this.alignment.y) - Math.round(height * this.alignment.y); } return this.y; } @@ -255,7 +255,8 @@ protected int getStartX(float lineWidth) { protected int getStartX(float maxWidth, float lineWidth) { if (this.alignment.x > 0 && maxWidth > 0) { - return Math.max(this.x, (int) (this.x + (maxWidth * this.alignment.x) - lineWidth * this.alignment.x)); + return Math.max(this.x, + this.x + Math.round(maxWidth * this.alignment.x) - Math.round(lineWidth * this.alignment.x)); } return this.x; } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/factory/GuiData.java b/src/main/java/com/gregtechceu/gtceu/api/mui/factory/GuiData.java index 9ab5628414c..25ecd015fd3 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/factory/GuiData.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/factory/GuiData.java @@ -7,6 +7,7 @@ import net.minecraft.world.level.Level; import lombok.Getter; +import org.jetbrains.annotations.NotNull; import java.util.Objects; @@ -21,10 +22,11 @@ */ public class GuiData { + @NotNull @Getter private final Player player; - public GuiData(Player player) { + public GuiData(@NotNull Player player) { this.player = Objects.requireNonNull(player); } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/factory/GuiManager.java b/src/main/java/com/gregtechceu/gtceu/api/mui/factory/GuiManager.java index f251d4ae882..74a4c355c51 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/factory/GuiManager.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/factory/GuiManager.java @@ -5,7 +5,6 @@ import com.gregtechceu.gtceu.api.mui.base.MCHelper; import com.gregtechceu.gtceu.api.mui.base.UIFactory; import com.gregtechceu.gtceu.api.mui.base.XeiSettings; -import com.gregtechceu.gtceu.api.mui.value.sync.ModularSyncManager; import com.gregtechceu.gtceu.api.mui.value.sync.PanelSyncManager; import com.gregtechceu.gtceu.api.mui.widget.WidgetTree; import com.gregtechceu.gtceu.client.mui.screen.*; @@ -158,11 +157,15 @@ public static void onTick(TickEvent.ServerTickEvent event) { @SubscribeEvent public static void onOpenContainer(PlayerContainerEvent.Open event) { - if (event.getContainer() instanceof ModularContainerMenu modular) { - ModularSyncManager syncManager = modular.getSyncManager(); - if (syncManager != null) { - syncManager.onOpen(); - } + if (event.getContainer() instanceof ModularContainerMenu modularContainer) { + modularContainer.opened(); + } + } + + @SubscribeEvent + public static void onCloseContainer(PlayerContainerEvent.Close event) { + if (event.getContainer() instanceof ModularContainerMenu modularContainer) { + modularContainer.removed(); } } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/factory/PlayerInventoryGuiData.java b/src/main/java/com/gregtechceu/gtceu/api/mui/factory/PlayerInventoryGuiData.java index 22aa847d96e..a7e96bc257b 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/factory/PlayerInventoryGuiData.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/factory/PlayerInventoryGuiData.java @@ -6,6 +6,7 @@ import net.minecraft.world.item.ItemStack; import lombok.Getter; +import org.jetbrains.annotations.NotNull; /** * GuiData that finds an item in a player bound inventory. This can be the hotbar, main inventory, armor slots, offhand @@ -17,7 +18,8 @@ @Getter public class PlayerInventoryGuiData extends GuiData { - public static PlayerInventoryGuiData of(Player player, InventoryType inventoryType, T context, + public static PlayerInventoryGuiData of(@NotNull Player player, @NotNull InventoryType inventoryType, + T context, int slotIndex) { return new PlayerInventoryGuiData<>(player, inventoryType, context, slotIndex); } @@ -25,6 +27,7 @@ public static PlayerInventoryGuiData of(Player player, InventoryType i /** * Inventory type where the item can be found (player or curios for example). */ + @NotNull private final InventoryType inventoryType; /** * Additional context to find the item. Usually this is null, but for curios it is a string (slot identifier). @@ -35,7 +38,8 @@ public static PlayerInventoryGuiData of(Player player, InventoryType i */ private final int slotIndex; - private PlayerInventoryGuiData(Player player, InventoryType inventoryType, T context, int slotIndex) { + private PlayerInventoryGuiData(@NotNull Player player, @NotNull InventoryType inventoryType, T context, + int slotIndex) { super(player); this.inventoryType = inventoryType; this.context = context; diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/factory/PosGuiData.java b/src/main/java/com/gregtechceu/gtceu/api/mui/factory/PosGuiData.java index 7584ab37b28..c9611fba243 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/factory/PosGuiData.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/factory/PosGuiData.java @@ -7,16 +7,17 @@ import net.minecraft.world.level.block.entity.BlockEntity; import lombok.Getter; +import org.jetbrains.annotations.NotNull; /** * See {@link GuiData} for an explanation for what this is for. */ +@Getter public class PosGuiData extends GuiData { - @Getter private final BlockPos blockPos; - public PosGuiData(Player player, BlockPos blockPos) { + public PosGuiData(@NotNull Player player, BlockPos blockPos) { super(player); this.blockPos = blockPos; } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/factory/SidedPosGuiData.java b/src/main/java/com/gregtechceu/gtceu/api/mui/factory/SidedPosGuiData.java index 15acb493cb3..9d74510ca1a 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/factory/SidedPosGuiData.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/factory/SidedPosGuiData.java @@ -5,16 +5,18 @@ import net.minecraft.world.entity.player.Player; import lombok.Getter; +import org.jetbrains.annotations.NotNull; /** * See {@link GuiData} for an explanation for what this is for. */ +@Getter public class SidedPosGuiData extends PosGuiData { - @Getter + @NotNull private final Direction side; - public SidedPosGuiData(Player player, BlockPos pos, Direction side) { + public SidedPosGuiData(@NotNull Player player, BlockPos pos, @NotNull Direction side) { super(player, pos); this.side = side; } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/BoolValue.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/BoolValue.java index b9af72852d1..6e61a7c0b0f 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/BoolValue.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/BoolValue.java @@ -55,6 +55,11 @@ public void setStringValue(String val) { setBoolValue(Boolean.parseBoolean(val)); } + @Override + public Class getValueType() { + return Boolean.class; + } + public static class Dynamic implements IBoolValue, IIntValue, IStringValue { private final BooleanSupplier getter; @@ -104,5 +109,10 @@ public int getIntValue() { public void setIntValue(int val) { setBoolValue(val == 1); } + + @Override + public Class getValueType() { + return Boolean.class; + } } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/ByteValue.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/ByteValue.java index 497dfe4fba2..7975d4d822f 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/ByteValue.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/ByteValue.java @@ -30,6 +30,11 @@ public void setValue(Byte value) { setByteValue(value); } + @Override + public Class getValueType() { + return Byte.class; + } + public static class Dynamic extends ByteValue { private final Supplier getter; diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/ConstValue.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/ConstValue.java index 26c06c58738..f800dd17ae7 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/ConstValue.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/ConstValue.java @@ -18,4 +18,9 @@ public class ConstValue implements IValue { public ConstValue(T value) { this.value = value; } + + @Override + public Class getValueType() { + return (Class) value.getClass(); + } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/DoubleValue.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/DoubleValue.java index b0fff27770a..7b0f0c9402d 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/DoubleValue.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/DoubleValue.java @@ -65,6 +65,11 @@ public void setFloatValue(float val) { setDoubleValue(val); } + @Override + public Class getValueType() { + return Double.class; + } + public static class Dynamic implements IDoubleValue, IStringValue { private final DoubleSupplier getter; @@ -104,5 +109,10 @@ public Double getValue() { public void setValue(Double value) { setDoubleValue(value); } + + @Override + public Class getValueType() { + return Double.class; + } } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/DynamicValue.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/DynamicValue.java index dc44473f051..8d761f92a91 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/DynamicValue.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/DynamicValue.java @@ -33,4 +33,9 @@ public void setValue(T value) { this.setter.accept(value); } } + + @Override + public Class getValueType() { + return (Class) this.getter.get().getClass(); + } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/EnumValue.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/EnumValue.java index 07782bae821..4dbd5e3fc0b 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/EnumValue.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/EnumValue.java @@ -36,6 +36,11 @@ public void setIntValue(int val) { setValue(this.enumClass.getEnumConstants()[val]); } + @Override + public Class getValueType() { + return this.enumClass; + } + public static class Dynamic> implements IEnumValue, IIntValue { @Getter @@ -68,5 +73,10 @@ public T getValue() { public void setValue(T value) { this.setter.accept(value); } + + @Override + public Class getValueType() { + return this.enumClass; + } } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/FloatValue.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/FloatValue.java index 62aeb7dbb35..d4b2fa42553 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/FloatValue.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/FloatValue.java @@ -64,6 +64,11 @@ public void setStringValue(String val) { setFloatValue(Float.parseFloat(val)); } + @Override + public Class getValueType() { + return Float.class; + } + public static class Dynamic implements IFloatValue, IDoubleValue, IStringValue { private final FloatSupplier getter; @@ -113,5 +118,10 @@ public double getDoubleValue() { public void setDoubleValue(double val) { setFloatValue((float) val); } + + @Override + public Class getValueType() { + return Float.class; + } } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/IntValue.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/IntValue.java index 95b17c07608..ea047eeb909 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/IntValue.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/IntValue.java @@ -64,6 +64,11 @@ public void setStringValue(String val) { setIntValue(Integer.parseInt(val)); } + @Override + public Class getValueType() { + return Integer.class; + } + public static class Dynamic implements IIntValue, IStringValue { private final IntSupplier getter; @@ -103,5 +108,10 @@ public Integer getValue() { public void setValue(Integer value) { setIntValue(value); } + + @Override + public Class getValueType() { + return Integer.class; + } } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/LongValue.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/LongValue.java index fc794ab7a64..a37e3f3ed2b 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/LongValue.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/LongValue.java @@ -64,6 +64,11 @@ public void setIntValue(int val) { setLongValue(val); } + @Override + public Class getValueType() { + return Long.class; + } + public static class Dynamic implements ILongValue, IIntValue, IStringValue { private final LongSupplier getter; @@ -113,5 +118,10 @@ public int getIntValue() { public void setIntValue(int val) { setLongValue(val); } + + @Override + public Class getValueType() { + return Long.class; + } } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/ObjectValue.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/ObjectValue.java index aff7e722698..8b4245eb3ec 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/ObjectValue.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/ObjectValue.java @@ -2,6 +2,8 @@ import com.gregtechceu.gtceu.api.mui.base.value.IValue; +import org.jetbrains.annotations.ApiStatus; + import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; import java.util.function.Supplier; @@ -16,9 +18,18 @@ public static Dynamic wrapAtomic(AtomicReference val) { return new Dynamic<>(val::get, val::set); } + private final Class type; private T value; + public ObjectValue(Class type, T value) { + this.type = type; + this.value = value; + } + + @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") + @Deprecated public ObjectValue(T value) { + this.type = value != null ? (Class) value.getClass() : null; this.value = value; } @@ -32,14 +43,29 @@ public void setValue(T value) { this.value = value; } + @Override + public Class getValueType() { + return this.type != null ? this.type : (Class) this.value.getClass(); + } + public static class Dynamic implements IValue { + private final Class type; private final Supplier getter; private final Consumer setter; + public Dynamic(Class type, Supplier getter, Consumer setter) { + this.type = type; + this.getter = getter; + this.setter = setter; + } + + @Deprecated public Dynamic(Supplier getter, Consumer setter) { this.getter = getter; this.setter = setter; + T value = getter.get(); + this.type = value != null ? (Class) value.getClass() : null; } @Override @@ -51,5 +77,10 @@ public T getValue() { public void setValue(T value) { this.setter.accept(value); } + + @Override + public Class getValueType() { + return this.type != null ? this.type : (Class) this.getter.get().getClass(); + } } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/StringValue.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/StringValue.java index f9dd5b1b8b0..0cd823a111d 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/StringValue.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/StringValue.java @@ -14,7 +14,7 @@ public static Dynamic wrap(IStringValue val) { } public StringValue(String value) { - super(value); + super(String.class, value); } @Override @@ -30,7 +30,7 @@ public void setStringValue(String val) { public static class Dynamic extends ObjectValue.Dynamic implements IStringValue { public Dynamic(Supplier getter, @Nullable Consumer setter) { - super(getter, setter); + super(String.class, getter, setter); } @Override diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/AbstractGenericSyncValue.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/AbstractGenericSyncValue.java new file mode 100644 index 00000000000..6d7875be455 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/AbstractGenericSyncValue.java @@ -0,0 +1,143 @@ +package com.gregtechceu.gtceu.api.mui.value.sync; + +import com.gregtechceu.gtceu.GTCEu; + +import net.minecraft.network.FriendlyByteBuf; + +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.Nullable; + +import java.util.Objects; +import java.util.function.Consumer; +import java.util.function.Supplier; + +public abstract class AbstractGenericSyncValue extends ValueSyncHandler { + + private final Class type; + private final Supplier getter; + private final Consumer setter; + private T cache; + + protected AbstractGenericSyncValue(Class type, Supplier getter, Consumer setter) { + this.getter = Objects.requireNonNull(getter); + this.setter = setter; + this.cache = getter.get(); + if (type == null && this.cache != null) { + type = (Class) this.cache.getClass(); + } + this.type = type; + } + + @Contract("_, null, _, null, _ -> fail") + protected AbstractGenericSyncValue(Class type, @Nullable Supplier clientGetter, + @Nullable Consumer clientSetter, + @Nullable Supplier serverGetter, @Nullable Consumer serverSetter) { + if (clientGetter == null && serverGetter == null) { + throw new NullPointerException("Client or server getter must not be null!"); + } + if (GTCEu.isClientThread()) { + this.getter = clientGetter != null ? clientGetter : serverGetter; + this.setter = clientSetter != null ? clientSetter : serverSetter; + } else { + this.getter = serverGetter != null ? serverGetter : clientGetter; + this.setter = serverSetter != null ? serverSetter : clientSetter; + } + this.cache = this.getter.get(); + if (type == null && this.cache != null) { + type = (Class) this.cache.getClass(); + } + this.type = type; + } + + protected abstract T createDeepCopyOf(T value); + + protected abstract boolean areEqual(T a, T b); + + protected abstract void serialize(FriendlyByteBuf buffer, T value); + + protected abstract T deserialize(FriendlyByteBuf buffer); + + @Override + public T getValue() { + return this.cache; + } + + @Override + public void setValue(T value, boolean setSource, boolean sync) { + this.cache = createDeepCopyOf(value); + if (setSource && this.setter != null) { + this.setter.accept(value); + } + onValueChanged(); + if (sync) sync(); + } + + @Override + public boolean updateCacheFromSource(boolean isFirstSync) { + if (this.getter == null) return false; + T t = this.getter.get(); + if (isFirstSync || !areEqual(this.cache, t)) { + setValue(t, false, false); + return true; + } + return false; + } + + @Override + public void notifyUpdate() { + if (this.getter == null) throw new NullPointerException("Can't notify sync handler with null getter."); + setValue(this.getter.get(), false, true); + } + + @Override + public void write(FriendlyByteBuf buffer) { + serialize(buffer, this.cache); + } + + @Override + public void read(FriendlyByteBuf buffer) { + setValue(deserialize(buffer), true, false); + } + + @SuppressWarnings("unchecked") + @Override + public Class getValueType() { + return (Class) getType(); + } + + @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") + @Deprecated + @SuppressWarnings("unchecked") + public @Nullable Class getType() { + if (this.type != null) return type; + if (this.cache != null) { + return (Class) this.cache.getClass(); + } + T t = this.getter.get(); + if (t != null) { + return (Class) t.getClass(); + } + return null; + } + + @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") + @Deprecated + public boolean isOfType(Class expectedType) { + return isValueOfType(expectedType); + } + + @Override + public boolean isValueOfType(Class expectedType) { + Class type = getValueType(); + if (type == null) { + throw new IllegalStateException("Could not infer type of GenericSyncValue since value is null!"); + } + return expectedType.isAssignableFrom(type); + } + + @SuppressWarnings("unchecked") + public AbstractGenericSyncValue cast() { + return (AbstractGenericSyncValue) this; + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/BigDecimalSyncValue.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/BigDecimalSyncValue.java index 611927b7cc4..50f117c2680 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/BigDecimalSyncValue.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/BigDecimalSyncValue.java @@ -14,7 +14,7 @@ public class BigDecimalSyncValue extends GenericSyncValue implements IStringValue { public BigDecimalSyncValue(@NotNull Supplier getter, @Nullable Consumer setter) { - super(getter, setter, ByteBufAdapters.BIG_DECIMAL, ICopy.immutable()); + super(BigDecimal.class, getter, setter, ByteBufAdapters.BIG_DECIMAL, ICopy.immutable()); } @Override diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/BigIntegerSyncValue.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/BigIntegerSyncValue.java index 5fa36ef2234..cf517aa6833 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/BigIntegerSyncValue.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/BigIntegerSyncValue.java @@ -14,7 +14,7 @@ public class BigIntegerSyncValue extends GenericSyncValue implements IStringValue { public BigIntegerSyncValue(@NotNull Supplier getter, @Nullable Consumer setter) { - super(getter, setter, ByteBufAdapters.BIG_INT, ICopy.immutable()); + super(BigInteger.class, getter, setter, ByteBufAdapters.BIG_INT, ICopy.immutable()); } @Override diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/BooleanSyncValue.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/BooleanSyncValue.java index 43591c6e8d3..d11a9f1c85c 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/BooleanSyncValue.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/BooleanSyncValue.java @@ -74,9 +74,8 @@ public void setBoolValue(boolean value, boolean setSource, boolean sync) { if (setSource && this.setter != null) { this.setter.accept(value); } - if (sync) { - sync(0, this::write); - } + onValueChanged(); + if (sync) sync(); } @Override @@ -112,4 +111,9 @@ public void setStringValue(String value, boolean setSource, boolean sync) { public String getStringValue() { return String.valueOf(this.cache); } + + @Override + public Class getValueType() { + return Boolean.class; + } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/ByteArraySyncValue.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/ByteArraySyncValue.java index 38b73a8e852..aec4ba6a297 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/ByteArraySyncValue.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/ByteArraySyncValue.java @@ -11,6 +11,6 @@ public class ByteArraySyncValue extends GenericSyncValue { public ByteArraySyncValue(@NotNull Supplier getter, @Nullable Consumer setter) { - super(getter, setter, ByteBufAdapters.BYTE_ARR, byte[]::clone); + super(byte[].class, getter, setter, ByteBufAdapters.BYTE_ARR, byte[]::clone); } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/ByteSyncValue.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/ByteSyncValue.java index eb3e3da7acd..56024bfddf1 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/ByteSyncValue.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/ByteSyncValue.java @@ -89,13 +89,17 @@ public void setByteValue(byte value, boolean setSource, boolean sync) { if (setSource && this.setter != null) { this.setter.setByte(value); } - if (sync) { - sync(0, this::write); - } + onValueChanged(); + if (sync) sync(); } @Override public byte getByteValue() { return this.cache; } + + @Override + public Class getValueType() { + return Byte.class; + } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/DoubleSyncValue.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/DoubleSyncValue.java index d7bf1441928..8c519afea1b 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/DoubleSyncValue.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/DoubleSyncValue.java @@ -75,9 +75,8 @@ public void setDoubleValue(double value, boolean setSource, boolean sync) { if (setSource && this.setter != null) { this.setter.accept(value); } - if (sync) { - sync(0, this::write); - } + onValueChanged(); + if (sync) sync(); } @Override @@ -123,4 +122,9 @@ public float getFloatValue() { public void setFloatValue(float value, boolean setSource, boolean sync) { setDoubleValue(value, setSource, sync); } + + @Override + public Class getValueType() { + return Double.class; + } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/EnumSyncValue.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/EnumSyncValue.java index 0a07529f437..9637aa3b380 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/EnumSyncValue.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/EnumSyncValue.java @@ -69,9 +69,8 @@ public void setValue(T value, boolean setSource, boolean sync) { if (setSource && this.setter != null) { this.setter.accept(value); } - if (sync) { - sync(0, this::write); - } + onValueChanged(); + if (sync) sync(); } @Override @@ -107,4 +106,9 @@ public void setIntValue(int value, boolean setSource, boolean sync) { public int getIntValue() { return this.cache.ordinal(); } + + @Override + public Class getValueType() { + return this.enumClass; + } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/FloatSyncValue.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/FloatSyncValue.java index e2a9afc52df..68e634c39a1 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/FloatSyncValue.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/FloatSyncValue.java @@ -75,9 +75,8 @@ public void setFloatValue(float value, boolean setSource, boolean sync) { if (setSource && this.setter != null) { this.setter.accept(value); } - if (sync) { - sync(0, this::write); - } + onValueChanged(); + if (sync) sync(); } @Override @@ -123,4 +122,9 @@ public double getDoubleValue() { public void setDoubleValue(double value, boolean setSource, boolean sync) { setFloatValue((float) value, setSource, sync); } + + @Override + public Class getValueType() { + return Float.class; + } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/FluidSlotSyncHandler.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/FluidSlotSyncHandler.java index 4acbdb0168b..121cfa49c10 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/FluidSlotSyncHandler.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/FluidSlotSyncHandler.java @@ -1,6 +1,5 @@ package com.gregtechceu.gtceu.api.mui.value.sync; -import com.gregtechceu.gtceu.GTCEu; import com.gregtechceu.gtceu.api.misc.forge.FluidTankHandler; import com.gregtechceu.gtceu.api.mui.utils.MouseData; @@ -25,7 +24,6 @@ @Accessors(fluent = true, chain = true) public class FluidSlotSyncHandler extends ValueSyncHandler { - public static final int SYNC_FLUID = 0; public static final int SYNC_CLICK = 1; public static final int SYNC_SCROLL = 2; public static final int SYNC_CONTROLS_AMOUNT = 3; @@ -62,14 +60,8 @@ public void setValue(@NotNull FluidStack value, boolean setSource, boolean sync) this.fluidTank.fill(value.copy(), IFluidHandler.FluidAction.EXECUTE); } } - if (sync) { - if (GTCEu.isClientThread()) { - syncToServer(SYNC_FLUID, this::write); - } else { - syncToClient(SYNC_FLUID, this::write); - } - } onValueChanged(); + if (sync) sync(); } public boolean needsSync() { @@ -88,6 +80,11 @@ public boolean updateCacheFromSource(boolean isFirstSync) { return false; } + @Override + public Class getValueType() { + return FluidStack.class; + } + @Override public void notifyUpdate() { setValue(this.fluidTank.getFluid(), false, true); @@ -105,7 +102,7 @@ public void read(FriendlyByteBuf buffer) { @Override public void readOnClient(int id, FriendlyByteBuf buf) { - if (id == SYNC_FLUID) { + if (id == SYNC_VALUE) { read(buf); } else if (id == SYNC_CONTROLS_AMOUNT) { this.controlsAmount = buf.readBoolean(); @@ -114,7 +111,7 @@ public void readOnClient(int id, FriendlyByteBuf buf) { @Override public void readOnServer(int id, FriendlyByteBuf buf) { - if (id == SYNC_FLUID) { + if (id == SYNC_VALUE) { if (this.phantom) { read(buf); } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/GenericCollectionSyncHandler.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/GenericCollectionSyncHandler.java index fa8d488dd80..22eaa608f68 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/GenericCollectionSyncHandler.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/GenericCollectionSyncHandler.java @@ -51,9 +51,8 @@ protected void onSetCache(C value, boolean setSource, boolean sync) { if (setSource && this.setter != null) { this.setter.accept(value); } - if (sync) { - sync(0, this::write); - } + onValueChanged(); + if (sync) sync(); } @Override diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/GenericListSyncHandler.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/GenericListSyncHandler.java index fc4e6d2f319..a6a95772a8f 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/GenericListSyncHandler.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/GenericListSyncHandler.java @@ -61,6 +61,11 @@ public void read(FriendlyByteBuf buffer) { onSetCache(getValue(), true, false); } + @Override + public Class> getValueType() { + return (Class>) (Object) List.class; + } + public static Builder builder() { return new Builder<>(); } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/GenericMapSyncHandler.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/GenericMapSyncHandler.java index 86eebd7d908..3cb94d363a0 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/GenericMapSyncHandler.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/GenericMapSyncHandler.java @@ -59,9 +59,8 @@ public void setValue(Map value, boolean setSource, boolean sync) { if (setSource && this.setter != null) { this.setter.accept(value); } - if (sync) { - sync(0, this::write); - } + onValueChanged(); + if (sync) sync(); } @Override @@ -113,6 +112,11 @@ public Map getValue() { return Collections.unmodifiableMap(this.cache); } + @Override + public Class> getValueType() { + return (Class>) (Object) Map.class; + } + public static class Builder { private Supplier> getter; diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/GenericSetSyncHandler.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/GenericSetSyncHandler.java index ed8b025f703..36af4cf6642 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/GenericSetSyncHandler.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/GenericSetSyncHandler.java @@ -56,6 +56,11 @@ public void read(FriendlyByteBuf buffer) { onSetCache(getValue(), true, false); } + @Override + public Class> getValueType() { + return (Class>) (Object) Set.class; + } + public static Builder builder() { return new Builder<>(); } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/GenericSyncValue.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/GenericSyncValue.java index cc3b81db8c0..e473d9beffe 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/GenericSyncValue.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/GenericSyncValue.java @@ -11,6 +11,7 @@ import net.minecraft.world.item.ItemStack; import net.minecraftforge.fluids.FluidStack; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -18,7 +19,7 @@ import java.util.function.Consumer; import java.util.function.Supplier; -public class GenericSyncValue extends ValueSyncHandler { +public class GenericSyncValue extends AbstractGenericSyncValue { public static GenericSyncValue forItem(@NotNull Supplier getter, @Nullable Consumer setter) { @@ -30,20 +31,21 @@ public static GenericSyncValue forFluid(@NotNull Supplier(getter, setter, ByteBufAdapters.FLUID_STACK); } - private final Supplier getter; - private final Consumer setter; private final IByteBufDeserializer deserializer; private final IByteBufSerializer serializer; private final EqualityTest equals; private final ICopy copy; - private T cache; + @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") + @Deprecated public GenericSyncValue(@NotNull Supplier getter, @Nullable Consumer setter, @NotNull IByteBufAdapter adapter) { this(getter, setter, adapter, adapter, adapter, null); } + @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") + @Deprecated public GenericSyncValue(@NotNull Supplier getter, @Nullable Consumer setter, @NotNull IByteBufAdapter adapter, @@ -51,6 +53,8 @@ public GenericSyncValue(@NotNull Supplier getter, this(getter, setter, adapter, adapter, adapter, copy); } + @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") + @Deprecated public GenericSyncValue(@NotNull Supplier getter, @Nullable Consumer setter, @NotNull IByteBufDeserializer deserializer, @@ -58,6 +62,8 @@ public GenericSyncValue(@NotNull Supplier getter, this(getter, setter, deserializer, serializer, null, null); } + @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") + @Deprecated public GenericSyncValue(@NotNull Supplier getter, @Nullable Consumer setter, @NotNull IByteBufDeserializer deserializer, @@ -66,23 +72,31 @@ public GenericSyncValue(@NotNull Supplier getter, this(getter, setter, deserializer, serializer, null, copy); } + @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") + @Deprecated public GenericSyncValue(@NotNull Supplier getter, @NotNull IByteBufAdapter adapter) { this(getter, null, adapter, adapter, adapter, null); } + @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") + @Deprecated public GenericSyncValue(@NotNull Supplier getter, @NotNull IByteBufAdapter adapter, @Nullable ICopy copy) { this(getter, null, adapter, adapter, adapter, copy); } + @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") + @Deprecated public GenericSyncValue(@NotNull Supplier getter, @NotNull IByteBufDeserializer deserializer, @NotNull IByteBufSerializer serializer) { this(getter, null, deserializer, serializer, null, null); } + @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") + @Deprecated public GenericSyncValue(@NotNull Supplier getter, @NotNull IByteBufDeserializer deserializer, @NotNull IByteBufSerializer serializer, @@ -90,15 +104,40 @@ public GenericSyncValue(@NotNull Supplier getter, this(getter, null, deserializer, serializer, null, copy); } + @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") + @Deprecated public GenericSyncValue(@NotNull Supplier getter, @Nullable Consumer setter, @NotNull IByteBufDeserializer deserializer, @NotNull IByteBufSerializer serializer, @Nullable EqualityTest equals, @Nullable ICopy copy) { - this.getter = Objects.requireNonNull(getter); - this.cache = getter.get(); - this.setter = setter; + this(null, getter, setter, deserializer, serializer, equals, copy); + } + + public GenericSyncValue(@NotNull Class type, + @NotNull Supplier getter, + @Nullable Consumer setter, + @NotNull IByteBufAdapter adapter, + @Nullable ICopy copy) { + this(type, getter, setter, adapter, adapter, adapter, copy); + } + + public GenericSyncValue(@NotNull Class type, + @NotNull Supplier getter, + @Nullable Consumer setter, + @NotNull IByteBufAdapter adapter) { + this(type, getter, setter, adapter, adapter, adapter, null); + } + + public GenericSyncValue(@NotNull Class type, + @NotNull Supplier getter, + @Nullable Consumer setter, + @NotNull IByteBufDeserializer deserializer, + @NotNull IByteBufSerializer serializer, + @Nullable EqualityTest equals, + @Nullable ICopy copy) { + super(type, getter, setter); this.deserializer = Objects.requireNonNull(deserializer); this.serializer = Objects.requireNonNull(serializer); this.equals = equals == null ? Objects::equals : EqualityTest.wrapNullSafe(equals); @@ -106,68 +145,94 @@ public GenericSyncValue(@NotNull Supplier getter, } @Override - public T getValue() { - return this.cache; + protected T createDeepCopyOf(T value) { + return this.copy.createDeepCopy(value); } @Override - public void setValue(T value, boolean setSource, boolean sync) { - this.cache = this.copy.createDeepCopy(value); - if (setSource && this.setter != null) { - this.setter.accept(value); - } - if (sync) { - sync(0, this::write); - } + protected boolean areEqual(T a, T b) { + return this.equals.areEqual(a, b); } @Override - public boolean updateCacheFromSource(boolean isFirstSync) { - T t = this.getter.get(); - if (isFirstSync || !this.equals.areEqual(this.cache, t)) { - setValue(t, false, false); - return true; - } - return false; + protected void serialize(FriendlyByteBuf buffer, T value) { + this.serializer.serialize(buffer, value); } @Override - public void notifyUpdate() { - setValue(this.getter.get(), false, true); + protected T deserialize(FriendlyByteBuf buffer) { + return this.deserializer.deserialize(buffer); } - @Override - public void write(FriendlyByteBuf buffer) { - this.serializer.serialize(buffer, this.cache); + @SuppressWarnings("unchecked") + public GenericSyncValue cast() { + return (GenericSyncValue) this; } - @Override - public void read(FriendlyByteBuf buffer) { - setValue(this.deserializer.deserialize(buffer), true, false); - } + public static class Builder { - @SuppressWarnings("unchecked") - public @Nullable Class getType() { - if (this.cache != null) { - return (Class) this.cache.getClass(); + private final Class type; + private Supplier getter; + private Consumer setter; + private IByteBufDeserializer deserializer; + private IByteBufSerializer serializer; + private EqualityTest equals; + private ICopy copy; + + public Builder(Class type) { + this.type = type; } - T t = this.getter.get(); - if (t != null) { - return (Class) t.getClass(); + + public Builder getter(Supplier getter) { + this.getter = getter; + return this; } - return null; - } - public boolean isOfType(Class expectedType) { - Class type = getType(); - if (type == null) { - throw new IllegalStateException("Could not infer type of GenericSyncValue since value is null!"); + public Builder setter(Consumer setter) { + this.setter = setter; + return this; } - return expectedType.isAssignableFrom(type); - } - @SuppressWarnings("unchecked") - public GenericSyncValue cast() { - return (GenericSyncValue) this; + public Builder deserializer(IByteBufDeserializer deserializer) { + this.deserializer = deserializer; + return this; + } + + public Builder serializer(IByteBufSerializer serializer) { + this.serializer = serializer; + return this; + } + + public Builder equals(EqualityTest equals) { + this.equals = equals; + return this; + } + + public Builder equalsDefault() { + return equals(EqualityTest.defaultTester()); + } + + public Builder equalsReference() { + return equals((a, b) -> a == b); + } + + public Builder copy(ICopy copy) { + this.copy = copy; + return this; + } + + public Builder copyImmutable() { + return copy(ICopy.immutable()); + } + + public Builder adapter(IByteBufAdapter adapter) { + return deserializer(adapter) + .serializer(adapter) + .equals(adapter); + } + + public GenericSyncValue build() { + return new GenericSyncValue<>(type, getter, setter, deserializer, serializer, equals, copy); + } } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/IntSyncValue.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/IntSyncValue.java index 22a4b0c0733..01fba34865d 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/IntSyncValue.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/IntSyncValue.java @@ -75,9 +75,8 @@ public void setIntValue(int value, boolean setSource, boolean sync) { if (setSource && this.setter != null) { this.setter.accept(value); } - if (sync) { - sync(0, this::write); - } + onValueChanged(); + if (sync) sync(); } @Override @@ -123,4 +122,9 @@ public void setStringValue(String value, boolean setSource, boolean sync) { public String getStringValue() { return String.valueOf(this.cache); } + + @Override + public Class getValueType() { + return Integer.class; + } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/ItemSlotSH.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/ItemSlotSH.java index 8a5ee87af68..eedde4bd6e9 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/ItemSlotSH.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/ItemSlotSH.java @@ -16,8 +16,8 @@ */ public class ItemSlotSH extends SyncHandler { - public static final int SYNC_ITEM = 1; - public static final int SYNC_ENABLED = 2; + public static final int SYNC_ITEM = 0; + public static final int SYNC_ENABLED = 1; @Getter private final ModularSlot slot; diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/LongArraySyncValue.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/LongArraySyncValue.java index 2ebec4704cf..e69ab0bd15a 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/LongArraySyncValue.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/LongArraySyncValue.java @@ -11,6 +11,6 @@ public class LongArraySyncValue extends GenericSyncValue { public LongArraySyncValue(@NotNull Supplier getter, @Nullable Consumer setter) { - super(getter, setter, ByteBufAdapters.LONG_ARR, long[]::clone); + super(long[].class, getter, setter, ByteBufAdapters.LONG_ARR, long[]::clone); } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/LongSyncValue.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/LongSyncValue.java index b42ba437947..0696cd13cd8 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/LongSyncValue.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/LongSyncValue.java @@ -75,9 +75,8 @@ public void setLongValue(long value, boolean setSource, boolean sync) { if (setSource && this.setter != null) { this.setter.accept(value); } - if (sync) { - sync(0, this::write); - } + onValueChanged(); + if (sync) sync(); } @Override @@ -123,4 +122,9 @@ public int getIntValue() { public String getStringValue() { return String.valueOf(this.cache); } + + @Override + public Class getValueType() { + return Long.class; + } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/ModularSyncManager.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/ModularSyncManager.java index a9f4ffa6c33..dde753d534d 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/ModularSyncManager.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/ModularSyncManager.java @@ -57,8 +57,9 @@ public void detectAndSendChanges(boolean init) { this.panelSyncManagerMap.values().forEach(psm -> psm.detectAndSendChanges(init)); } - public void onClose() { + public void dispose() { this.panelSyncManagerMap.values().forEach(PanelSyncManager::onClose); + this.panelSyncManagerMap.clear(); } public void onOpen() { diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/PanelSyncHandler.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/PanelSyncHandler.java index 3d3608bc17e..c47d0113fbd 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/PanelSyncHandler.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/PanelSyncHandler.java @@ -20,6 +20,11 @@ */ public final class PanelSyncHandler extends SyncHandler implements IPanelHandler { + public static final int SYNC_NOTIFY_OPEN = 0; + public static final int SYNC_OPEN = 1; + public static final int SYNC_CLOSE = 2; + public static final int SYNC_DISPOSE = 3; + private final IPanelBuilder panelBuilder; private final boolean subPanel; private String panelName; @@ -50,7 +55,7 @@ private void openPanel(boolean syncToServer) { if (isPanelOpen()) return; boolean client = getSyncManager().isClient(); if (syncToServer && client) { - syncToServer(0); + syncToServer(SYNC_NOTIFY_OPEN); return; } if (this.syncManager != null && @@ -60,7 +65,7 @@ private void openPanel(boolean syncToServer) { this.syncManager = new PanelSyncManager(client); this.openedPanel = Objects.requireNonNull(createUI(this.syncManager)); this.panelName = this.openedPanel.getName(); - this.openedPanel.setSyncHandler(this); + this.openedPanel.setPanelSyncHandler(this); WidgetTree.collectSyncValues(this.syncManager, this.openedPanel, false); if (!client) { this.openedPanel = null; @@ -94,7 +99,7 @@ public void closePanel() { this.openedPanel.closeIfOpen(); } } else { - syncToClient(2); + syncToClient(SYNC_CLOSE); } } @@ -109,7 +114,7 @@ public void closePanelInternal() { getSyncManager().getModularSyncManager().close(this.panelName); this.open = false; if (getSyncManager().isClient()) { - syncToServer(2); + syncToServer(SYNC_CLOSE); } } @@ -117,7 +122,6 @@ public void closePanelInternal() { public void deleteCachedPanel() { if (openedPanel == null || isPanelOpen()) return; boolean canDispose = WidgetTree.foreachChild(openedPanel, iWidget -> { - if (!iWidget.isValid()) return false; if (iWidget instanceof ISynced synced && synced.isSynced()) { return !(synced.getSyncHandler() instanceof ItemSlotSH); } @@ -126,13 +130,13 @@ public void deleteCachedPanel() { // This is because we can't guarantee that the sync handlers of the new panel are the same. // Dynamic sync handler changing is very error-prone. - if (!canDispose) + if (!canDispose) { throw new UnsupportedOperationException( "Can't delete cached panel if it's still open or has ItemSlot Sync Handlers!"); - + } disposePanel(); - sync(3); + sync(SYNC_DISPOSE); } private void disposePanel() { @@ -153,23 +157,23 @@ public boolean isPanelOpen() { @Override public void readOnClient(int i, FriendlyByteBuf packetBuffer) { - if (i == 1) { + if (i == SYNC_OPEN) { openPanel(false); - } else if (i == 2) { + } else if (i == SYNC_CLOSE) { closePanel(); - } else if (i == 3) { + } else if (i == SYNC_DISPOSE) { disposePanel(); } } @Override public void readOnServer(int i, FriendlyByteBuf packetBuffer) { - if (i == 0) { + if (i == SYNC_NOTIFY_OPEN) { openPanel(false); - syncToClient(1); - } else if (i == 2) { + syncToClient(SYNC_OPEN); + } else if (i == SYNC_CLOSE) { closePanelInternal(); - } else if (i == 3) { + } else if (i == SYNC_DISPOSE) { disposePanel(); } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/PanelSyncManager.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/PanelSyncManager.java index d859f2ab4c7..39175dd08d4 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/PanelSyncManager.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/PanelSyncManager.java @@ -35,7 +35,7 @@ public class PanelSyncManager { private final Map slotGroups = new Object2ObjectOpenHashMap<>(); private final Map reverseSyncHandlers = new Object2ObjectOpenHashMap<>(); private final Map syncedActions = new Object2ObjectOpenHashMap<>(); - private final Map subPanels = new Object2ObjectArrayMap<>(); + private final Map subPanels = new Object2ObjectArrayMap<>(); private ModularSyncManager modularSyncManager; @Getter private String panelName; @@ -67,9 +67,16 @@ public void initialize(String panelName, ModularSyncManager msm) { private void registerPanelSyncHandler(String name, SyncHandler syncHandler) { // only called on main psm SyncHandler currentSh = this.syncHandlers.get(name); - if (currentSh != null && currentSh != syncHandler) throw new IllegalStateException(); + if (currentSh != null && currentSh != syncHandler) { + throw new IllegalStateException("Failed to register panel sync handler during initialization. " + + "There already exists a sync handler for the name '" + name + "'."); + } String currentName = this.reverseSyncHandlers.get(syncHandler); - if (currentName != null && !name.equals(currentName)) throw new IllegalStateException(); + if (currentName != null && !name.equals(currentName)) { + throw new IllegalStateException( + "Failed to register panel sync handler for name '" + name + "' during initialization. " + + "The panel sync handler is already registered under the name '" + currentName + "'."); + } this.syncHandlers.put(name, syncHandler); this.reverseSyncHandlers.put(syncHandler, name); syncHandler.init(name, this); @@ -77,12 +84,8 @@ private void registerPanelSyncHandler(String name, SyncHandler syncHandler) { void closeSubPanels() { this.subPanels.values().forEach(syncHandler -> { - if (syncHandler instanceof IPanelHandler panelHandler) { - if (panelHandler.isSubPanel()) { - panelHandler.closePanel(); - } - } else { - throw new IllegalStateException(); + if (syncHandler.isSubPanel()) { + syncHandler.closePanel(); } }); } @@ -95,6 +98,7 @@ public void onOpen() { @ApiStatus.Internal public void onClose() { this.closeListener.forEach(listener -> listener.accept(getPlayer())); + this.syncHandlers.values().forEach(SyncHandler::dispose); // previously panel sync handlers were removed from the main psm, however this problematic if the screen will be // reopened at some point. // we can just not remove the sync handlers since mui has proper checks for re-registering panels @@ -142,7 +146,8 @@ private boolean invokeSyncedAction(String mapKey, FriendlyByteBuf buf) { GTCEu.LOGGER.warn("SyncAction '{}' does not exist for panel '{}'!.", mapKey, panelName); return false; } - if (this.allowSyncHandlerRegistration || !syncedAction.isExecuteClient() || !syncedAction.isExecuteServer()) { + if (!isLocked() || this.allowSyncHandlerRegistration || !syncedAction.isExecuteClient() || + !syncedAction.isExecuteServer()) { syncedAction.invoke(this.client, buf); } else { // only allow sync handler registration if it is executed on client and server @@ -238,32 +243,74 @@ public DynamicSyncHandler dynamicSyncHandler(String key, int id, return syncHandler; } + /** + * @deprecated replaced by {@link #syncedPanel(String, boolean, PanelSyncHandler.IPanelBuilder)} + */ + @ApiStatus.ScheduledForRemoval(inVersion = "3.3.0") + @Deprecated + public IPanelHandler panel(String key, PanelSyncHandler.IPanelBuilder panelBuilder, boolean subPanel) { + SyncHandler sh = this.subPanels.get(key); + if (sh != null) return (IPanelHandler) sh; + PanelSyncHandler syncHandler = new PanelSyncHandler(panelBuilder, subPanel); + this.subPanels.put(key, syncHandler); + return syncHandler; + } + /** * Creates a synced panel handler. This can be used to automatically handle syncing for synced panels. * Synced panels do not need to be synced themselves, but contain at least one widget which is synced. *

- * NOTE + * NOTE *

* A panel sync handler is only created once. If one was already registered, that one will be returned. - * (This is only relevant for nested sub panels.) + * (This is only relevant for nested sub panels.) Furthermore, the panel handler has to be created on client and + * server with the same + * key. Like any other sync handler, the panel sync handler has to be created before the panel opened. The only + * exception is inside + * dynamic sync handlers. * * @param key the key used for syncing - * @param panelBuilder the panel builder, that will create the new panel. It must not return null or any existing - * panels. * @param subPanel true if this panel should close when its parent closes (the parent is defined by this * {@link PanelSyncManager}) + * @param panelBuilder the panel builder, that will create the new panel. It must not return null or any existing + * panels. * @return a synced panel handler. * @throws NullPointerException if the build panel of the builder is null * @throws IllegalArgumentException if the build panel of the builder is the main panel + * @throws IllegalStateException if this method was called too late */ - public IPanelHandler panel(String key, PanelSyncHandler.IPanelBuilder panelBuilder, boolean subPanel) { - SyncHandler sh = this.subPanels.get(key); - if (sh != null) return (IPanelHandler) sh; + public IPanelHandler syncedPanel(String key, boolean subPanel, PanelSyncHandler.IPanelBuilder panelBuilder) { + IPanelHandler ph = findPanelHandlerNullable(key); + if (ph != null) return ph; + if (isLocked() && !this.allowSyncHandlerRegistration) { + // registration of sync handlers forbidden + throw new IllegalStateException( + "Synced panels must be registered during panel building. The only exceptions is via a DynamicSyncHandler and sync functions!"); + } PanelSyncHandler syncHandler = new PanelSyncHandler(panelBuilder, subPanel); this.subPanels.put(key, syncHandler); + if (isInitialised() && (this == this.modularSyncManager.getMainPSM() || + this.modularSyncManager.getMainPSM().findSyncHandlerNullable(this.panelName, PanelSyncHandler.class) == + null)) { + // current panel is open + this.modularSyncManager.getMainPSM().registerPanelSyncHandler(key, syncHandler); + } return syncHandler; } + public @Nullable IPanelHandler findPanelHandlerNullable(String key) { + return this.subPanels.get(key); + } + + public @NotNull IPanelHandler findPanelHandler(String key) { + IPanelHandler panelHandler = findPanelHandlerNullable(key); + if (panelHandler == null) { + throw new NoSuchElementException( + "Expected to find panel sync handler with key '" + key + "', but none was found."); + } + return panelHandler; + } + public PanelSyncManager registerSlotGroup(SlotGroup slotGroup) { if (!slotGroup.isSingleton()) { this.slotGroups.put(slotGroup.getName(), slotGroup); @@ -383,7 +430,7 @@ public T getOrCreateSyncHandler(String name, Class cl } public T getOrCreateSyncHandler(String name, int id, Class clazz, Supplier supplier) { - SyncHandler syncHandler = getSyncHandler(name); + SyncHandler syncHandler = findSyncHandlerNullable(name, id); if (syncHandler == null) { if (isLocked() && !this.allowSyncHandlerRegistration) { // registration is locked, and we don't have permission to temporarily bypass lock @@ -399,7 +446,7 @@ public T getOrCreateSyncHandler(String name, int id, Cla } if (clazz.isAssignableFrom(syncHandler.getClass())) { - return (T) syncHandler; + return clazz.cast(syncHandler); } throw new IllegalStateException("SyncHandler for key " + makeSyncKey(name, id) + " is of type " + syncHandler.getClass() + ", but type " + clazz + " was expected!"); @@ -448,11 +495,10 @@ public Collection getSlotGroups() { return findSyncHandler(name, 0); } - @SuppressWarnings("unchecked") public @Nullable T findSyncHandlerNullable(String name, int id, Class type) { SyncHandler syncHandler = this.syncHandlers.get(makeSyncKey(name, id)); if (syncHandler != null && type.isAssignableFrom(syncHandler.getClass())) { - return (T) syncHandler; + return type.cast(syncHandler); } return null; } @@ -461,7 +507,6 @@ public Collection getSlotGroups() { return findSyncHandlerNullable(name, 0, type); } - @SuppressWarnings("unchecked") public @NotNull T findSyncHandler(String name, int id, Class type) { SyncHandler syncHandler = this.syncHandlers.get(makeSyncKey(name, id)); if (syncHandler == null) { @@ -472,7 +517,7 @@ public Collection getSlotGroups() { throw new ClassCastException("Expected to find sync handler with key '" + makeSyncKey(name, id) + "' of type '" + type.getName() + "', but found type '" + syncHandler.getClass().getName() + "'."); } - return (T) syncHandler; + return type.cast(syncHandler); } public @NotNull T findSyncHandler(String name, Class type) { diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/PhantomItemSlotSH.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/PhantomItemSlotSH.java index 821b08f1e91..1b25e50c426 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/PhantomItemSlotSH.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/PhantomItemSlotSH.java @@ -4,6 +4,7 @@ import com.gregtechceu.gtceu.api.mui.widgets.slot.ModularSlot; import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.inventory.Slot; import net.minecraft.world.item.ItemStack; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.items.ItemHandlerHelper; @@ -25,6 +26,7 @@ public class PhantomItemSlotSH extends ItemSlotSH { @ApiStatus.Internal public PhantomItemSlotSH(ModularSlot slot) { super(slot); + ((Slot) slot).index = -1; } @Override diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/StringSyncValue.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/StringSyncValue.java index f7b0d359c13..1e59df14920 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/StringSyncValue.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/StringSyncValue.java @@ -1,6 +1,5 @@ package com.gregtechceu.gtceu.api.mui.value.sync; -import com.gregtechceu.gtceu.GTCEu; import com.gregtechceu.gtceu.api.mui.base.value.sync.IStringSyncValue; import com.gregtechceu.gtceu.utils.NetworkUtils; @@ -14,16 +13,10 @@ import java.util.function.Consumer; import java.util.function.Supplier; -public class StringSyncValue extends ValueSyncHandler implements IStringSyncValue { +public class StringSyncValue extends AbstractGenericSyncValue implements IStringSyncValue { - private final Supplier getter; - private final Consumer setter; - private String cache; - - public StringSyncValue(@NotNull Supplier getter, @Nullable Consumer setter) { - this.getter = Objects.requireNonNull(getter); - this.setter = setter; - this.cache = getter.get(); + public StringSyncValue(Supplier getter, Consumer setter) { + super(String.class, getter, setter); } public StringSyncValue(@NotNull Supplier getter) { @@ -39,66 +32,36 @@ public StringSyncValue(@Nullable Supplier clientGetter, @Contract("null, _, null, _ -> fail") public StringSyncValue(@Nullable Supplier clientGetter, @Nullable Consumer clientSetter, @Nullable Supplier serverGetter, @Nullable Consumer serverSetter) { - if (clientGetter == null && serverGetter == null) { - throw new NullPointerException("Client or server getter must not be null!"); - } - if (GTCEu.isClientThread()) { - this.getter = clientGetter != null ? clientGetter : serverGetter; - this.setter = clientSetter != null ? clientSetter : serverSetter; - } else { - this.getter = serverGetter != null ? serverGetter : clientGetter; - this.setter = serverSetter != null ? serverSetter : clientSetter; - } - this.cache = this.getter.get(); - } - - @Override - public String getValue() { - return this.cache; + super(String.class, clientGetter, clientSetter, serverGetter, serverSetter); } @Override - public String getStringValue() { - return this.cache; + protected String createDeepCopyOf(String value) { + return value; } @Override - public void setValue(String value, boolean setSource, boolean sync) { - setStringValue(value, setSource, sync); + protected boolean areEqual(String a, String b) { + return Objects.equals(a, b); } @Override - public void setStringValue(String value, boolean setSource, boolean sync) { - this.cache = value; - if (setSource && this.setter != null) { - this.setter.accept(value); - } - if (sync) { - sync(0, this::write); - } + protected void serialize(FriendlyByteBuf buffer, String value) { + NetworkUtils.writeStringSafe(buffer, value, Short.MAX_VALUE - 74); } @Override - public boolean updateCacheFromSource(boolean isFirstSync) { - if (isFirstSync || !Objects.equals(this.getter.get(), this.cache)) { - setValue(this.getter.get(), false, false); - return true; - } - return false; + protected String deserialize(FriendlyByteBuf buffer) { + return NetworkUtils.readStringSafe(buffer); } @Override - public void notifyUpdate() { - setValue(this.getter.get(), false, true); - } - - @Override - public void write(FriendlyByteBuf buffer) { - NetworkUtils.writeStringSafe(buffer, getValue(), Short.MAX_VALUE - 74); + public String getStringValue() { + return getValue(); } @Override - public void read(FriendlyByteBuf buffer) { - setValue(NetworkUtils.readStringSafe(buffer), true, false); + public void setStringValue(String value, boolean setSource, boolean sync) { + setValue(value, setSource, sync); } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/SyncHandler.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/SyncHandler.java index 9317e566c24..fe65b658178 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/SyncHandler.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/SyncHandler.java @@ -1,6 +1,7 @@ package com.gregtechceu.gtceu.api.mui.value.sync; import com.gregtechceu.gtceu.api.mui.base.IPacketWriter; +import com.gregtechceu.gtceu.api.mui.base.value.ISyncOrValue; import com.gregtechceu.gtceu.common.network.GTNetwork; import com.gregtechceu.gtceu.common.network.packets.ui.SyncHandlerPacket; @@ -22,7 +23,7 @@ * A sync handler must exist on client and server. * It must be configured exactly the same to avoid issues. */ -public abstract class SyncHandler { +public abstract class SyncHandler implements ISyncOrValue { private PanelSyncManager syncManager; /** @@ -160,6 +161,11 @@ public PanelSyncManager getSyncManager() { return this.syncManager; } + @Override + public boolean isSyncHandler() { + return true; + } + public static void sendToClient(String panel, FriendlyByteBuf buffer, SyncHandler syncHandler) { Objects.requireNonNull(buffer); Objects.requireNonNull(syncHandler); diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/SyncHandlers.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/SyncHandlers.java index 15975340127..62985618dca 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/SyncHandlers.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/SyncHandlers.java @@ -45,4 +45,8 @@ public static > EnumSyncValue enumValue(Class clazz, Sup Consumer setter) { return new EnumSyncValue<>(clazz, getter, setter); } + + public static GenericSyncValue.Builder generic(Class type) { + return new GenericSyncValue.Builder<>(type); + } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/ValueSyncHandler.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/ValueSyncHandler.java index 02c2277efb3..b70bd31a991 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/ValueSyncHandler.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/ValueSyncHandler.java @@ -9,29 +9,35 @@ public abstract class ValueSyncHandler extends SyncHandler implements IValueSyncHandler { + public static final int SYNC_VALUE = 0; + @Getter @Setter private Runnable changeListener; @Override public void readOnClient(int id, FriendlyByteBuf buf) { - read(buf); - onValueChanged(); + if (id == SYNC_VALUE) read(buf); } @Override public void readOnServer(int id, FriendlyByteBuf buf) { - read(buf); - onValueChanged(); + if (id == SYNC_VALUE) read(buf); + } + + protected void sync() { + sync(SYNC_VALUE, this::write); } @Override public void detectAndSendChanges(boolean init) { - if (updateCacheFromSource(init)) { - syncToClient(0, this::write); - } + if (updateCacheFromSource(init)) sync(); } + /** + * Called when the cached value of this sync handler updates. Implementations need to call this inside + * {@link #setValue(Object, boolean, boolean)}. + */ protected void onValueChanged() { if (this.changeListener != null) { this.changeListener.run(); diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/widget/EmptyWidget.java b/src/main/java/com/gregtechceu/gtceu/api/mui/widget/EmptyWidget.java index a18587c208d..2e36cb5849e 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/widget/EmptyWidget.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/widget/EmptyWidget.java @@ -36,7 +36,6 @@ public ModularScreen getScreen() { @Override public void initialise(@NotNull IWidget parent, boolean late) { this.parent = parent; - getArea().setPanelLayer(getPanel().getArea().getPanelLayer()); getArea().z(parent.getArea().z() + 1); } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/widget/Widget.java b/src/main/java/com/gregtechceu/gtceu/api/mui/widget/Widget.java index b61ef7993b4..686941ccc3d 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/widget/Widget.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/widget/Widget.java @@ -6,6 +6,7 @@ import com.gregtechceu.gtceu.api.mui.base.drawable.IDrawable; import com.gregtechceu.gtceu.api.mui.base.layout.IResizeable; import com.gregtechceu.gtceu.api.mui.base.layout.IViewportStack; +import com.gregtechceu.gtceu.api.mui.base.value.ISyncOrValue; import com.gregtechceu.gtceu.api.mui.base.value.IValue; import com.gregtechceu.gtceu.api.mui.base.widget.*; import com.gregtechceu.gtceu.api.mui.factory.GuiData; @@ -24,7 +25,6 @@ import com.gregtechceu.gtceu.client.mui.screen.viewport.ModularGuiContext; import lombok.Getter; -import lombok.Setter; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.MustBeInvokedByOverriders; import org.jetbrains.annotations.NotNull; @@ -109,7 +109,6 @@ public class Widget> implements IWidget, IPositioned, ITo * {@link IUIHolder#buildUI(GuiData, com.gregtechceu.gtceu.api.mui.value.sync.PanelSyncManager, com.gregtechceu.gtceu.client.mui.screen.UISettings)} * since it's called on server and client. Otherwise, this will not work. */ - @Setter @Nullable private SyncHandler syncHandler; // rendering @@ -172,7 +171,6 @@ public void initialise(@NotNull IWidget parent, boolean late) { this.parent = parent; this.panel = parent.getPanel(); this.context = parent.getContext(); - getArea().setPanelLayer(this.panel.getArea().getPanelLayer()); getArea().z(parent.getArea().z() + 1); if (this.guiActionListeners != null) { for (IGuiAction action : this.guiActionListeners) { @@ -215,20 +213,17 @@ public void onInit() {} public void afterInit() {} /** - * Retrieves, initialises and verifies a linked sync handler. + * Retrieves, verifies and initialises a linked sync handler. * Custom logic should be handled in {@link #isValidSyncHandler(SyncHandler)}. */ @Override public void initialiseSyncHandler(ModularSyncManager syncManager, boolean late) { - if (this.syncKey != null) { - this.syncHandler = syncManager.getSyncHandler(getPanel().getName(), this.syncKey); - } - if ((this.syncKey != null || this.syncHandler != null) && !isValidSyncHandler(this.syncHandler)) { - String type = this.syncHandler == null ? null : this.syncHandler.getClass().getName(); - this.syncHandler = null; - throw new IllegalStateException("SyncHandler of type " + type + " is not valid for " + - getClass().getName() + ", with key " + this.syncKey); + SyncHandler handler = this.syncHandler; + if (handler == null && this.syncKey != null) { + handler = syncManager.getSyncHandler(getPanel().getName(), this.syncKey); } + if (handler != null) setSyncOrValue(handler); + setSyncHandler(handler); if (this.syncHandler instanceof ValueSyncHandler valueSyncHandler && valueSyncHandler.getChangeListener() == null) { valueSyncHandler.setChangeListener(this::markTooltipDirty); @@ -858,15 +853,36 @@ public void setEnabled(boolean enabled) { } /** - * Used for widgets to set a value handler. Can also be a sync handler + * Used for widgets to set a value handler.
+ * Will also call {@link #setSyncHandler(SyncHandler)} if it is a SyncHandler */ + @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") + @Deprecated protected void setValue(IValue value) { this.value = value; - if (value instanceof SyncHandler syncHandler1) { - setSyncHandler(syncHandler1); + if (value instanceof SyncHandler handler) { + setSyncHandler(handler); } } + /** + * Used for widgets to set a sync handler. + */ + @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") + @Deprecated + protected void setSyncHandler(@Nullable SyncHandler syncHandler) { + if (syncHandler != null) checkValidSyncOrValue(syncHandler); + this.syncHandler = syncHandler; + } + + @MustBeInvokedByOverriders + protected void setSyncOrValue(@NotNull ISyncOrValue syncOrValue) { + if (!syncOrValue.isSyncHandler() && !syncOrValue.isValueHandler()) return; + checkValidSyncOrValue(syncOrValue); + if (syncOrValue instanceof SyncHandler syncHandler1) setSyncHandler(syncHandler1); + if (syncOrValue instanceof IValue value1) setValue(value1); + } + // ------------- // === Other === // ------------- diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/widget/WidgetTree.java b/src/main/java/com/gregtechceu/gtceu/api/mui/widget/WidgetTree.java index 0049806ce64..9118b724040 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/widget/WidgetTree.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/widget/WidgetTree.java @@ -207,7 +207,7 @@ public static boolean foreachChildReverse(IWidget parent, Predicate con } /** - * Creates a stream of the whole sub widget tree. + * Creates a flat stream of the whole sub widget tree. *

* {@link Stream#forEach(Consumer)} on this has slightly worse performance than * {@link #foreachChildBFS(IWidget, Predicate, boolean)} on @@ -219,7 +219,7 @@ public static boolean foreachChildReverse(IWidget parent, Predicate con * @return stream of the sub widget tree */ @SuppressWarnings("UnstableApiUsage") - public static Stream stream(IWidget parent) { + public static Stream flatStream(IWidget parent) { if (!parent.hasChildren()) return Stream.of(parent); return Streams.stream(iteratorBFS(parent)); } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/widget/sizer/Area.java b/src/main/java/com/gregtechceu/gtceu/api/mui/widget/sizer/Area.java index f6e88f38f9e..f9ed20e3146 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/widget/sizer/Area.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/widget/sizer/Area.java @@ -12,7 +12,6 @@ import net.minecraft.util.Mth; import lombok.Getter; -import lombok.Setter; import java.util.Objects; @@ -35,12 +34,6 @@ public static boolean isInside(int x, int y, int w, int h, int px, int py) { * relative position (in most cases the direct parent) */ public int rx, ry; - /** - * each panel has its own layer - */ - @Getter - @Setter - private byte panelLayer = 0; /** * the widget layer within this panel */ @@ -66,7 +59,6 @@ public Area(Area area) { super(area); this.rx = area.rx; this.ry = area.ry; - this.panelLayer = area.panelLayer; this.z = area.z; getMargin().set(area.getMargin()); getPadding().set(area.getPadding()); @@ -576,13 +568,13 @@ public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) return false; if (!super.equals(o)) return false; Area area = (Area) o; - return rx == area.rx && ry == area.ry && panelLayer == area.panelLayer && z == area.z && + return rx == area.rx && ry == area.ry && z == area.z && Objects.equals(getMargin(), area.getMargin()) && Objects.equals(getPadding(), area.getPadding()); } @Override public int hashCode() { - return Objects.hash(super.hashCode(), rx, ry, panelLayer, z, margin, padding); + return Objects.hash(super.hashCode(), rx, ry, z, margin, padding); } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/widget/sizer/Flex.java b/src/main/java/com/gregtechceu/gtceu/api/mui/widget/sizer/Flex.java index 30600ee3258..3b7dea00919 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/widget/sizer/Flex.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/widget/sizer/Flex.java @@ -423,20 +423,19 @@ public boolean isYMarginPaddingApplied() { public boolean resize(IGuiElement guiElement, boolean isParentLayout) { IResizeable relativeTo = getRelativeTo(); Area relativeArea = relativeTo.getArea(); - byte panelLayer = this.parent.getArea().getPanelLayer(); - - if (!this.bypassLayerRestriction && (relativeArea.getPanelLayer() > panelLayer || - (relativeArea.getPanelLayer() == panelLayer && relativeArea.z() >= this.parent.getArea().z()))) { - Area area = guiElement.getArea(); - area.setSize(18, 18); - area.rx = 0; - area.ry = 0; - guiElement.resizer().setResized(true); - GuiError.throwNew(this.parent, GuiError.Type.SIZING, - "Widget can't be relative to a widget at the same level or above"); - return true; - } + /* + * if (!this.bypassLayerRestriction && relativeArea.z() >= this.parent.getArea().z()) { + * Area area = guiElement.getArea(); + * area.setSize(18, 18); + * area.rx = 0; + * area.ry = 0; + * guiElement.resizer().setResized(true); + * GuiError.throwNew(this.parent, GuiError.Type.SIZING, + * "Widget can't be relative to a widget at the same level or above"); + * return true; + * } + */ // calculate x, y, width and height if possible this.x.apply(guiElement.getArea(), relativeTo, guiElement::getDefaultWidth); this.y.apply(guiElement.getArea(), relativeTo, guiElement::getDefaultHeight); diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/AbstractCycleButtonWidget.java b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/AbstractCycleButtonWidget.java index 729e5c9d779..33c48a9f846 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/AbstractCycleButtonWidget.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/AbstractCycleButtonWidget.java @@ -1,40 +1,40 @@ package com.gregtechceu.gtceu.api.mui.widgets; +import com.gregtechceu.gtceu.GTCEu; import com.gregtechceu.gtceu.api.mui.base.ITheme; import com.gregtechceu.gtceu.api.mui.base.drawable.IDrawable; import com.gregtechceu.gtceu.api.mui.base.drawable.IKey; import com.gregtechceu.gtceu.api.mui.base.drawable.ITextLine; -import com.gregtechceu.gtceu.api.mui.base.value.IBoolValue; -import com.gregtechceu.gtceu.api.mui.base.value.IEnumValue; -import com.gregtechceu.gtceu.api.mui.base.value.IIntValue; +import com.gregtechceu.gtceu.api.mui.base.value.*; import com.gregtechceu.gtceu.api.mui.base.widget.Interactable; import com.gregtechceu.gtceu.api.mui.drawable.UITexture; import com.gregtechceu.gtceu.api.mui.theme.WidgetThemeEntry; import com.gregtechceu.gtceu.api.mui.utils.Alignment; import com.gregtechceu.gtceu.api.mui.value.IntValue; -import com.gregtechceu.gtceu.api.mui.value.sync.SyncHandler; import com.gregtechceu.gtceu.api.mui.widget.Widget; import com.gregtechceu.gtceu.client.mui.screen.RichTooltip; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; import java.util.Arrays; -import java.util.List; import java.util.function.Consumer; public class AbstractCycleButtonWidget> extends Widget implements Interactable { + private static final RichTooltip[] EMPTY_TOOLTIP = new RichTooltip[0]; + private int stateCount = 1; + private boolean explicitStateCount = false; + private boolean hasCount = false; private IIntValue intValue; private int lastValue = -1; protected IDrawable[] background = null; protected IDrawable[] hoverBackground = null; protected IDrawable[] overlay = null; protected IDrawable[] hoverOverlay = null; - private final List stateTooltip = new ArrayList<>(); + protected RichTooltip[] tooltip = EMPTY_TOOLTIP; @Override public void onInit() { @@ -44,9 +44,58 @@ public void onInit() { } @Override - public boolean isValidSyncHandler(SyncHandler syncHandler) { - this.intValue = castIfTypeElseNull(syncHandler, IIntValue.class); - return this.intValue != null; + public boolean isValidSyncOrValue(@NotNull ISyncOrValue syncOrValue) { + return syncOrValue.isTypeOrEmpty(IIntValue.class); + } + + protected void updateStateCount(int count, boolean explicit) { + if (count < 1) return; + if (explicit) { + setStateCount(count); + this.explicitStateCount = true; + } else if (!this.explicitStateCount && count > this.stateCount) { + setStateCount(count); + } + } + + private void setStateCount(int stateCount) { + this.hasCount = true; + if (this.stateCount == stateCount) return; + this.stateCount = stateCount; + + int currentSize = this.tooltip.length; + if (stateCount > currentSize) { + this.tooltip = Arrays.copyOf(this.tooltip, stateCount); + for (; currentSize < stateCount; currentSize++) { + this.tooltip[currentSize] = new RichTooltip().parent(this); + } + } else if (stateCount < currentSize) { + for (int i = stateCount; i < currentSize; i++) { + this.tooltip[i].reset(); + } + } + + this.background = checkArray(this.background, stateCount); + this.overlay = checkArray(this.overlay, stateCount); + this.hoverBackground = checkArray(this.hoverBackground, stateCount); + this.hoverOverlay = checkArray(this.hoverOverlay, stateCount); + } + + protected void expectCount() { + if (!this.hasCount) { + GTCEu.LOGGER.error("State count for widget {} is required, but has not been set yet!", this); + } + } + + @Override + protected void setSyncOrValue(@NotNull ISyncOrValue syncOrValue) { + super.setSyncOrValue(syncOrValue); + this.intValue = syncOrValue.castNullable(IIntValue.class); + if (syncOrValue instanceof IEnumValue enumValue) { + updateStateCount(enumValue.getEnumClass().getEnumConstants().length, true); + } else if (syncOrValue instanceof IBoolValue) { + updateStateCount(2, true); + } } protected int getState() { @@ -128,13 +177,13 @@ public IDrawable getCurrentOverlay(ITheme theme, WidgetThemeEntry widgetTheme @Override public boolean hasTooltip() { int state = getState(); - return super.hasTooltip() || (this.stateTooltip.size() > state && !this.stateTooltip.get(state).isEmpty()); + return super.hasTooltip() || (this.tooltip.length > state && !this.tooltip[state].isEmpty()); } @Override public void markTooltipDirty() { super.markTooltipDirty(); - for (RichTooltip tooltip : this.stateTooltip) { + for (RichTooltip tooltip : this.tooltip) { tooltip.markDirty(); } getState(); @@ -144,13 +193,17 @@ public void markTooltipDirty() { public @Nullable RichTooltip getTooltip() { RichTooltip tooltip = super.getTooltip(); if (tooltip == null || tooltip.isEmpty()) { - return this.stateTooltip.get(getState()); + int state = getState(); + if (this.tooltip.length > 0 && this.tooltip.length > state) { + return this.tooltip[state]; + } } return tooltip; } @Override public W disableHoverBackground() { + expectCount(); if (this.hoverBackground != null) { Arrays.fill(this.hoverBackground, IDrawable.NONE); } @@ -162,6 +215,7 @@ public W disableHoverBackground() { @Override public W disableHoverOverlay() { + expectCount(); if (this.hoverOverlay != null) { Arrays.fill(this.hoverOverlay, IDrawable.NONE); } @@ -172,13 +226,7 @@ public W disableHoverOverlay() { } protected W value(IIntValue value) { - this.intValue = value; - setValue(value); - if (value instanceof IEnumValue enumValue) { - stateCount(enumValue.getEnumClass().getEnumConstants().length); - } else if (value instanceof IBoolValue) { - stateCount(2); - } + setSyncOrValue(ISyncOrValue.orEmpty(value)); return getThis(); } @@ -190,6 +238,7 @@ protected W value(IIntValue value) { * @return this */ public W stateBackground(UITexture texture) { + expectCount(); splitTexture(texture, this.background); return getThis(); } @@ -202,6 +251,7 @@ public W stateBackground(UITexture texture) { * @return this */ public W stateOverlay(UITexture texture) { + expectCount(); splitTexture(texture, this.overlay); return getThis(); } @@ -214,6 +264,7 @@ public W stateOverlay(UITexture texture) { * @return this */ public W stateHoverBackground(UITexture texture) { + expectCount(); splitTexture(texture, this.hoverBackground); return getThis(); } @@ -226,6 +277,7 @@ public W stateHoverBackground(UITexture texture) { * @return this */ public W stateHoverOverlay(UITexture texture) { + expectCount(); splitTexture(texture, this.hoverOverlay); return getThis(); } @@ -234,10 +286,8 @@ public W stateHoverOverlay(UITexture texture) { * Adds a line to the tooltip */ protected W addTooltip(int state, IDrawable tooltip) { - if (state >= this.stateTooltip.size() || state < 0) { - throw new IndexOutOfBoundsException(); - } - this.stateTooltip.get(state).addLine(tooltip); + updateStateCount(state + 1, false); + this.tooltip[state].addLine(tooltip); return getThis(); } @@ -256,7 +306,8 @@ protected W addTooltip(int state, String tooltip) { */ @Override public W addTooltipElement(String s) { - for (RichTooltip tooltip : this.stateTooltip) { + expectCount(); + for (RichTooltip tooltip : this.tooltip) { tooltip.add(s); } return getThis(); @@ -270,7 +321,8 @@ public W addTooltipElement(String s) { */ @Override public W addTooltipDrawableLines(Iterable lines) { - for (RichTooltip tooltip : this.stateTooltip) { + expectCount(); + for (RichTooltip tooltip : this.tooltip) { tooltip.addDrawableLines(lines); } return getThis(); @@ -284,7 +336,8 @@ public W addTooltipDrawableLines(Iterable lines) { */ @Override public W addTooltipElement(IDrawable drawable) { - for (RichTooltip tooltip : this.stateTooltip) { + expectCount(); + for (RichTooltip tooltip : this.tooltip) { tooltip.add(drawable); } return getThis(); @@ -298,7 +351,8 @@ public W addTooltipElement(IDrawable drawable) { */ @Override public W addTooltipLine(ITextLine line) { - for (RichTooltip tooltip : this.stateTooltip) { + expectCount(); + for (RichTooltip tooltip : this.tooltip) { tooltip.addLine(line); } return getThis(); @@ -312,7 +366,8 @@ public W addTooltipLine(ITextLine line) { */ @Override public W addTooltipLine(IDrawable drawable) { - for (RichTooltip tooltip : this.stateTooltip) { + expectCount(); + for (RichTooltip tooltip : this.tooltip) { tooltip.addLine(drawable); } return getThis(); @@ -326,7 +381,8 @@ public W addTooltipLine(IDrawable drawable) { */ @Override public W addTooltipStringLines(Iterable lines) { - for (RichTooltip tooltip : this.stateTooltip) { + expectCount(); + for (RichTooltip tooltip : this.tooltip) { tooltip.addStringLines(lines); } return getThis(); @@ -340,7 +396,8 @@ public W addTooltipStringLines(Iterable lines) { */ @Override public W tooltipStatic(Consumer tooltipConsumer) { - for (RichTooltip tooltip : this.stateTooltip) { + expectCount(); + for (RichTooltip tooltip : this.tooltip) { tooltipConsumer.accept(tooltip); } return getThis(); @@ -354,7 +411,8 @@ public W tooltipStatic(Consumer tooltipConsumer) { */ @Override public W tooltipDynamic(Consumer tooltipBuilder) { - for (RichTooltip tooltip : this.stateTooltip) { + expectCount(); + for (RichTooltip tooltip : this.tooltip) { tooltip.tooltipBuilder(tooltipBuilder); } return getThis(); @@ -368,7 +426,8 @@ public W tooltipDynamic(Consumer tooltipBuilder) { */ @Override public W tooltipAlignment(Alignment alignment) { - for (RichTooltip tooltip : this.stateTooltip) { + expectCount(); + for (RichTooltip tooltip : this.tooltip) { tooltip.alignment(alignment); } return getThis(); @@ -382,7 +441,8 @@ public W tooltipAlignment(Alignment alignment) { */ @Override public W tooltipPos(RichTooltip.Pos pos) { - for (RichTooltip tooltip : this.stateTooltip) { + expectCount(); + for (RichTooltip tooltip : this.tooltip) { tooltip.pos(pos); } return getThis(); @@ -397,7 +457,8 @@ public W tooltipPos(RichTooltip.Pos pos) { */ @Override public W tooltipPos(int x, int y) { - for (RichTooltip tooltip : this.stateTooltip) { + expectCount(); + for (RichTooltip tooltip : this.tooltip) { tooltip.pos(x, y); } return getThis(); @@ -411,7 +472,8 @@ public W tooltipPos(int x, int y) { */ @Override public W tooltipScale(float scale) { - for (RichTooltip tooltip : this.stateTooltip) { + expectCount(); + for (RichTooltip tooltip : this.tooltip) { tooltip.scale(scale); } return getThis(); @@ -425,7 +487,8 @@ public W tooltipScale(float scale) { */ @Override public W tooltipTextColor(int textColor) { - for (RichTooltip tooltip : this.stateTooltip) { + expectCount(); + for (RichTooltip tooltip : this.tooltip) { tooltip.textColor(textColor); } return getThis(); @@ -439,7 +502,8 @@ public W tooltipTextColor(int textColor) { */ @Override public W tooltipTextShadow(boolean textShadow) { - for (RichTooltip tooltip : this.stateTooltip) { + expectCount(); + for (RichTooltip tooltip : this.tooltip) { tooltip.textShadow(textShadow); } return getThis(); @@ -453,25 +517,15 @@ public W tooltipTextShadow(boolean textShadow) { */ @Override public W tooltipShowUpTimer(int showUpTimer) { - for (RichTooltip tooltip : this.stateTooltip) { + expectCount(); + for (RichTooltip tooltip : this.tooltip) { tooltip.showUpTimer(showUpTimer); } return getThis(); } protected W stateCount(int stateCount) { - this.stateCount = stateCount; - // adjust tooltip buffer size - while (this.stateTooltip.size() < this.stateCount) { - this.stateTooltip.add(new RichTooltip().parent(this)); - } - while (this.stateTooltip.size() > this.stateCount) { - this.stateTooltip.remove(this.stateTooltip.size() - 1); - } - this.background = checkArray(this.background, stateCount); - this.overlay = checkArray(this.overlay, stateCount); - this.hoverBackground = checkArray(this.hoverBackground, stateCount); - this.hoverOverlay = checkArray(this.hoverOverlay, stateCount); + updateStateCount(stateCount, true); return getThis(); } @@ -486,6 +540,7 @@ protected IDrawable[] addToArray(IDrawable[] array, IDrawable[] drawable, int in protected IDrawable[] addToArray(IDrawable[] array, IDrawable drawable, int index) { if (index < 0) throw new IndexOutOfBoundsException(); + updateStateCount(index + 1, false); if (array == null || index >= array.length) { IDrawable[] copy = new IDrawable[(int) (Math.ceil((index + 1) / 4.0) * 4)]; if (array != null) { @@ -505,12 +560,14 @@ protected static void splitTexture(UITexture texture, IDrawable[] dest) { } protected W tooltip(int index, Consumer builder) { - builder.accept(this.stateTooltip.get(index)); + updateStateCount(index + 1, false); + builder.accept(this.tooltip[index]); return getThis(); } protected W tooltipBuilder(int index, Consumer builder) { - this.stateTooltip.get(index).tooltipBuilder(builder); + updateStateCount(index + 1, false); + this.tooltip[index].tooltipBuilder(builder); return getThis(); } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/ButtonWidget.java b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/ButtonWidget.java index d6dbf004945..6544e65447f 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/ButtonWidget.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/ButtonWidget.java @@ -2,11 +2,11 @@ import com.gregtechceu.gtceu.api.mui.base.ITheme; import com.gregtechceu.gtceu.api.mui.base.IThemeApi; +import com.gregtechceu.gtceu.api.mui.base.value.ISyncOrValue; import com.gregtechceu.gtceu.api.mui.base.widget.IGuiAction; import com.gregtechceu.gtceu.api.mui.base.widget.Interactable; import com.gregtechceu.gtceu.api.mui.theme.WidgetThemeEntry; import com.gregtechceu.gtceu.api.mui.value.sync.InteractionSyncHandler; -import com.gregtechceu.gtceu.api.mui.value.sync.SyncHandler; import com.gregtechceu.gtceu.api.mui.widget.SingleChildWidget; import com.gregtechceu.gtceu.common.mui.GTGuiTextures; @@ -41,14 +41,19 @@ public static ButtonWidget panelCloseButton() { private InteractionSyncHandler syncHandler; @Override - public boolean isValidSyncHandler(SyncHandler syncHandler) { - this.syncHandler = castIfTypeElseNull(syncHandler, InteractionSyncHandler.class); - return this.syncHandler != null; + public WidgetThemeEntry getWidgetThemeInternal(ITheme theme) { + return theme.getButtonTheme(); } @Override - public WidgetThemeEntry getWidgetThemeInternal(ITheme theme) { - return theme.getButtonTheme(); + public boolean isValidSyncOrValue(@NotNull ISyncOrValue syncOrValue) { + return syncOrValue.isTypeOrEmpty(InteractionSyncHandler.class); + } + + @Override + protected void setSyncOrValue(@NotNull ISyncOrValue syncOrValue) { + super.setSyncOrValue(syncOrValue); + this.syncHandler = syncOrValue.castNullable(InteractionSyncHandler.class); } public void playClickSound() { @@ -165,8 +170,7 @@ public W onKeyTapped(IGuiAction.KeyPressed keyTapped) { } public W syncHandler(InteractionSyncHandler interactionSyncHandler) { - this.syncHandler = interactionSyncHandler; - setSyncHandler(interactionSyncHandler); + setSyncOrValue(ISyncOrValue.orEmpty(interactionSyncHandler)); return getThis(); } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/DynamicSyncedWidget.java b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/DynamicSyncedWidget.java index 9d6607dff84..e77ac0086a4 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/DynamicSyncedWidget.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/DynamicSyncedWidget.java @@ -1,5 +1,6 @@ package com.gregtechceu.gtceu.api.mui.widgets; +import com.gregtechceu.gtceu.api.mui.base.value.ISyncOrValue; import com.gregtechceu.gtceu.api.mui.base.widget.IWidget; import com.gregtechceu.gtceu.api.mui.value.sync.DynamicSyncHandler; import com.gregtechceu.gtceu.api.mui.value.sync.SyncHandler; @@ -27,10 +28,15 @@ public class DynamicSyncedWidget> extends Widge private IWidget child; @Override - public boolean isValidSyncHandler(SyncHandler syncHandler) { - this.syncHandler = castIfTypeElseNull(syncHandler, DynamicSyncHandler.class, - t -> t.attachDynamicWidgetListener(this::updateChild)); - return this.syncHandler != null; + public boolean isValidSyncOrValue(@NotNull ISyncOrValue syncOrValue) { + return syncOrValue.isTypeOrEmpty(DynamicSyncHandler.class); + } + + @Override + protected void setSyncOrValue(@NotNull ISyncOrValue syncOrValue) { + super.setSyncOrValue(syncOrValue); + this.syncHandler = syncOrValue.castNullable(DynamicSyncHandler.class); + if (this.syncHandler != null) this.syncHandler.attachDynamicWidgetListener(this::updateChild); } @Override @@ -56,9 +62,7 @@ private void updateChild(IWidget widget) { } public W syncHandler(DynamicSyncHandler syncHandler) { - this.syncHandler = syncHandler; - setSyncHandler(syncHandler); - syncHandler.attachDynamicWidgetListener(this::updateChild); + setSyncOrValue(ISyncOrValue.orEmpty(syncHandler)); return getThis(); } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/ItemDisplayWidget.java b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/ItemDisplayWidget.java index e36c5601b7a..18647510dbf 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/ItemDisplayWidget.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/ItemDisplayWidget.java @@ -1,16 +1,18 @@ package com.gregtechceu.gtceu.api.mui.widgets; import com.gregtechceu.gtceu.api.mui.base.ITheme; +import com.gregtechceu.gtceu.api.mui.base.value.ISyncOrValue; import com.gregtechceu.gtceu.api.mui.base.value.IValue; import com.gregtechceu.gtceu.api.mui.drawable.GuiDraw; import com.gregtechceu.gtceu.api.mui.theme.WidgetThemeEntry; import com.gregtechceu.gtceu.api.mui.value.ObjectValue; -import com.gregtechceu.gtceu.api.mui.value.sync.SyncHandler; import com.gregtechceu.gtceu.api.mui.widget.Widget; import com.gregtechceu.gtceu.client.mui.screen.viewport.ModularGuiContext; import net.minecraft.world.item.ItemStack; +import org.jetbrains.annotations.NotNull; + public class ItemDisplayWidget extends Widget { private IValue value; @@ -21,9 +23,14 @@ public ItemDisplayWidget() { } @Override - public boolean isValidSyncHandler(SyncHandler syncHandler) { - this.value = castIfTypeGenericElseNull(syncHandler, ItemStack.class); - return this.value != null; + public boolean isValidSyncOrValue(@NotNull ISyncOrValue syncOrValue) { + return syncOrValue.isValueOfType(ItemStack.class); + } + + @Override + protected void setSyncOrValue(@NotNull ISyncOrValue syncOrValue) { + super.setSyncOrValue(syncOrValue); + this.value = syncOrValue.castValueNullable(ItemStack.class); } @Override @@ -43,14 +50,12 @@ public void draw(ModularGuiContext context, WidgetThemeEntry widgetTheme) { } public ItemDisplayWidget item(IValue itemSupplier) { - this.value = itemSupplier; - setValue(itemSupplier); + setSyncOrValue(ISyncOrValue.orEmpty(itemSupplier)); return this; } public ItemDisplayWidget item(ItemStack itemStack) { - ; - return item(new ObjectValue<>(itemStack)); + return item(new ObjectValue<>(ItemStack.class, itemStack)); } public ItemDisplayWidget displayAmount(boolean displayAmount) { diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/ProgressWidget.java b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/ProgressWidget.java index 0adf3d125f3..6691725b19c 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/ProgressWidget.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/ProgressWidget.java @@ -2,12 +2,12 @@ import com.gregtechceu.gtceu.api.mui.base.drawable.IDrawable; import com.gregtechceu.gtceu.api.mui.base.value.IDoubleValue; +import com.gregtechceu.gtceu.api.mui.base.value.ISyncOrValue; import com.gregtechceu.gtceu.api.mui.drawable.UITexture; import com.gregtechceu.gtceu.api.mui.theme.WidgetTheme; import com.gregtechceu.gtceu.api.mui.theme.WidgetThemeEntry; import com.gregtechceu.gtceu.api.mui.utils.Color; import com.gregtechceu.gtceu.api.mui.value.DoubleValue; -import com.gregtechceu.gtceu.api.mui.value.sync.SyncHandler; import com.gregtechceu.gtceu.api.mui.widget.Widget; import com.gregtechceu.gtceu.client.mui.screen.viewport.GuiContext; import com.gregtechceu.gtceu.client.mui.screen.viewport.ModularGuiContext; @@ -16,6 +16,7 @@ import net.minecraft.util.Mth; import lombok.experimental.Accessors; +import org.jetbrains.annotations.NotNull; import java.util.function.DoubleSupplier; @@ -47,9 +48,14 @@ public void onInit() { } @Override - public boolean isValidSyncHandler(SyncHandler syncHandler) { - this.doubleValue = castIfTypeElseNull(syncHandler, IDoubleValue.class); - return this.doubleValue != null; + public boolean isValidSyncOrValue(@NotNull ISyncOrValue syncOrValue) { + return syncOrValue.isTypeOrEmpty(IDoubleValue.class); + } + + @Override + protected void setSyncOrValue(@NotNull ISyncOrValue syncOrValue) { + super.setSyncOrValue(syncOrValue); + this.doubleValue = syncOrValue.castNullable(IDoubleValue.class); } @Override @@ -166,8 +172,7 @@ private void drawCircular(GuiContext context, float progress, WidgetTheme widget } public ProgressWidget value(IDoubleValue value) { - this.doubleValue = value; - setValue(value); + setSyncOrValue(ISyncOrValue.orEmpty(value)); return this; } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/SliderWidget.java b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/SliderWidget.java index 29842a45437..4b3f06e1636 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/SliderWidget.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/SliderWidget.java @@ -3,6 +3,7 @@ import com.gregtechceu.gtceu.api.mui.base.GuiAxis; import com.gregtechceu.gtceu.api.mui.base.drawable.IDrawable; import com.gregtechceu.gtceu.api.mui.base.value.IDoubleValue; +import com.gregtechceu.gtceu.api.mui.base.value.ISyncOrValue; import com.gregtechceu.gtceu.api.mui.base.widget.IGuiAction; import com.gregtechceu.gtceu.api.mui.base.widget.Interactable; import com.gregtechceu.gtceu.api.mui.drawable.Rectangle; @@ -10,7 +11,6 @@ import com.gregtechceu.gtceu.api.mui.theme.WidgetThemeEntry; import com.gregtechceu.gtceu.api.mui.utils.Color; import com.gregtechceu.gtceu.api.mui.value.DoubleValue; -import com.gregtechceu.gtceu.api.mui.value.sync.SyncHandler; import com.gregtechceu.gtceu.api.mui.widget.Widget; import com.gregtechceu.gtceu.api.mui.widget.sizer.Area; import com.gregtechceu.gtceu.api.mui.widget.sizer.Unit; @@ -69,9 +69,14 @@ public void onInit() { } @Override - public boolean isValidSyncHandler(SyncHandler syncHandler) { - this.doubleValue = castIfTypeElseNull(syncHandler, IDoubleValue.class); - return this.doubleValue != null; + public boolean isValidSyncOrValue(@NotNull ISyncOrValue syncOrValue) { + return syncOrValue.isTypeOrEmpty(IDoubleValue.class); + } + + @Override + protected void setSyncOrValue(@NotNull ISyncOrValue syncOrValue) { + super.setSyncOrValue(syncOrValue); + this.doubleValue = syncOrValue.castNullable(IDoubleValue.class); } @Override @@ -192,8 +197,7 @@ public String toString() { } public SliderWidget value(IDoubleValue value) { - this.doubleValue = value; - setValue(value); + setSyncOrValue(ISyncOrValue.orEmpty(value)); return this; } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/SortableListWidget.java b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/SortableListWidget.java index 7506eecd4ef..f107af52769 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/SortableListWidget.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/SortableListWidget.java @@ -169,7 +169,7 @@ public static class Item extends DraggableWidget> implements IValueWi private SortableListWidget listWidget; @Getter private int index = -1; - private int movingFrom = -1; // no usages? why added? + private final int movingFrom = -1; // no usages? why added? public Item(T value) { this.value = value; diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/slot/FluidSlot.java b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/slot/FluidSlot.java index fc9e51af547..e3d32ed16a8 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/slot/FluidSlot.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/slot/FluidSlot.java @@ -3,6 +3,7 @@ import com.gregtechceu.gtceu.api.mui.base.ITheme; import com.gregtechceu.gtceu.api.mui.base.drawable.IDrawable; import com.gregtechceu.gtceu.api.mui.base.drawable.IKey; +import com.gregtechceu.gtceu.api.mui.base.value.ISyncOrValue; import com.gregtechceu.gtceu.api.mui.base.widget.Interactable; import com.gregtechceu.gtceu.api.mui.drawable.GuiDraw; import com.gregtechceu.gtceu.api.mui.drawable.text.TextRenderer; @@ -12,7 +13,6 @@ import com.gregtechceu.gtceu.api.mui.utils.Color; import com.gregtechceu.gtceu.api.mui.utils.MouseData; import com.gregtechceu.gtceu.api.mui.value.sync.FluidSlotSyncHandler; -import com.gregtechceu.gtceu.api.mui.value.sync.SyncHandler; import com.gregtechceu.gtceu.api.mui.widget.Widget; import com.gregtechceu.gtceu.client.mui.screen.RichTooltip; import com.gregtechceu.gtceu.client.mui.screen.viewport.ModularGuiContext; @@ -166,9 +166,14 @@ public void onInit() { } @Override - public boolean isValidSyncHandler(SyncHandler syncHandler) { - this.syncHandler = castIfTypeElseNull(syncHandler, FluidSlotSyncHandler.class); - return this.syncHandler != null; + public boolean isValidSyncOrValue(@NotNull ISyncOrValue syncOrValue) { + return syncOrValue.isTypeOrEmpty(FluidSlotSyncHandler.class); + } + + @Override + protected void setSyncOrValue(@NotNull ISyncOrValue syncOrValue) { + super.setSyncOrValue(syncOrValue); + this.syncHandler = syncOrValue.castNullable(FluidSlotSyncHandler.class); } @Override @@ -306,8 +311,7 @@ public FluidSlot syncHandler(IFluidTank fluidTank) { } public FluidSlot syncHandler(FluidSlotSyncHandler syncHandler) { - setSyncHandler(syncHandler); - this.syncHandler = syncHandler; + setSyncOrValue(ISyncOrValue.orEmpty(syncHandler)); return this; } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/slot/ItemSlot.java b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/slot/ItemSlot.java index 41c446175b4..5a76f9eaf27 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/slot/ItemSlot.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/slot/ItemSlot.java @@ -2,6 +2,7 @@ import com.gregtechceu.gtceu.api.mui.base.ITheme; import com.gregtechceu.gtceu.api.mui.base.IThemeApi; +import com.gregtechceu.gtceu.api.mui.base.value.ISyncOrValue; import com.gregtechceu.gtceu.api.mui.base.widget.IVanillaSlot; import com.gregtechceu.gtceu.api.mui.base.widget.Interactable; import com.gregtechceu.gtceu.api.mui.drawable.GuiDraw; @@ -9,7 +10,6 @@ import com.gregtechceu.gtceu.api.mui.theme.SlotTheme; import com.gregtechceu.gtceu.api.mui.theme.WidgetThemeEntry; import com.gregtechceu.gtceu.api.mui.value.sync.ItemSlotSH; -import com.gregtechceu.gtceu.api.mui.value.sync.SyncHandler; import com.gregtechceu.gtceu.api.mui.widget.Widget; import com.gregtechceu.gtceu.client.mui.screen.ClientScreenHandler; import com.gregtechceu.gtceu.client.mui.screen.RichTooltip; @@ -69,9 +69,14 @@ public void onInit() { } @Override - public boolean isValidSyncHandler(SyncHandler syncHandler) { - this.syncHandler = castIfTypeElseNull(syncHandler, ItemSlotSH.class); - return this.syncHandler != null; + public boolean isValidSyncOrValue(@NotNull ISyncOrValue syncOrValue) { + return syncOrValue instanceof ItemSlotSH; + } + + @Override + protected void setSyncOrValue(@NotNull ISyncOrValue syncOrValue) { + super.setSyncOrValue(syncOrValue); + this.syncHandler = syncOrValue.castOrThrow(ItemSlotSH.class); } @Override @@ -208,8 +213,7 @@ public ItemSlot slot(IItemHandlerModifiable itemHandler, int index) { } public ItemSlot syncHandler(ItemSlotSH syncHandler) { - this.syncHandler = syncHandler; - setSyncHandler(this.syncHandler); + setSyncOrValue(ISyncOrValue.orEmpty(syncHandler)); return this; } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/slot/PhantomItemSlot.java b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/slot/PhantomItemSlot.java index 8b766e6bda9..0defd79b586 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/slot/PhantomItemSlot.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/slot/PhantomItemSlot.java @@ -1,13 +1,13 @@ package com.gregtechceu.gtceu.api.mui.widgets.slot; +import com.gregtechceu.gtceu.api.mui.base.value.ISyncOrValue; import com.gregtechceu.gtceu.api.mui.utils.MouseData; +import com.gregtechceu.gtceu.api.mui.value.sync.ItemSlotSH; import com.gregtechceu.gtceu.api.mui.value.sync.PhantomItemSlotSH; -import com.gregtechceu.gtceu.api.mui.value.sync.SyncHandler; import com.gregtechceu.gtceu.client.mui.screen.viewport.ModularGuiContext; import com.gregtechceu.gtceu.integration.xei.handlers.GhostIngredientSlot; import com.gregtechceu.gtceu.integration.xei.handlers.RecipeViewerHandler; -import net.minecraft.world.inventory.Slot; import net.minecraft.world.item.ItemStack; import com.mojang.blaze3d.systems.RenderSystem; @@ -25,9 +25,14 @@ public void onInit() { } @Override - public boolean isValidSyncHandler(SyncHandler syncHandler) { - this.syncHandler = castIfTypeElseNull(syncHandler, PhantomItemSlotSH.class); - return this.syncHandler != null && super.isValidSyncHandler(syncHandler); + public boolean isValidSyncOrValue(@NotNull ISyncOrValue syncOrValue) { + return syncOrValue instanceof PhantomItemSlotSH; + } + + @Override + protected void setSyncOrValue(@NotNull ISyncOrValue syncOrValue) { + super.setSyncOrValue(syncOrValue); + this.syncHandler = syncOrValue.castOrThrow(PhantomItemSlotSH.class); } @Override @@ -90,10 +95,12 @@ public PhantomItemSlotSH getSyncHandler() { @Override public PhantomItemSlot slot(ModularSlot slot) { - ((Slot) slot).index = -1; - this.syncHandler = new PhantomItemSlotSH(slot); - super.isValidSyncHandler(this.syncHandler); - setSyncHandler(this.syncHandler); + return syncHandler(new PhantomItemSlotSH(slot)); + } + + @Override + public PhantomItemSlot syncHandler(ItemSlotSH syncHandler) { + setSyncOrValue(ISyncOrValue.orEmpty(syncHandler)); return this; } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/textfield/TextFieldWidget.java b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/textfield/TextFieldWidget.java index 850fde43e46..e4961bd14d5 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/textfield/TextFieldWidget.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/textfield/TextFieldWidget.java @@ -5,8 +5,8 @@ import com.gregtechceu.gtceu.api.mui.base.drawable.IKey; import com.gregtechceu.gtceu.api.mui.base.drawable.ITextLine; import com.gregtechceu.gtceu.api.mui.base.value.IStringValue; +import com.gregtechceu.gtceu.api.mui.base.value.ISyncOrValue; import com.gregtechceu.gtceu.api.mui.value.StringValue; -import com.gregtechceu.gtceu.api.mui.value.sync.SyncHandler; import com.gregtechceu.gtceu.api.mui.value.sync.ValueSyncHandler; import com.gregtechceu.gtceu.client.mui.screen.RichTooltip; import com.gregtechceu.gtceu.client.mui.screen.viewport.ModularGuiContext; @@ -66,17 +66,20 @@ public void onInit() { } @Override - public boolean isValidSyncHandler(SyncHandler syncHandler) { - if (syncHandler instanceof IStringValue iStringValue && - syncHandler instanceof ValueSyncHandler valueSyncHandler) { - this.stringValue = iStringValue; + public boolean isValidSyncOrValue(@NotNull ISyncOrValue syncOrValue) { + return syncOrValue.isTypeOrEmpty(IStringValue.class); + } + + @Override + protected void setSyncOrValue(@NotNull ISyncOrValue syncOrValue) { + super.setSyncOrValue(syncOrValue); + this.stringValue = syncOrValue.castNullable(IStringValue.class); + if (syncOrValue instanceof ValueSyncHandler valueSyncHandler) { valueSyncHandler.setChangeListener(() -> { markTooltipDirty(); setText(this.stringValue.getValue().toString()); }); - return true; } - return false; } @Override @@ -218,8 +221,7 @@ public TextFieldWidget setDefaultNumber(double defaultNumber) { } public TextFieldWidget value(IStringValue stringValue) { - this.stringValue = stringValue; - setValue(stringValue); + setSyncOrValue(ISyncOrValue.orEmpty(stringValue)); return this; } diff --git a/src/main/java/com/gregtechceu/gtceu/client/mui/screen/ClientScreenHandler.java b/src/main/java/com/gregtechceu/gtceu/client/mui/screen/ClientScreenHandler.java index 28e5c62b8b9..008d852f1d3 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/mui/screen/ClientScreenHandler.java +++ b/src/main/java/com/gregtechceu/gtceu/client/mui/screen/ClientScreenHandler.java @@ -290,7 +290,7 @@ private static void onGuiChanged(Screen oldScreen, Screen newScreen) { private static void invalidateCurrentScreen() { // reset mouse inputs, relevant when screen gets reopened if (lastMui != null) { - lastMui.getScreen().getPanelManager().closeAll(); + lastMui.getScreen().getPanelManager().closeScreen(); lastMui = null; } currentScreen = null; @@ -349,7 +349,7 @@ private static boolean keyTyped(Screen screen, int keyCode, int scanCode, int mo private static void onClose() { if (currentScreen.getContext().hasDraggable()) { - currentScreen.getContext().dropDraggable(); + currentScreen.getContext().dropDraggable(true); } else { currentScreen.getPanelManager().closeTopPanel(); } diff --git a/src/main/java/com/gregtechceu/gtceu/client/mui/screen/ModularContainerMenu.java b/src/main/java/com/gregtechceu/gtceu/client/mui/screen/ModularContainerMenu.java index bff981ca015..8f0e0dddd91 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/mui/screen/ModularContainerMenu.java +++ b/src/main/java/com/gregtechceu/gtceu/client/mui/screen/ModularContainerMenu.java @@ -11,6 +11,7 @@ import com.gregtechceu.gtceu.utils.NetworkUtils; import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player; @@ -111,11 +112,25 @@ public AbstractContainerMenuAccessor acc() { } @MustBeInvokedByOverriders - @Override - public void removed(@NotNull Player player) { + public void opened() { + if (this.syncManager != null) { + this.syncManager.onOpen(); + } + } + + /** + * Called when this container closes. This is different to {@link AbstractContainerMenu#removed(Player)}, since that + * one is also + * called from {@link AbstractContainerScreen#removed()}, which means it is called even when the container may still + * exist. + * This happens when a temporary client screen takes over (like JEI,NEI,etc.). This is only called when the + * container actually closes. + */ + @MustBeInvokedByOverriders + public void removed() { super.removed(player); if (this.syncManager != null) { - this.syncManager.onClose(); + this.syncManager.dispose(); } } @@ -129,7 +144,7 @@ public void broadcastChanges() { this.init = false; } - @ApiStatus.Internal + @MustBeInvokedByOverriders public void onUpdate() { // detectAndSendChanges is potentially called multiple times per tick, while this method is called exactly once // per tick diff --git a/src/main/java/com/gregtechceu/gtceu/client/mui/screen/ModularPanel.java b/src/main/java/com/gregtechceu/gtceu/client/mui/screen/ModularPanel.java index 2f126f5481c..2375b70bf85 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/mui/screen/ModularPanel.java +++ b/src/main/java/com/gregtechceu/gtceu/client/mui/screen/ModularPanel.java @@ -6,6 +6,7 @@ import com.gregtechceu.gtceu.api.mui.base.MCHelper; import com.gregtechceu.gtceu.api.mui.base.layout.IViewport; import com.gregtechceu.gtceu.api.mui.base.layout.IViewportStack; +import com.gregtechceu.gtceu.api.mui.base.value.ISyncOrValue; import com.gregtechceu.gtceu.api.mui.base.widget.*; import com.gregtechceu.gtceu.api.mui.theme.WidgetThemeEntry; import com.gregtechceu.gtceu.api.mui.utils.HoveredWidgetList; @@ -13,7 +14,6 @@ import com.gregtechceu.gtceu.api.mui.utils.Interpolations; import com.gregtechceu.gtceu.api.mui.value.sync.PanelSyncHandler; import com.gregtechceu.gtceu.api.mui.value.sync.PanelSyncManager; -import com.gregtechceu.gtceu.api.mui.value.sync.SyncHandler; import com.gregtechceu.gtceu.api.mui.widget.ParentWidget; import com.gregtechceu.gtceu.api.mui.widget.WidgetTree; import com.gregtechceu.gtceu.api.mui.widget.sizer.Area; @@ -87,6 +87,8 @@ public static ModularPanel defaultPanel(@NotNull String name, int width, int hei private boolean resizeable = false; + private Runnable onCloseAction; + public ModularPanel(@NotNull String name) { this.name = Objects.requireNonNull(name, "A panels name must not be null and should be unique!"); center(); @@ -108,8 +110,19 @@ public void onInit() { } @Override - public boolean isValidSyncHandler(SyncHandler syncHandler) { - return syncHandler instanceof IPanelHandler; + public boolean isValidSyncOrValue(@NotNull ISyncOrValue syncOrValue) { + return syncOrValue.isTypeOrEmpty(IPanelHandler.class); + } + + @Override + protected void setSyncOrValue(@NotNull ISyncOrValue syncOrValue) { + super.setSyncOrValue(syncOrValue); + setPanelHandler(syncOrValue.castNullable(IPanelHandler.class)); + } + + @ApiStatus.Internal + public void setPanelSyncHandler(PanelSyncHandler syncHandler) { + setSyncOrValue(ISyncOrValue.orEmpty(syncHandler)); } /** @@ -239,17 +252,15 @@ public void onOpen(ModularScreen screen) { this.state = State.OPEN; } - boolean reopen(boolean strict) { - if (this.state != State.CLOSED) { - if (strict) throw new IllegalStateException(); - return false; - } + void reopen() { this.state = State.OPEN; - return true; } @MustBeInvokedByOverriders public void onClose() { + if (this.onCloseAction != null) { + this.onCloseAction.run(); + } this.state = State.CLOSED; if (this.panelHandler != null) { this.panelHandler.closePanelInternal(); @@ -323,6 +334,7 @@ public boolean onMousePressed(double mouseX, double mouseY, int button) { } } else { for (LocatedWidget widget : this.hovering) { + if (widget.getElement() == null || !widget.getElement().isValid()) continue; widget.applyMatrix(getContext()); IWidget w = widget.getElement(); if (w instanceof IDragResizeable resizeable && @@ -400,6 +412,7 @@ public boolean onMouseReleased(double mouseX, double mouseY, int button) { boolean tryTap = this.mouse.tryTap(button); // first see if the clicked widget is still hovered and try to interact with it for (LocatedWidget widget : this.hovering) { + if (widget.getElement() == null || !widget.getElement().isValid()) continue; if (this.mouse.isWidget(widget)) { if (widget.getElement() instanceof Interactable interactable && onMouseReleased(mouseX, mouseY, button, tryTap, widget, interactable)) { @@ -411,6 +424,7 @@ public boolean onMouseReleased(double mouseX, double mouseY, int button) { } // now try all other hovered for (LocatedWidget widget : this.hovering) { + if (widget.getElement() == null || !widget.getElement().isValid()) continue; if (!this.mouse.isWidget(widget) && widget.getElement() instanceof Interactable interactable && onMouseReleased(mouseX, mouseY, button, tryTap, widget, interactable)) { return true; @@ -463,6 +477,7 @@ public boolean onKeyPressed(int keyCode, int scanCode, int modifiers) { LocatedWidget pressed = null; boolean result = false; for (LocatedWidget widget : this.hovering) { + if (widget.getElement() == null || !widget.getElement().isValid()) continue; if (widget.getElement() instanceof Interactable interactable) { widget.applyMatrix(getContext()); Interactable.Result interactResult = interactable.onKeyPressed(keyCode, scanCode, modifiers); @@ -499,6 +514,7 @@ public boolean onKeyReleased(int keyCode, int scanCode, int modifiers) { boolean tryTap = this.keyboard.tryTap(keyCode); // first see if the clicked widget is still hovered and try to interact with it for (LocatedWidget widget : this.hovering) { + if (widget.getElement() == null || !widget.getElement().isValid()) continue; if (this.keyboard.isWidget(widget)) { if (widget.getElement() instanceof Interactable interactable && onKeyReleased(keyCode, scanCode, modifiers, tryTap, widget, interactable)) { @@ -510,6 +526,7 @@ public boolean onKeyReleased(int keyCode, int scanCode, int modifiers) { } // now try all other hovered for (LocatedWidget widget : this.hovering) { + if (widget.getElement() == null || !widget.getElement().isValid()) continue; if (!this.keyboard.isWidget(widget) && widget.getElement() instanceof Interactable interactable && onKeyReleased(keyCode, scanCode, modifiers, tryTap, widget, interactable)) { return true; @@ -561,6 +578,7 @@ public boolean onCharTyped(char codePoint, int modifiers) { LocatedWidget pressed = null; boolean result = false; for (LocatedWidget widget : this.hovering) { + if (widget.getElement() == null || !widget.getElement().isValid()) continue; if (widget.getElement() instanceof Interactable interactable) { widget.applyMatrix(getContext()); Interactable.Result interactResult = interactable.onCharTyped(codePoint, modifiers); @@ -591,6 +609,7 @@ public boolean onMouseScrolled(double mouseX, double mouseY, double delta) { } if (this.hovering.isEmpty()) return false; for (LocatedWidget widget : this.hovering) { + if (widget.getElement() == null || !widget.getElement().isValid()) continue; if (widget.getElement() instanceof Interactable interactable) { widget.applyMatrix(getContext()); boolean result = interactable.onMouseScrolled(mouseX, mouseY, delta); @@ -620,7 +639,8 @@ public boolean onMouseDrag(double mouseX, double mouseY, int button, double drag if (this.mouse.held && button == this.mouse.lastButton && this.mouse.lastPressed != null && - this.mouse.lastPressed.getElement() instanceof Interactable interactable) { + this.mouse.lastPressed.getElement() instanceof Interactable interactable && + this.mouse.lastPressed.getElement().isValid()) { this.mouse.lastPressed.applyMatrix(getContext()); interactable.onMouseDrag(mouseX, mouseY, button, dragX, dragY); this.mouse.lastPressed.unapplyMatrix(getContext()); @@ -635,7 +655,7 @@ private T interactFocused T defaultValue) { LocatedWidget focused = this.getContext().getFocusedWidget(); T result = defaultValue; - if (focused.getElement() instanceof Interactable interactable) { + if (focused.getElement() instanceof Interactable interactable && focused.getElement().isValid()) { focused.applyMatrix(getContext()); result = function.apply((W) interactable); focused.unapplyMatrix(getContext()); @@ -759,16 +779,6 @@ public final boolean isMainPanel() { return getScreen().getMainPanel() == this; } - @ApiStatus.Internal - @Override - public void setSyncHandler(@Nullable SyncHandler syncHandler) { - if (!isValidSyncHandler(syncHandler)) - throw new IllegalStateException("Panel SyncHandler's must implement IPanelHandler!"); - - super.setSyncHandler(syncHandler); - setPanelHandler((IPanelHandler) syncHandler); - } - @NotNull protected Animator getAnimator() { if (this.animator == null) { @@ -826,6 +836,11 @@ public ModularPanel resizeableOnDrag(boolean resizeable) { return this; } + public ModularPanel onCloseAction(Runnable onCloseAction) { + this.onCloseAction = onCloseAction; + return this; + } + @Deprecated @Override public ModularPanel name(String name) { diff --git a/src/main/java/com/gregtechceu/gtceu/client/mui/screen/ModularScreen.java b/src/main/java/com/gregtechceu/gtceu/client/mui/screen/ModularScreen.java index 103c8457f3e..b31f97e5eba 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/mui/screen/ModularScreen.java +++ b/src/main/java/com/gregtechceu/gtceu/client/mui/screen/ModularScreen.java @@ -326,7 +326,7 @@ public void render(@NotNull GuiGraphics graphics, int mouseX, int mouseY, float this.context.reset(); this.context.pushViewport(null, this.context.getScreenArea()); for (ModularPanel panel : this.panelManager.getReverseOpenPanels()) { - this.context.updateZ(panel.getArea().getPanelLayer() * 20); + this.context.updateZ(0); if (panel.disablePanelsBelow()) { GuiDraw.drawRect(graphics, 0, 0, this.context.getScreenArea().w(), this.context.getScreenArea().h(), Color.argb(16, 16, 16, (int) (125 * panel.getAlpha()))); @@ -354,7 +354,7 @@ public void drawForeground(GuiGraphics guiGraphics, float partialTicks) { this.context.reset(); this.context.pushViewport(null, this.context.getScreenArea()); for (ModularPanel panel : this.panelManager.getReverseOpenPanels()) { - this.context.updateZ(100 + panel.getArea().getPanelLayer() * 20); + this.context.updateZ(100); if (panel.isEnabled()) { WidgetTree.drawTreeForeground(panel, this.context); } diff --git a/src/main/java/com/gregtechceu/gtceu/client/mui/screen/PanelManager.java b/src/main/java/com/gregtechceu/gtceu/client/mui/screen/PanelManager.java index 51b8d504ec7..1a88270a9a5 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/mui/screen/PanelManager.java +++ b/src/main/java/com/gregtechceu/gtceu/client/mui/screen/PanelManager.java @@ -62,7 +62,7 @@ boolean tryInit() { if (this.panels.isEmpty()) { throw new IllegalStateException("Can't init in closed state!"); } - this.panels.forEach(p -> p.reopen(true)); + this.panels.forEach(ModularPanel::reopen); this.disposal.removeIf(this.panels::contains); setState(State.REOPENED); yield true; @@ -132,7 +132,6 @@ private void openPanel(ModularPanel panel, boolean resize) { panel.setPanelGuiContext(this.screen.getContext()); this.panels.add(0, panel); this.dirty = true; - panel.getArea().setPanelLayer((byte) this.panels.size()); panel.onOpen(this.screen); if (resize) { WidgetTree.resizeInternal(panel, true); @@ -233,8 +232,17 @@ public boolean closeAll() { return false; } + void closeScreen() { + // only close the screen without closing the panels + // this is useful when we expect the screen to reopen at some point and the sync managers are still available + if (this.state.isOpen) { + setState(State.CLOSED); + this.screen.onClose(); + } + } + private void finalizePanel(ModularPanel panel) { - panel.onClose(); + if (panel.isOpen()) panel.onClose(); if (!this.disposal.contains(panel)) { if (this.disposal.size() == DISPOSAL_CAPACITY) { this.disposal.remove(0).dispose(); @@ -265,6 +273,8 @@ public void dispose() { setState(State.WAIT_DISPOSAL); return; } + // make sure every panel gets closed before disposing + this.panels.forEach(this::finalizePanel); setState(State.CLOSED); this.disposal.forEach(ModularPanel::dispose); this.disposal.clear(); @@ -472,7 +482,7 @@ public enum State { */ REOPENED(true), /** - * Screen is closed after it was open. + * Screen is closed after it was open. Panels may still be considered open in some cases. */ CLOSED(false), /** diff --git a/src/main/java/com/gregtechceu/gtceu/client/mui/screen/RichTooltip.java b/src/main/java/com/gregtechceu/gtceu/client/mui/screen/RichTooltip.java index 578540874ad..112249d6bfb 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/mui/screen/RichTooltip.java +++ b/src/main/java/com/gregtechceu/gtceu/client/mui/screen/RichTooltip.java @@ -73,6 +73,19 @@ public RichTooltip() { parent(Area.ZERO); } + public void reset() { + clearText(); + this.pos = null; + this.tooltipBuilder = null; + this.showUpTimer = 0; + this.autoUpdate = false; + this.titleMargin = 0; + this.appliedMargin = true; + this.x = 0; + this.y = 0; + this.maxWidth = Integer.MAX_VALUE; + } + @Tolerate public RichTooltip parent(Area parent) { return parent(area -> area.set(parent)); diff --git a/src/main/java/com/gregtechceu/gtceu/client/mui/screen/viewport/ModularGuiContext.java b/src/main/java/com/gregtechceu/gtceu/client/mui/screen/viewport/ModularGuiContext.java index ddf755a2911..3af4237c2c0 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/mui/screen/viewport/ModularGuiContext.java +++ b/src/main/java/com/gregtechceu/gtceu/client/mui/screen/viewport/ModularGuiContext.java @@ -47,6 +47,7 @@ public class ModularGuiContext extends GuiContext { private final HoveredIterable hoveredWidgets; private LocatedElement draggable; + private int dragStartX = 0, dragStartY = 0; private int lastButton = -1; private long lastClickTime = 0; private int lastDragX, lastDragY; @@ -275,7 +276,7 @@ public boolean isMouseItemEmpty() { @ApiStatus.Internal public boolean onMousePressed(double mouseX, double mouseY, int button) { if ((button == 0 || button == 1) && isMouseItemEmpty() && hasDraggable()) { - dropDraggable(); + dropDraggable(true); return true; } return false; @@ -285,18 +286,19 @@ public boolean onMousePressed(double mouseX, double mouseY, int button) { public boolean onMouseReleased(double mouseX, double mouseY, int button) { if (button == this.lastButton && isMouseItemEmpty() && hasDraggable()) { long time = Util.getMillis(); - if (time - this.lastClickTime < 200) return false; - dropDraggable(); + dropDraggable((this.dragStartX == getAbsMouseX() && this.dragStartY == getAbsMouseY()) || + (time - this.lastClickTime) < 100); return true; } return false; } @ApiStatus.Internal - public void dropDraggable() { + public void dropDraggable(boolean shouldCancel) { this.draggable.applyMatrix(this); this.draggable.getElement() - .onDragEnd(this.draggable.getElement().canDropHere(getAbsMouseX(), getAbsMouseY(), getTopHovered())); + .onDragEnd(!shouldCancel && + this.draggable.getElement().canDropHere(getAbsMouseX(), getAbsMouseY(), getTopHovered())); // TODO: getTopHovered correct here? this.draggable.getElement().setMoving(false); this.draggable.unapplyMatrix(this); @@ -327,8 +329,9 @@ public boolean onHoveredClick(int button, LocatedWidget hovered) { } if (draggable.getElement().onDragStart(button)) { draggable.getElement().setMoving(true); - this.draggable = draggable; + this.dragStartX = getAbsMouseX(); + this.dragStartY = getAbsMouseY(); this.lastButton = button; this.lastClickTime = Util.getMillis(); return true; diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/GTMachines.java b/src/main/java/com/gregtechceu/gtceu/common/data/GTMachines.java index ec28bacac1e..a96ef257612 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/GTMachines.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/GTMachines.java @@ -24,6 +24,7 @@ import com.gregtechceu.gtceu.common.data.mui.GTSingleblockMachinePanels; import com.gregtechceu.gtceu.common.machine.electric.*; import com.gregtechceu.gtceu.common.machine.muimachine.TestMuiMachine; +import com.gregtechceu.gtceu.common.machine.muimachine.TestMuiMachine2; import com.gregtechceu.gtceu.common.machine.multiblock.part.*; import com.gregtechceu.gtceu.common.machine.multiblock.part.monitor.AdvancedMonitorPartMachine; import com.gregtechceu.gtceu.common.machine.multiblock.part.monitor.MonitorPartMachine; @@ -1143,7 +1144,7 @@ public class GTMachines { .register(); public static final MachineDefinition MUI_TEST_2 = REGISTRATE - .machine("test_mui_new", MonitorPartMachine::new) + .machine("test_mui_new", TestMuiMachine2::new) .rotationState(RotationState.ALL) .recipeType(GTRecipeTypes.ALLOY_SMELTER_RECIPES) .model(createOverlayCasingMachineModel(GTCEu.id("block/casings/solid/machine_casing_clean_stainless_steel"), diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/electric/ItemCollectorMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/electric/ItemCollectorMachine.java index 68c3f69740d..eb91cd6d16c 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/electric/ItemCollectorMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/electric/ItemCollectorMachine.java @@ -503,9 +503,9 @@ public ModularPanel buildUI(PosGuiData data, PanelSyncManager syncManager, UISet .childPadding(2) .excludeAreaInXei() .background(GTGuiTextures.BACKGROUND.getSubArea(0.25f, 0f, 1.0f, 1.0f)) - .child(GTMuiWidgets.createBatterySlot(getChargerInventory(), 0, syncManager)) .child(GTMuiWidgets.createPowerButton(this::isWorkingEnabled, this::setWorkingEnabled, syncManager)) + .child(GTMuiWidgets.createBatterySlot(getChargerInventory(), 0, syncManager)) .child(GTMuiWidgets.createAutoOutputItemButton(this, syncManager))); } } diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/muimachine/TestMuiMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/muimachine/TestMuiMachine.java index 03a0340bf8a..c9d012855fc 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/muimachine/TestMuiMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/muimachine/TestMuiMachine.java @@ -147,7 +147,7 @@ public ModularPanel buildUI(PosGuiData data, PanelSyncManager syncManager, UISet Rectangle colorPickerBackground = new Rectangle().setColor(Color.RED.main); ModularPanel panel = new ModularPanel("test_tile"); - IPanelHandler panelSyncHandler = syncManager.panel("other_panel", this::openSecondWindow, true); + IPanelHandler panelSyncHandler = syncManager.syncedPanel("other_panel", true, this::openSecondWindow); IPanelHandler colorPicker = IPanelHandler.simple(panel, (mainPanel, player) -> new ColorPickerDialog(colorPickerBackground::setColor, colorPickerBackground.getColor(), @@ -584,8 +584,8 @@ public ModularPanel openSecondWindow(PanelSyncManager syncManager, IPanelHandler syncManager.registerSlotGroup(slotGroup); AtomicInteger number = new AtomicInteger(0); syncManager.syncValue("int_value", new IntSyncValue(number::get, number::set)); - IPanelHandler panelSyncHandler = syncManager.panel("other_panel_2", - (syncManager1, syncHandler1) -> openThirdWindow(syncManager1, syncHandler1, number), true); + IPanelHandler panelSyncHandler = syncManager.syncedPanel("other_panel_2", true, + (syncManager1, syncHandler1) -> openThirdWindow(syncManager1, syncHandler1, number)); panel.child(ButtonWidget.panelCloseButton()) .child(new ButtonWidget<>() .size(10).top(14).right(4) diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/muimachine/TestMuiMachine2.java b/src/main/java/com/gregtechceu/gtceu/common/machine/muimachine/TestMuiMachine2.java new file mode 100644 index 00000000000..a1c0213b579 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/muimachine/TestMuiMachine2.java @@ -0,0 +1,21 @@ +package com.gregtechceu.gtceu.common.machine.muimachine; + +import com.gregtechceu.gtceu.api.machine.IMachineBlockEntity; +import com.gregtechceu.gtceu.api.machine.MetaMachine; +import com.gregtechceu.gtceu.api.machine.feature.IMuiMachine; +import com.gregtechceu.gtceu.api.mui.factory.PosGuiData; +import com.gregtechceu.gtceu.api.mui.value.sync.PanelSyncManager; +import com.gregtechceu.gtceu.client.mui.screen.ModularPanel; +import com.gregtechceu.gtceu.client.mui.screen.UISettings; + +public class TestMuiMachine2 extends MetaMachine implements IMuiMachine { + + public TestMuiMachine2(IMachineBlockEntity holder) { + super(holder); + } + + @Override + public ModularPanel buildUI(PosGuiData data, PanelSyncManager syncManager, UISettings settings) { + return null; + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/utils/serialization/network/ByteBufAdapters.java b/src/main/java/com/gregtechceu/gtceu/utils/serialization/network/ByteBufAdapters.java index f09c634fbe1..74e14ce9bea 100644 --- a/src/main/java/com/gregtechceu/gtceu/utils/serialization/network/ByteBufAdapters.java +++ b/src/main/java/com/gregtechceu/gtceu/utils/serialization/network/ByteBufAdapters.java @@ -14,6 +14,7 @@ import java.math.BigDecimal; import java.math.BigInteger; +import java.util.Objects; public class ByteBufAdapters { @@ -109,8 +110,7 @@ public boolean areEqual(@NotNull BigDecimal t1, @NotNull BigDecimal t2) { public static IByteBufAdapter makeAdapter(@NotNull IByteBufDeserializer deserializer, @NotNull IByteBufSerializer serializer, - @Nullable EqualityTest comparator) { - final EqualityTest tester = comparator != null ? comparator : EqualityTest.defaultTester(); + @Nullable EqualityTest tester) { return new IByteBufAdapter<>() { @Override @@ -125,7 +125,7 @@ public void serialize(FriendlyByteBuf buffer, T u) { @Override public boolean areEqual(@NotNull T t1, @NotNull T t2) { - return tester.areEqual(t1, t2); + return tester != null ? tester.areEqual(t1, t2) : Objects.equals(t1, t2); } }; }