Skip to content

Commit 7ca69c3

Browse files
Simplify window updating
1 parent 0624ed3 commit 7ca69c3

13 files changed

Lines changed: 230 additions & 233 deletions

File tree

invui/src/main/java/xyz/xenondevs/invui/gui/AbstractGui.java

Lines changed: 28 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,17 @@
88
import org.jetbrains.annotations.ApiStatus.Internal;
99
import org.jspecify.annotations.Nullable;
1010
import xyz.xenondevs.invui.Click;
11-
import xyz.xenondevs.invui.internal.Viewer;
1211
import xyz.xenondevs.invui.internal.ViewerAtSlot;
1312
import xyz.xenondevs.invui.internal.util.*;
1413
import xyz.xenondevs.invui.inventory.Inventory;
1514
import xyz.xenondevs.invui.inventory.ObscuredInventory;
1615
import xyz.xenondevs.invui.inventory.event.ItemPreUpdateEvent;
1716
import xyz.xenondevs.invui.inventory.event.PlayerUpdateReason;
1817
import xyz.xenondevs.invui.inventory.event.UpdateReason;
19-
import xyz.xenondevs.invui.item.*;
18+
import xyz.xenondevs.invui.item.BoundItem;
19+
import xyz.xenondevs.invui.item.Item;
20+
import xyz.xenondevs.invui.item.ItemProvider;
21+
import xyz.xenondevs.invui.item.ItemWrapper;
2022
import xyz.xenondevs.invui.util.ItemUtils;
2123
import xyz.xenondevs.invui.window.AbstractWindow;
2224
import xyz.xenondevs.invui.window.Window;
@@ -32,15 +34,15 @@
3234
*/
3335
@Internal
3436
public sealed abstract class AbstractGui
35-
implements Gui, Viewer
37+
implements Gui
3638
permits NormalGuiImpl, AbstractPagedGui, AbstractScrollGui, TabGuiImpl
3739
{
3840

3941
private final int width;
4042
private final int height;
4143
private final int size;
4244
private final @Nullable SlotElement[] slotElements;
43-
private final @Nullable Set<ViewerAtSlot<?>>[] viewers;
45+
private final @Nullable Set<ViewerAtSlot>[] viewers;
4446

4547
private boolean frozen;
4648
private boolean ignoreObscuredInventorySlots = true;
@@ -78,8 +80,8 @@ public void handleBundleSelect(Player player, int slot, int bundleSlot) {
7880
return;
7981

8082
SlotElement slotElement = slotElements[slot];
81-
switch(slotElement) {
82-
case SlotElement.GuiLink le -> ((AbstractGui)le.gui()).handleBundleSelect(player, le.slot(), bundleSlot);
83+
switch (slotElement) {
84+
case SlotElement.GuiLink le -> ((AbstractGui) le.gui()).handleBundleSelect(player, le.slot(), bundleSlot);
8385
case SlotElement.Item ie -> ie.item().handleBundleSelect(player, bundleSlot);
8486
case SlotElement.InventoryLink ie -> handleInvBundleSelect(player, ie.inventory(), ie.slot(), bundleSlot);
8587
case null -> {}
@@ -240,10 +242,10 @@ private void handleInvNumberKey(Click click, Inventory inventory, int slot) {
240242
AbstractWindow<?> window = (AbstractWindow<?>) WindowManager.getInstance().getOpenWindow(player);
241243
assert window != null;
242244

243-
Pair<AbstractGui, Integer> pair = window.getGuiAtHotbar(click.hotbarButton());
244-
if (pair == null)
245+
SlotElement.GuiLink link = window.getGuiAtHotbar(click.hotbarButton());
246+
if (link == null)
245247
return;
246-
SlotElement hotbarElement = pair.first().getSlotElement(pair.second());
248+
SlotElement hotbarElement = link.gui().getSlotElement(link.slot());
247249
if (hotbarElement == null)
248250
return;
249251
hotbarElement = hotbarElement.getHoldingElement();
@@ -413,18 +415,6 @@ public SequencedCollection<? extends Inventory> getInventories(Inventory... igno
413415
}
414416
//</editor-fold>
415417

416-
@Override
417-
public void notifyUpdate(int slot) {
418-
synchronized (viewers) {
419-
var viewers = this.viewers[slot];
420-
if (viewers != null) {
421-
for (var viewer : viewers) {
422-
viewer.notifyUpdate();
423-
}
424-
}
425-
}
426-
}
427-
428418
@Override
429419
public void notifyWindows() {
430420
synchronized (viewers) {
@@ -455,72 +445,55 @@ public void notifyWindows(int index) {
455445
}
456446
}
457447

458-
public void addViewer(Viewer who, int what, int how) {
448+
public void addViewer(AbstractWindow<?> who, int what, int how) {
459449
synchronized (viewers) {
460450
var viewerSet = this.viewers[what];
461451
if (viewerSet == null) {
462452
viewerSet = new HashSet<>();
463453
this.viewers[what] = viewerSet;
464454
}
465-
viewerSet.add(new ViewerAtSlot<>(who, how));
455+
viewerSet.add(new ViewerAtSlot(who, how));
466456
}
467457
}
468458

469-
public void removeViewer(Viewer who, int what, int how) {
459+
public void removeViewer(AbstractWindow<?> who, int what, int how) {
470460
synchronized (viewers) {
471461
var viewerSet = this.viewers[what];
472462
if (viewerSet != null) {
473-
viewerSet.remove(new ViewerAtSlot<>(who, how));
463+
viewerSet.remove(new ViewerAtSlot(who, how));
474464
if (viewerSet.isEmpty())
475465
this.viewers[what] = null;
476466
}
477467
}
478468
}
479469

480470
@Override
481-
public List<Window> findAllWindows() {
482-
// no need for synchronization on viewers because this method is called on-main and read-only
483-
var windows = new ArrayList<Window>();
484-
485-
var explored = new HashSet<Viewer>();
486-
var queue = new LinkedList<Viewer>();
487-
queue.add(this);
488-
489-
while (!queue.isEmpty()) {
490-
var current = queue.poll();
491-
explored.add(current);
492-
493-
if (current instanceof AbstractGui viewable) {
494-
for (var viewers : viewable.viewers) {
495-
if (viewers == null)
496-
continue;
497-
498-
for (var viewerAtSlot : viewers) {
499-
var viewer = viewerAtSlot.viewer();
500-
if (!explored.contains(viewer)) {
501-
queue.add(viewer);
502-
}
471+
public Collection<Window> getWindows() {
472+
synchronized (viewers) {
473+
var windows = new HashSet<Window>();
474+
for (var viewerSet : viewers) {
475+
if (viewerSet != null) {
476+
for (var viewerAtSlot : viewerSet) {
477+
windows.add(viewerAtSlot.window());
503478
}
504479
}
505-
} else if (current instanceof Window window) {
506-
windows.add(window);
507480
}
481+
482+
return Collections.unmodifiableSet(windows);
508483
}
509-
510-
return windows;
511484
}
512485

513486
@Override
514-
public Set<Player> findAllCurrentViewers() {
515-
return findAllWindows().stream()
487+
public Collection<Player> getCurrentViewers() {
488+
return getWindows().stream()
516489
.filter(Window::isOpen)
517490
.map(Window::getViewer)
518-
.collect(Collectors.toSet());
491+
.collect(Collectors.toUnmodifiableSet());
519492
}
520493

521494
@Override
522495
public void closeForAllViewers() {
523-
findAllCurrentViewers().forEach(Player::closeInventory);
496+
getCurrentViewers().forEach(Player::closeInventory);
524497
}
525498

526499
@Override
@@ -573,7 +546,6 @@ public void cancelAnimation() {
573546

574547
@Override
575548
public void setSlotElement(int index, @Nullable SlotElement slotElement) {
576-
SlotElement oldElement = slotElements[index];
577549
slotElements[index] = slotElement;
578550

579551
// set the gui if it is a bound item
@@ -583,16 +555,6 @@ public void setSlotElement(int index, @Nullable SlotElement slotElement) {
583555
}
584556
}
585557

586-
// remove this gui as a viewer from the old slot element's gui
587-
if (oldElement instanceof SlotElement.GuiLink(Gui gui, int slot)) {
588-
((AbstractGui) gui).removeViewer(this, slot, index);
589-
}
590-
591-
// add this gui as a viewer to the new slot element's viewable
592-
if (slotElement instanceof SlotElement.GuiLink(Gui gui, int slot)) {
593-
((AbstractGui) gui).addViewer(this, slot, index);
594-
}
595-
596558
// notify parents that a slot element has been changed
597559
var viewers = this.viewers[index];
598560
if (viewers != null) {

invui/src/main/java/xyz/xenondevs/invui/gui/Animation.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ default Builder filterTaggedSlots(char key, char... keys) {
203203
*/
204204
default Builder addSoundEffect(Sound sound, float volume, float pitch) {
205205
return addShowHandler((animation, slot) ->
206-
animation.getGui().findAllCurrentViewers().forEach(viewer ->
206+
animation.getGui().getCurrentViewers().forEach(viewer ->
207207
viewer.playSound(viewer, sound, volume, pitch)
208208
)
209209
);

invui/src/main/java/xyz/xenondevs/invui/gui/Gui.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import xyz.xenondevs.invui.item.ItemProvider;
99
import xyz.xenondevs.invui.window.Window;
1010

11+
import java.util.Collection;
1112
import java.util.List;
1213
import java.util.SequencedCollection;
1314
import java.util.Set;
@@ -493,22 +494,21 @@ static Gui single(Inventory inventory, int slot, ItemProvider background) {
493494
boolean isTagged(Slot slot, char key);
494495

495496
/**
496-
* Finds all {@link Window Windows} that show this {@link Gui}.
497+
* Gets all {@link Window Windows} that show this {@link Gui}.
497498
*
498-
* @return The list of {@link Window} that show this {@link Gui}
499+
* @return The collection of {@link Window} that show this {@link Gui}
499500
*/
500-
List<Window> findAllWindows();
501+
Collection<Window> getWindows();
501502

502503
/**
503-
* Finds all {@link Player Players} that are currently seeing this {@link Window}.
504+
* Gets all {@link Player Players} that are currently seeing this {@link Window}.
504505
*
505-
* @return The list of {@link Player Players} that are currently seeing this {@link Window}
506+
* @return The collection of {@link Player Players} that are currently seeing this {@link Window}
506507
*/
507-
Set<Player> findAllCurrentViewers();
508+
Collection<Player> getCurrentViewers();
508509

509510
/**
510-
* Closes the open {@link org.bukkit.inventory.Inventory} for all viewers of {@link Window Windows}
511-
* where this {@link Gui} is displayed.
511+
* Closes the all open {@link Window Windows} that display this {@link Gui}.
512512
*/
513513
void closeForAllViewers();
514514

invui/src/main/java/xyz/xenondevs/invui/gui/SlotElement.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77
import xyz.xenondevs.invui.inventory.Inventory;
88
import xyz.xenondevs.invui.item.ItemProvider;
99

10+
import java.util.ArrayList;
11+
import java.util.Collections;
12+
import java.util.List;
13+
1014
/**
1115
* Represents an element in a slot in a {@link Gui}.
1216
* You will rarely need to use this interface directly.
@@ -101,6 +105,26 @@ record GuiLink(Gui gui, int slot) implements SlotElement {
101105
return holdingElement != null ? holdingElement.getItemStack(player) : null;
102106
}
103107

108+
/**
109+
* Creates a {@link List} of all {@link SlotElement SlotElements} that are linked together,
110+
* starting with this {@link GuiLink}.
111+
*
112+
* @return A {@link List} of all linked {@link SlotElement SlotElements}
113+
*/
114+
public List<SlotElement> traverse() {
115+
var elements = new ArrayList<SlotElement>();
116+
117+
SlotElement current = this;
118+
while (current instanceof GuiLink(Gui g, int s)) {
119+
elements.add(current);
120+
current = g.getSlotElement(s);
121+
}
122+
if (current != null)
123+
elements.add(current);
124+
125+
return Collections.unmodifiableList(elements);
126+
}
127+
104128
}
105129

106130
}

invui/src/main/java/xyz/xenondevs/invui/internal/Viewer.java

Lines changed: 0 additions & 7 deletions
This file was deleted.
Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
package xyz.xenondevs.invui.internal;
22

3-
public record ViewerAtSlot<V extends Viewer>(V viewer, int slot) {
3+
import xyz.xenondevs.invui.window.AbstractWindow;
4+
5+
public record ViewerAtSlot(AbstractWindow<?> window, int slot) {
46

57
public void notifyUpdate() {
6-
viewer.notifyUpdate(slot);
8+
window.notifyUpdate(slot);
79
}
810

911
}

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

Lines changed: 0 additions & 4 deletions
This file was deleted.

0 commit comments

Comments
 (0)