Skip to content

Commit 037d08b

Browse files
Use (Mutable)Property for Window state
1 parent 71b4fba commit 037d08b

15 files changed

+354
-293
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package xyz.xenondevs.invui.window
2+
3+
import xyz.xenondevs.commons.provider.MutableProvider
4+
import xyz.xenondevs.invui.ExperimentalReactiveApi
5+
6+
@Suppress("UNCHECKED_CAST")
7+
@ExperimentalReactiveApi
8+
fun AnvilWindow.Builder.addRenameHandler(handler: MutableProvider<String>): AnvilWindow.Builder =
9+
addRenameHandler(handler::set)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package xyz.xenondevs.invui.window
2+
3+
import xyz.xenondevs.commons.provider.MutableProvider
4+
import xyz.xenondevs.invui.ExperimentalReactiveApi
5+
import xyz.xenondevs.invui.MutablePropertyAdapter
6+
import xyz.xenondevs.invui.gui.Slot
7+
8+
@ExperimentalReactiveApi
9+
fun CrafterWindow.Builder.setSlot(slot: Int, provider: MutableProvider<Boolean>): CrafterWindow.Builder =
10+
setSlot(slot, MutablePropertyAdapter(provider))
11+
12+
@ExperimentalReactiveApi
13+
fun CrafterWindow.Builder.setSlot(x: Int, y: Int, provider: MutableProvider<Boolean>): CrafterWindow.Builder =
14+
setSlot(x, y, MutablePropertyAdapter(provider))
15+
16+
@ExperimentalReactiveApi
17+
fun CrafterWindow.Builder.setSlot(slot: Slot, provider: MutableProvider<Boolean>): CrafterWindow.Builder =
18+
setSlot(slot, MutablePropertyAdapter(provider))
19+
20+
@ExperimentalReactiveApi
21+
fun CrafterWindow.Builder.setSlots(slots: List<MutableProvider<Boolean>>): CrafterWindow.Builder =
22+
setSlots(slots.map { MutablePropertyAdapter(it) })
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package xyz.xenondevs.invui.window
2+
3+
import xyz.xenondevs.commons.provider.Provider
4+
import xyz.xenondevs.invui.ExperimentalReactiveApi
5+
import xyz.xenondevs.invui.PropertyAdapter
6+
7+
@ExperimentalReactiveApi
8+
fun MerchantWindow.Builder.setTrades(trades: Provider<List<MerchantWindow.Trade>>): MerchantWindow.Builder =
9+
setTrades(PropertyAdapter(trades))
10+
11+
@ExperimentalReactiveApi
12+
fun MerchantWindow.Builder.setLevel(level: Provider<Int>): MerchantWindow.Builder =
13+
setLevel(PropertyAdapter(level))
14+
15+
@ExperimentalReactiveApi
16+
fun MerchantWindow.Builder.setProgress(progress: Provider<Double>): MerchantWindow.Builder =
17+
setProgress(PropertyAdapter(progress))
18+
19+
@ExperimentalReactiveApi
20+
fun MerchantWindow.Builder.setRestockMessageEnabled(restockMessageEnabled: Provider<Boolean>): MerchantWindow.Builder =
21+
setRestockMessageEnabled(PropertyAdapter(restockMessageEnabled))
22+
23+
@ExperimentalReactiveApi
24+
fun MerchantWindow.Trade.Builder.setDiscount(discount: Provider<Int>): MerchantWindow.Trade.Builder =
25+
setDiscount(PropertyAdapter(discount))
26+
27+
@ExperimentalReactiveApi
28+
fun MerchantWindow.Trade.Builder.setAvailable(available: Provider<Boolean>): MerchantWindow.Trade.Builder =
29+
setAvailable(PropertyAdapter(available))

invui-kotlin/src/main/kotlin/xyz/xenondevs/invui/window/ReactiveWindows.kt

-82
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package xyz.xenondevs.invui.window
2+
3+
import xyz.xenondevs.commons.provider.MutableProvider
4+
import xyz.xenondevs.invui.ExperimentalReactiveApi
5+
import xyz.xenondevs.invui.MutablePropertyAdapter
6+
7+
@ExperimentalReactiveApi
8+
fun StonecutterWindow.Builder.setSelectedSlot(provider: MutableProvider<Int>): StonecutterWindow.Builder =
9+
setSelectedSlot(MutablePropertyAdapter(provider))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package xyz.xenondevs.invui.window
2+
3+
import net.kyori.adventure.text.Component
4+
import xyz.xenondevs.commons.provider.MutableProvider
5+
import xyz.xenondevs.commons.provider.Provider
6+
import xyz.xenondevs.invui.ExperimentalReactiveApi
7+
8+
@Suppress("UNCHECKED_CAST")
9+
@ExperimentalReactiveApi
10+
fun <S : Window.Builder<*, *>> S.setTitle(provider: Provider<Component>): S {
11+
addModifier { window -> provider.observeWeak(window) { weakWindow -> weakWindow.updateTitle() } }
12+
return setTitleSupplier(provider) as S
13+
}

