Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 120 additions & 0 deletions src/main/java/com/cleanroommc/modularui/api/value/ISyncOrValue.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package com.cleanroommc.modularui.api.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.cleanroommc.modularui.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 <T> @Nullable T castNullable(Class<T> 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 <T> type to cast to
* @return this cast sync handler or value
*/
@Nullable
@SuppressWarnings("unchecked")
default <T> T castNullable(Class<T> type) {
return type.isAssignableFrom(getClass()) ? (T) this : null;
}

/**
* Casts this sync handler or value to a {@link IValue IValue&lt;V&gt;} 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 <V> expected type of the containing value
* @return a {@link IValue IValue&lt;V&gt;} if types match or null
*/
@Nullable
default <V> IValue<V> castValueNullable(Class<V> 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 <T> 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> T castOrThrow(Class<T> 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;
}
}
19 changes: 18 additions & 1 deletion src/main/java/com/cleanroommc/modularui/api/value/IValue.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*
* @param <T> value type
*/
public interface IValue<T> {
public interface IValue<T> extends ISyncOrValue {

/**
* Gets the current value.
Expand All @@ -20,4 +20,21 @@ public interface IValue<T> {
* @param value new value
*/
void setValue(T value);

Class<T> getValueType();

default boolean isValueOfType(Class<?> type) {
return type.isAssignableFrom(getValueType());
}

@SuppressWarnings("unchecked")
@Override
default <V> IValue<V> castValueNullable(Class<V> valueType) {
return isValueOfType(valueType) ? (IValue<V>) this : null;
}

@Override
default boolean isValueHandler() {
return true;
}
}
36 changes: 28 additions & 8 deletions src/main/java/com/cleanroommc/modularui/api/widget/ISynced.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.cleanroommc.modularui.api.widget;

import com.cleanroommc.modularui.api.value.ISyncOrValue;
import com.cleanroommc.modularui.value.sync.GenericSyncValue;
import com.cleanroommc.modularui.value.sync.ModularSyncManager;
import com.cleanroommc.modularui.value.sync.SyncHandler;
Expand Down Expand Up @@ -29,21 +30,32 @@ default W getThis() {
* Called when this widget gets initialised or when this widget is added to the gui
*
* @param syncManager sync manager
* @param late
* @param late if this is called at any point after the panel this widget belongs to opened
*/
void initialiseSyncHandler(ModularSyncManager syncManager, boolean late);

/**
* Checks and return if the received sync handler is valid for this widget This is usually an instanceof check. <br />
* <b>Synced widgets must override this!</b>
*
* @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.cleanroommc.modularui.api.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)}
Expand All @@ -52,17 +64,21 @@ default boolean isValidSyncHandler(SyncHandler syncHandler) {
* @throws IllegalStateException if the given sync handler is invalid for this widget.
*/
@ApiStatus.NonExtendable
default void checkValidSyncHandler(SyncHandler syncHandler) {
if (!isValidSyncHandler(syncHandler)) {
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> T castIfTypeElseNull(SyncHandler syncHandler, Class<T> clazz) {
return castIfTypeElseNull(syncHandler, clazz, null);
}

@ApiStatus.ScheduledForRemoval(inVersion = "3.2.0")
@Deprecated
@SuppressWarnings("unchecked")
default <T> T castIfTypeElseNull(SyncHandler syncHandler, Class<T> clazz, @Nullable Consumer<T> setup) {
if (syncHandler != null && clazz.isAssignableFrom(syncHandler.getClass())) {
Expand All @@ -73,10 +89,14 @@ default <T> T castIfTypeElseNull(SyncHandler syncHandler, Class<T> clazz, @Nulla
return null;
}

@ApiStatus.ScheduledForRemoval(inVersion = "3.2.0")
@Deprecated
default <T> GenericSyncValue<T> castIfTypeGenericElseNull(SyncHandler syncHandler, Class<T> clazz) {
return castIfTypeGenericElseNull(syncHandler, clazz, null);
}

@ApiStatus.ScheduledForRemoval(inVersion = "3.2.0")
@Deprecated
default <T> GenericSyncValue<T> castIfTypeGenericElseNull(SyncHandler syncHandler, Class<T> clazz,
@Nullable Consumer<GenericSyncValue<T>> setup) {
if (syncHandler instanceof GenericSyncValue<?> genericSyncValue && genericSyncValue.isOfType(clazz)) {
Expand Down
20 changes: 12 additions & 8 deletions src/main/java/com/cleanroommc/modularui/screen/ModularPanel.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import com.cleanroommc.modularui.api.UpOrDown;
import com.cleanroommc.modularui.api.layout.IViewport;
import com.cleanroommc.modularui.api.layout.IViewportStack;
import com.cleanroommc.modularui.api.value.ISyncOrValue;
import com.cleanroommc.modularui.api.widget.IDragResizeable;
import com.cleanroommc.modularui.api.widget.IFocusedWidget;
import com.cleanroommc.modularui.api.widget.IWidget;
Expand All @@ -25,7 +26,6 @@
import com.cleanroommc.modularui.utils.ObjectList;
import com.cleanroommc.modularui.value.sync.PanelSyncHandler;
import com.cleanroommc.modularui.value.sync.PanelSyncManager;
import com.cleanroommc.modularui.value.sync.SyncHandler;
import com.cleanroommc.modularui.widget.ParentWidget;
import com.cleanroommc.modularui.widget.WidgetTree;
import com.cleanroommc.modularui.widget.sizer.Area;
Expand Down Expand Up @@ -112,15 +112,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);
}

@ApiStatus.Internal
@Override
public void setSyncHandler(@Nullable SyncHandler syncHandler) {
super.setSyncHandler(syncHandler);
setPanelHandler((IPanelHandler) syncHandler);
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));
}

/**
Expand Down Expand Up @@ -612,7 +616,7 @@ public boolean onMouseDrag(int mouseButton, long timeSinceClick) {
mouseButton == this.mouse.lastButton &&
this.mouse.lastPressed != null &&
this.mouse.lastPressed.getElement() instanceof Interactable interactable &&
this.mouse.lastPressed.getElement().isValid()) {
this.mouse.lastPressed.getElement().isValid()) {
this.mouse.lastPressed.applyMatrix(getContext());
interactable.onMouseDrag(mouseButton, timeSinceClick);
this.mouse.lastPressed.unapplyMatrix(getContext());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Objects;

public class ByteBufAdapters {

Expand Down Expand Up @@ -108,8 +109,7 @@ public boolean areEqual(@NotNull BigDecimal t1, @NotNull BigDecimal t2) {
}
};

public static <T> IByteBufAdapter<T> makeAdapter(@NotNull IByteBufDeserializer<T> deserializer, @NotNull IByteBufSerializer<T> serializer, @Nullable IEquals<T> comparator) {
final IEquals<T> tester = comparator != null ? comparator : IEquals.defaultTester();
public static <T> IByteBufAdapter<T> makeAdapter(@NotNull IByteBufDeserializer<T> deserializer, @NotNull IByteBufSerializer<T> serializer, @Nullable IEquals<T> tester) {
return new IByteBufAdapter<>() {
@Override
public T deserialize(PacketBuffer buffer) throws IOException {
Expand All @@ -123,7 +123,7 @@ public void serialize(PacketBuffer buffer, T u) throws IOException {

@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);
}
};
}
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/com/cleanroommc/modularui/value/BoolValue.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ public void setStringValue(String val) {
setBoolValue(Boolean.parseBoolean(val));
}

@Override
public Class<Boolean> getValueType() {
return Boolean.class;
}

public static class Dynamic implements IBoolValue<Boolean>, IIntValue<Boolean>, IStringValue<Boolean> {

private final BooleanSupplier getter;
Expand Down Expand Up @@ -103,5 +108,10 @@ public int getIntValue() {
public void setIntValue(int val) {
setBoolValue(val == 1);
}

@Override
public Class<Boolean> getValueType() {
return Boolean.class;
}
}
}
5 changes: 5 additions & 0 deletions src/main/java/com/cleanroommc/modularui/value/ByteValue.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ public void setValue(Byte value) {
setByteValue(value);
}

@Override
public Class<Byte> getValueType() {
return Byte.class;
}

public static class Dynamic extends ByteValue {

private final Supplier getter;
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/com/cleanroommc/modularui/value/ConstValue.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,9 @@ public T getValue() {
public void setValue(T value) {
this.value = value;
}

@Override
public Class<T> getValueType() {
return (Class<T>) value.getClass();
}
}
10 changes: 10 additions & 0 deletions src/main/java/com/cleanroommc/modularui/value/DoubleValue.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ public void setFloatValue(float val) {
setDoubleValue(val);
}

@Override
public Class<Double> getValueType() {
return Double.class;
}

public static class Dynamic implements IDoubleValue<Double>, IStringValue<Double> {

private final DoubleSupplier getter;
Expand Down Expand Up @@ -104,5 +109,10 @@ public Double getValue() {
public void setValue(Double value) {
setDoubleValue(value);
}

@Override
public Class<Double> getValueType() {
return Double.class;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,9 @@ public void setValue(T value) {
this.setter.accept(value);
}
}

@Override
public Class<T> getValueType() {
return (Class<T>) this.getter.get().getClass();
}
}
Loading