Skip to content

Commit 1b6d201

Browse files
committed
Rewrite data slots using observable properties
1 parent 6e75d6e commit 1b6d201

File tree

4 files changed

+39
-45
lines changed

4 files changed

+39
-45
lines changed

src/main/java/io/github/cottonmc/cotton/gui/impl/DataSlotImpl.java

Lines changed: 7 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,38 @@
11
package io.github.cottonmc.cotton.gui.impl;
22

3-
import net.fabricmc.fabric.api.event.Event;
4-
import net.fabricmc.fabric.api.event.EventFactory;
5-
63
import io.github.cottonmc.cotton.gui.SyncedGuiDescription;
74
import io.github.cottonmc.cotton.gui.networking.DataSlot;
85
import io.github.cottonmc.cotton.gui.networking.NetworkDirection;
96
import io.github.cottonmc.cotton.gui.networking.ScreenMessageKey;
10-
11-
import java.util.Objects;
7+
import io.github.cottonmc.cotton.gui.widget.data.ObservableProperty;
128

139
public final class DataSlotImpl<T> implements DataSlot<T> {
1410
private final SyncedGuiDescription owner;
1511
private final ScreenMessageKey<T> key;
16-
private T value;
12+
private final ObservableProperty<T> value;
1713
private final NetworkDirection networkDirection;
18-
private final Event<ChangeListener<T>> valueChangedEvent;
1914
private boolean dirty = false;
2015

2116
public DataSlotImpl(SyncedGuiDescription owner, ScreenMessageKey<T> key, T initialValue, NetworkDirection networkDirection) {
2217
this.owner = owner;
2318
this.key = key;
24-
this.value = initialValue;
19+
this.value = ObservableProperty.of(initialValue).name("value").build();
20+
this.value.addListener((property, from, to) -> dirty = true);
2521
this.networkDirection = networkDirection;
26-
this.valueChangedEvent = EventFactory.createArrayBacked(ChangeListener.class, listeners -> (dataSlot, value) -> {
27-
for (ChangeListener<T> listener : listeners) {
28-
listener.onValueChanged(dataSlot, value);
29-
}
30-
});
3122
}
3223

33-
public T get() {
24+
@Override
25+
public ObservableProperty<T> valueProperty() {
3426
return value;
3527
}
3628

37-
public void set(T value) {
38-
if (!Objects.equals(this.value, value)) {
39-
this.value = value;
40-
dirty = true;
41-
valueChangedEvent.invoker().onValueChanged(this, value);
42-
}
43-
}
44-
4529
public void checkAndSendUpdate() {
4630
if (dirty) {
47-
owner.getNetworking(networkDirection.from()).send(key, value);
31+
owner.getNetworking(networkDirection.from()).send(key, value.get());
4832
dirty = false;
4933
}
5034
}
5135

52-
@Override
53-
public Event<ChangeListener<T>> getValueChangedEvent() {
54-
return valueChangedEvent;
55-
}
56-
5736
@Override
5837
public ScreenMessageKey<T> getKey() {
5938
return key;

src/main/java/io/github/cottonmc/cotton/gui/networking/DataSlot.java

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package io.github.cottonmc.cotton.gui.networking;
22

3-
import net.fabricmc.fabric.api.event.Event;
4-
3+
import io.github.cottonmc.cotton.gui.widget.data.ObservableProperty;
54
import org.jetbrains.annotations.ApiStatus;
65

76
/**
@@ -31,35 +30,50 @@
3130
* }
3231
*
3332
* // You can listen to data slot updates on both sides:
34-
* myData.getValueChangedEvent().register((dataSlot, value) -> {
35-
* System.out.println("updated data: " + value);
33+
* myData.addChangeListener((dataSlot, from, to) -> {
34+
* System.out.println("updated data: " + value);
3635
* });
3736
* }
3837
*
38+
* @properties
3939
* @param <T> the data slot content type
4040
* @see io.github.cottonmc.cotton.gui.SyncedGuiDescription#registerDataSlot(ScreenMessageKey, Object, NetworkDirection)
4141
* @since 13.1.0
4242
*/
4343
@ApiStatus.NonExtendable
4444
public interface DataSlot<T> {
45+
/**
46+
* Returns the current value of the data slot.
47+
* The result is an <em>observable property</em> that can be modified and listened to.
48+
*
49+
* @return the {@code value} property
50+
*/
51+
ObservableProperty<T> valueProperty();
52+
4553
/**
4654
* {@return the current value of the data slot}
4755
*/
48-
T get();
56+
default T get() {
57+
return valueProperty().get();
58+
}
4959

5060
/**
5161
* Sets the current value of the data slot.
52-
* If it's not equal to the previous value,
53-
* {@link #getValueChangedEvent()} will be triggered.
5462
*
5563
* @param value the new value
5664
*/
57-
void set(T value);
65+
default void set(T value) {
66+
valueProperty().set(value);
67+
}
5868

5969
/**
60-
* {@return an event triggered when this data slot's value changes}
70+
* Adds a change listener to this data slot.
71+
*
72+
* @param listener the added listener
6173
*/
62-
Event<ChangeListener<T>> getValueChangedEvent();
74+
default void addChangeListener(ChangeListener<T> listener) {
75+
valueProperty().addListener((property, from, to) -> listener.onValueChanged(this, from, to));
76+
}
6377

6478
/**
6579
* {@return the key of the message that syncs this data slot}
@@ -73,7 +87,7 @@ public interface DataSlot<T> {
7387
NetworkDirection getNetworkDirection();
7488

7589
/**
76-
* A listener for {@link #getValueChangedEvent()}.
90+
* A listener for data slot value changes.
7791
*
7892
* @param <T> the data slot content type
7993
*/
@@ -83,8 +97,9 @@ interface ChangeListener<T> {
8397
* Called when a data slot's value changes.
8498
*
8599
* @param dataSlot the data slot for which the event was triggered
86-
* @param value the new value
100+
* @param from the old value
101+
* @param to the new value
87102
*/
88-
void onValueChanged(DataSlot<T> dataSlot, T value);
103+
void onValueChanged(DataSlot<T> dataSlot, T from, T to);
89104
}
90105
}

src/main/java/io/github/cottonmc/cotton/gui/widget/WWidget.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -493,7 +493,7 @@ public boolean canHover() {
493493

494494
/**
495495
* Returns whether the user is hovering over this widget.
496-
* The result is an <i>observable property</i> that can be modified and listened to.
496+
* The result is an <em>observable property</em> that can be modified and listened to.
497497
*
498498
* <p>This property takes into account {@link #isWithinBounds(int, int)} to check
499499
* if the cursor is within the bounds, as well as {@link #canHover()} to enable hovering at all.

src/testMod/java/io/github/cottonmc/test/TestDescription.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,9 @@ public TestDescription(ScreenHandlerType<?> type, int syncId, PlayerInventory pl
104104
// The button will never be yellow! Initial values won't be synced.
105105
buttonColor = registerDataSlot(BUTTON_COLOR_DATA_SLOT, 0xFF_FFFF00, NetworkDirection.CLIENT_TO_SERVER);
106106

107-
buttonLabel.getValueChangedEvent().register((dataSlot, value) -> buttonA.setLabel(value));
108-
buttonColor.getValueChangedEvent().register((dataSlot, value) -> {
109-
buttonB.setLabel(buttonB.getLabel().copy().withColor(value));
107+
buttonLabel.addChangeListener((dataSlot, from, to) -> buttonA.setLabel(to));
108+
buttonColor.addChangeListener((dataSlot, from, to) -> {
109+
buttonB.setLabel(buttonB.getLabel().copy().withColor(to));
110110
});
111111

112112
getNetworking(NetworkSide.SERVER).receive(TEST_MESSAGE, Codec.INT, value -> {

0 commit comments

Comments
 (0)