invui/src/main/java/xyz/xenondevs/invui/internal/menu/CustomCrafterMenu.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ private void handleSlotStateChange(ServerboundContainerSlotStateChangedPacket pa
8080
dataSlots[slot] = value;
8181

8282
if (slotStateChangeHandler != null)
83-
slotStateChangeHandler.accept(slot, packet.newState());
83+
slotStateChangeHandler.accept(slot, !packet.newState());
8484
}
8585

8686
}

invui/src/main/java/xyz/xenondevs/invui/internal/util/CollectionUtils.java

+20
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22

33
import xyz.xenondevs.invui.InvUI;
44

5+
import java.util.ArrayList;
6+
import java.util.List;
57
import java.util.function.Consumer;
8+
import java.util.function.Function;
69
import java.util.logging.Level;
710

811
public class CollectionUtils {
@@ -28,4 +31,21 @@ public static <T> void forEachCatching(Iterable<? extends T> iterable, Consumer<
2831
}
2932
}
3033

34+
/**
35+
* Creates a new {@link List} of the specified size, filled with the results of the
36+
* specified {@link Function initializer}.
37+
*
38+
* @param size The size of the list to create
39+
* @param initializer The {@link Function} to use to initialize the elements of the list
40+
* @param <T> The type of the elements in the list
41+
* @return A new {@link List} of the specified size, filled with the results of the
42+
*/
43+
public static <T> List<T> create(int size, Function<? super Integer, ? extends T> initializer) {
44+
var list = new ArrayList<T>();
45+
for (int i = 0; i < size; i++) {
46+
list.add(initializer.apply(i));
47+
}
48+
return list;
49+
}
50+
3151
}

invui/src/main/java/xyz/xenondevs/invui/internal/util/ItemUtils2.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
@SuppressWarnings("UnstableApiUsage")
2121
public class ItemUtils2 {
2222

23-
private static final ItemStack NON_EMPTY_PLACEHOLDER = new ItemBuilder(Material.STONE)
23+
private static final ItemStack NON_EMPTY_PLACEHOLDER = new ItemBuilder(Material.BARRIER)
2424
.hideTooltip(true)
2525
.set(DataComponentTypes.ITEM_MODEL, Key.key("air"))
2626
.build();

invui/src/main/java/xyz/xenondevs/invui/window/CrafterWindow.java

+46
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import org.jspecify.annotations.Nullable;
55
import xyz.xenondevs.invui.gui.Gui;
66
import xyz.xenondevs.invui.gui.Slot;
7+
import xyz.xenondevs.invui.state.MutableProperty;
78

89
import java.util.List;
910
import java.util.function.BiConsumer;
@@ -189,6 +190,51 @@ default Builder setResultGui(Gui.Builder<?, ?> builder) {
189190
*/
190191
Builder addSlotToggleHandler(BiConsumer<? super Integer, ? super Boolean> handler);
191192

193+
/**
194+
* Sets the property that contains the disabled state of the slot at the given index.
195+
*
196+
* @param slot The slot index
197+
* @param state The property that contains the disabled state of the slot
198+
* @return This {@link Builder}
199+
* @throws IllegalArgumentException If the slot index is out of bounds (0-8)
200+
*/
201+
Builder setSlot(int slot, MutableProperty<Boolean> state);
202+
203+
/**
204+
* Sets the property that contains the disabled state of the slot at the given coordinates.
205+
*
206+
* @param x The x coordinate of the slot
207+
* @param y The y coordinate of the slot
208+
* @param state The property that contains the disabled state of the slot
209+
* @return This {@link Builder}
210+
* @throws IllegalArgumentException If the slot coordinates are out of bounds (0-2, 0-2)
211+
*/
212+
default Builder setSlot(int x, int y, MutableProperty<Boolean> state) {
213+
return setSlot(x + y * 3, state);
214+
}
215+
216+
/**
217+
* Sets the property that contains the disabled state of the slot at the given coordinates.
218+
*
219+
* @param slot The slot
220+
* @param state The property that contains the disabled state of the slot
221+
* @return This {@link Builder}
222+
* @throws IllegalArgumentException If the slot coordinates are out of bounds (0-2, 0-2)
223+
*/
224+
default Builder setSlot(Slot slot, MutableProperty<Boolean> state) {
225+
return setSlot(slot.x(), slot.y(), state);
226+
}
227+
228+
/**
229+
* Sets the slot properties that contain the disabled state of the slots, ordered by their slot index.
230+
* The given list must contain exactly 9 properties.
231+
*
232+
* @param slots The slot properties that contain the disabled state of the slots
233+
* @return This {@link Builder}
234+
* @throws IllegalArgumentException If the list does not contain exactly 9 properties
235+
*/
236+
Builder setSlots(List<? extends MutableProperty<Boolean>> slots);
237+
192238
}
193239

194240
}

invui/src/main/java/xyz/xenondevs/invui/window/CrafterWindowImpl.java

+39-3
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
import xyz.xenondevs.invui.gui.AbstractGui;
99
import xyz.xenondevs.invui.gui.Gui;
1010
import xyz.xenondevs.invui.internal.menu.CustomCrafterMenu;
11+
import xyz.xenondevs.invui.internal.util.CollectionUtils;
12+
import xyz.xenondevs.invui.state.MutableProperty;
1113

1214
import java.util.ArrayList;
1315
import java.util.Collections;
@@ -17,9 +19,12 @@
1719

1820
final class CrafterWindowImpl extends AbstractSplitWindow<CustomCrafterMenu> implements CrafterWindow {
1921

22+
private static final int CRAFTING_SLOTS = 9;
23+
2024
private final AbstractGui craftingGui;
2125
private final AbstractGui resultGui;
2226
private final AbstractGui lowerGui;
27+
private final List<? extends MutableProperty<Boolean>> slots;
2328
private final List<BiConsumer<? super Integer, ? super Boolean>> slotToggleHandlers;
2429

2530
CrafterWindowImpl(
@@ -28,6 +33,7 @@ final class CrafterWindowImpl extends AbstractSplitWindow<CustomCrafterMenu> imp
2833
AbstractGui craftingGui,
2934
AbstractGui resultGui,
3035
AbstractGui lowerGui,
36+
List<? extends MutableProperty<Boolean>> slots,
3137
List<BiConsumer<? super Integer, ? super Boolean>> slotToggleHandlers,
3238
boolean closeable
3339
) {
@@ -40,12 +46,20 @@ final class CrafterWindowImpl extends AbstractSplitWindow<CustomCrafterMenu> imp
4046
this.craftingGui = craftingGui;
4147
this.resultGui = resultGui;
4248
this.lowerGui = lowerGui;
49+
this.slots = slots;
4350
this.slotToggleHandlers = slotToggleHandlers;
44-
45-
menu.setSlotStateChangeHandler(this::handleSlotToggled);
51+
52+
for (int i = 0; i < CRAFTING_SLOTS; i++) {
53+
int slot = i;
54+
MutableProperty<Boolean> property = slots.get(i);
55+
property.observeWeak(this, thisRef -> thisRef.menu.setSlotDisabled(slot, property.get()));
56+
menu.setSlotDisabled(i, property.get());
57+
}
58+
menu.setSlotStateChangeHandler(this::playerToggleSlot);
4659
}
4760

48-
private void handleSlotToggled(int slot, boolean disabled) {
61+
private void playerToggleSlot(int slot, boolean disabled) {
62+
slots.get(slot).set(disabled);
4963
for (var handler : slotToggleHandlers) {
5064
handler.accept(slot, disabled);
5165
}
@@ -54,6 +68,7 @@ private void handleSlotToggled(int slot, boolean disabled) {
5468
@Override
5569
public void setSlotDisabled(int slot, boolean disabled) {
5670
menu.setSlotDisabled(slot, disabled);
71+
slots.get(slot).set(disabled);
5772
}
5873

5974
@Override
@@ -96,6 +111,7 @@ static final class BuilderImpl
96111
private Supplier<? extends Gui> craftingGuiSupplier = () -> Gui.empty(3, 3);
97112
private Supplier<? extends Gui> resultGuiSupplier = () -> Gui.empty(1, 1);
98113
private final List<BiConsumer<? super Integer, ? super Boolean>> slotToggleHandlers = new ArrayList<>();
114+
private final List<MutableProperty<Boolean>> slots = CollectionUtils.create(9, i -> MutableProperty.of(false));
99115

100116
@Override
101117
public CrafterWindow.Builder setCraftingGui(Supplier<? extends Gui> guiSupplier) {
@@ -122,6 +138,25 @@ public CrafterWindow.Builder addSlotToggleHandler(BiConsumer<? super Integer, ?
122138
return this;
123139
}
124140

141+
@Override
142+
public CrafterWindow.Builder setSlot(int slot, MutableProperty<Boolean> state) {
143+
if (slot < 0 || slot >= CRAFTING_SLOTS)
144+
throw new IllegalArgumentException("Slot must be between 0 and 8");
145+
slots.set(slot, state);
146+
return this;
147+
}
148+
149+
@Override
150+
public CrafterWindow.Builder setSlots(List<? extends MutableProperty<Boolean>> slots) {
151+
if (slots.size() != CRAFTING_SLOTS)
152+
throw new IllegalArgumentException("Slots must contain exactly " + CRAFTING_SLOTS + " properties");
153+
154+
for (int i = 0; i < CRAFTING_SLOTS; i++) {
155+
this.slots.set(i, slots.get(i));
156+
}
157+
return this;
158+
}
159+
125160
@Override
126161
public CrafterWindowImpl build(Player viewer) {
127162
var window = new CrafterWindowImpl(
@@ -130,6 +165,7 @@ public CrafterWindowImpl build(Player viewer) {
130165
(AbstractGui) craftingGuiSupplier.get(),
131166
(AbstractGui) resultGuiSupplier.get(),
132167
supplyLowerGui(viewer),
168+
slots,
133169
slotToggleHandlers,
134170
closeable
135171
);

0 commit comments

Comments
 (0)