Skip to content

Commit eea86db

Browse files
Cleanup/fix event processing
1 parent f597af3 commit eea86db

6 files changed

Lines changed: 108 additions & 102 deletions

File tree

src/main/java/io/github/apickledwalrus/skriptgui/elements/effects/EffCancelClose.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public static void register(SyntaxRegistry syntaxRegistry) {
4646
public boolean init(Expression<?>[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) {
4747
ParserInstance parser = getParser();
4848
if (!parser.isCurrentEvent(InventoryCloseEvent.class) || !SkriptUtils.isSection(parser, SecOpenClose.class)) {
49-
Skript.error("Cancelling or uncancelling the closing of a GUI can only be done within a GUI close section.");
49+
Skript.error("Canceling or uncanceling the closing of a GUI can only be done within a GUI close section.");
5050
return false;
5151
}
5252
cancel = parseResult.hasTag("cancel");

src/main/java/io/github/apickledwalrus/skriptgui/elements/expressions/ExprGUIValues.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import io.github.apickledwalrus.skriptgui.elements.sections.SecCreateGUI;
1919
import io.github.apickledwalrus.skriptgui.elements.sections.SecOpenClose;
2020
import io.github.apickledwalrus.skriptgui.elements.sections.SecMakeSlot;
21+
import io.github.apickledwalrus.skriptgui.elements.sections.SecSlotChange;
2122
import io.github.apickledwalrus.skriptgui.gui.GUI;
2223
import org.bukkit.entity.HumanEntity;
2324
import org.bukkit.entity.Player;
@@ -99,14 +100,14 @@ public boolean init(Expression<?>[] expressions, int matchedPattern, Kleenean is
99100
ParserInstance parser = getParser();
100101
if (SkriptUtils.isSection(parser, SecCreateGUI.class)) {
101102
if (value != Value.GUI) {
102-
Skript.error("You can't use '" + parseResult.expr + "' in a GUI open/close section.");
103+
Skript.error("You can't use '" + parseResult.expr + "' in a GUI creation section.");
103104
return false;
104105
}
105106
return true;
106107
}
107108

108-
if (!SkriptUtils.isSection(parser, SecMakeSlot.class, SecOpenClose.class)) {
109-
Skript.error("You can't use '" + parseResult.expr + "' outside of a GUI make or open/close section.");
109+
if (!SkriptUtils.isSection(parser, SecMakeSlot.class, SecOpenClose.class, SecSlotChange.class)) {
110+
Skript.error("You can't use '" + parseResult.expr + "' outside of a GUI section.");
110111
return false;
111112
}
112113

src/main/java/io/github/apickledwalrus/skriptgui/elements/expressions/ExprNextSlot.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import io.github.apickledwalrus.skriptgui.elements.sections.SecCreateGUI;
1616
import io.github.apickledwalrus.skriptgui.elements.sections.SecOpenClose;
1717
import io.github.apickledwalrus.skriptgui.elements.sections.SecMakeSlot;
18+
import io.github.apickledwalrus.skriptgui.elements.sections.SecSlotChange;
1819
import io.github.apickledwalrus.skriptgui.gui.GUI;
1920
import org.bukkit.event.Event;
2021
import org.jetbrains.annotations.Nullable;
@@ -44,7 +45,7 @@ public static void register(SyntaxRegistry syntaxRegistry) {
4445
@Override
4546
public boolean init(Expression<?>[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) {
4647
if (matchedPattern == 2) {
47-
if (!SkriptUtils.isSection(getParser(), SecCreateGUI.class, SecMakeSlot.class, SecOpenClose.class)) {
48+
if (!SkriptUtils.isSection(getParser(), SecCreateGUI.class, SecMakeSlot.class, SecOpenClose.class, SecSlotChange.class)) {
4849
Skript.error("The 'next gui slot' expression must have a GUI specified unless it is used in a GUI section.");
4950
return false;
5051
}

src/main/java/io/github/apickledwalrus/skriptgui/elements/sections/SecMakeSlot.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,8 @@ public boolean isMake() {
8585
@SuppressWarnings("unchecked")
8686
public boolean init(Expression<?>[] exprs, int matchedPattern, Kleenean kleenean, ParseResult parseResult,
8787
@Nullable SectionNode sectionNode, @Nullable List<TriggerItem> items) {
88-
if (!SkriptUtils.isSection(getParser(), SecCreateGUI.class, SecMakeSlot.class, SecOpenClose.class)) {
89-
Skript.error("You can't make a GUI slot outside of a GUI creation or editing section.");
88+
if (!SkriptUtils.isSection(getParser(), SecCreateGUI.class, SecMakeSlot.class, SecOpenClose.class, SecSlotChange.class)) {
89+
Skript.error("You can't make a GUI slot outside of a GUI section.");
9090
return false;
9191
}
9292

src/main/java/io/github/apickledwalrus/skriptgui/elements/sections/SecSlotChange.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,14 @@ public TriggerItem walk(Event event) {
8282

8383
Object[] slots = this.slots.getAll(event);
8484
for (Object slot : slots) {
85-
GUI.SlotData slotData = gui.getSlotData(gui.convert(slot));
86-
if (slotData == null) {
87-
continue;
85+
Character converted = gui.convert(slot);
86+
GUI.SlotData slotData = gui.getSlotData(converted);
87+
if (slotData == null) { // slot has not been set yet, initialize with dummy values
88+
gui.setItem(converted, null, false, null);
89+
slotData = gui.getSlotData(converted);
90+
if (slotData == null) {
91+
continue;
92+
}
8893
}
8994
slotData.setRunOnChange(onChange);
9095
}

src/main/java/io/github/apickledwalrus/skriptgui/gui/GUIEvents.java

Lines changed: 91 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -20,149 +20,148 @@
2020

2121
public final class GUIEvents implements Listener {
2222

23-
private void handleDoubleClick(GUI gui, InventoryClickEvent event) {
24-
GUIEventHandler eventHandler = gui.getEventHandler();
25-
26-
Inventory guiInventory = gui.getInventory();
27-
int size = guiInventory.getSize();
28-
ItemStack cursor = event.getCursor();
23+
private static InventoryClickEvent getClickEventWithSlot(InventoryClickEvent clickEvent, int slot) {
24+
return new InventoryClickEvent(
25+
clickEvent.getView(),
26+
clickEvent.getSlotType(),
27+
slot,
28+
clickEvent.getClick(),
29+
clickEvent.getAction()
30+
);
31+
}
2932

30-
if (event.getCurrentItem() != null)
33+
private static void handleDoubleClick(GUI gui, InventoryClickEvent clickEvent) {
34+
if (clickEvent.getCurrentItem() != null) {
3135
return;
36+
}
3237

38+
Inventory inventory = gui.getInventory();
39+
ItemStack cursor = clickEvent.getCursor();
3340
int totalAmount = cursor.getAmount();
34-
List<InventoryClickEvent> clickEvents = new ArrayList<>();
41+
int maxAmount = cursor.getMaxStackSize();
42+
int size = inventory.getSize();
43+
List<Integer> changedSlots = new ArrayList<>();
3544
for (int slot = 0; slot < size; slot++) {
36-
ItemStack item = guiInventory.getItem(slot);
37-
if (item != null && item.isSimilar(cursor)) {
38-
if (!gui.isChangeable(gui.convert(slot))) {
39-
event.setCancelled(true);
40-
return;
41-
}
45+
ItemStack item = inventory.getItem(slot);
46+
if (item == null || !item.isSimilar(cursor)) { // not a candidate for merging
47+
continue;
48+
}
4249

43-
if (totalAmount < cursor.getMaxStackSize()) {
44-
InventoryClickEvent clickEvent = getClickEventWithSlot(event, slot);
45-
clickEvents.add(clickEvent);
46-
totalAmount += item.getAmount();
47-
}
50+
if (!gui.isChangeable(gui.convert(slot))) { // would result in merging of an unchangeable slot
51+
clickEvent.setCancelled(true);
52+
return;
53+
}
54+
55+
changedSlots.add(slot);
56+
totalAmount += item.getAmount();
57+
if (totalAmount >= maxAmount) { // no other slots will be changed
58+
break;
4859
}
4960
}
50-
for (InventoryClickEvent clickEvent : clickEvents) {
51-
eventHandler.onChange(clickEvent);
52-
}
53-
}
5461

55-
private static InventoryClickEvent getClickEventWithSlot(InventoryClickEvent event, int slot) {
56-
return new InventoryClickEvent(
57-
event.getView(),
58-
event.getSlotType(),
59-
slot,
60-
event.getClick(),
61-
event.getAction()
62-
);
62+
GUIEventHandler eventHandler = gui.getEventHandler();
63+
for (int slot : changedSlots) {
64+
eventHandler.onChange(getClickEventWithSlot(clickEvent, slot));
65+
}
6366
}
6467

6568
@EventHandler(priority = EventPriority.LOWEST)
66-
public void onInventoryClick(InventoryClickEvent event) {
67-
// Process this event if it's cancelled ONLY if the clicker is in Spectator Mode
68-
if (event.getWhoClicked().getGameMode() != GameMode.SPECTATOR && event.isCancelled()) {
69+
public void onInventoryClick(InventoryClickEvent clickEvent) {
70+
// Process this event if it's canceled ONLY if the clicker is in Spectator Mode
71+
if (clickEvent.getWhoClicked().getGameMode() != GameMode.SPECTATOR && clickEvent.isCancelled()) {
6972
return;
7073
}
7174

7275
// Don't handle this event if it's from an unsupported click type
73-
switch (event.getClick()) {
76+
switch (clickEvent.getClick()) {
7477
case WINDOW_BORDER_RIGHT:
7578
case WINDOW_BORDER_LEFT:
7679
case CREATIVE:
7780
return;
7881
}
7982

8083
// No inventory was clicked
81-
Inventory clickedInventory = event.getClickedInventory();
84+
Inventory clickedInventory = clickEvent.getClickedInventory();
8285
if (clickedInventory == null) {
8386
return;
8487
}
8588

8689
// Don't handle this event if there isn't a matching GUI for it
87-
GUI gui = SkriptGUI.getGUIManager().getGUI(event.getInventory());
90+
GUI gui = SkriptGUI.getGUIManager().getGUI(clickEvent.getInventory());
8891
if (gui == null) {
8992
return;
9093
}
9194
GUIEventHandler eventHandler = gui.getEventHandler();
9295

9396
// Don't process unknown clicks for safety reasons - cancel them to prevent unwanted GUI changes
94-
if (event.getClick() == ClickType.UNKNOWN) {
95-
event.setCancelled(true);
97+
if (clickEvent.getClick() == ClickType.UNKNOWN) {
98+
clickEvent.setCancelled(true);
9699
return;
97100
}
98101

99102
// Don't handle this event if the clicked inventory is the bottom inventory, as we want users to be able to interact with their inventory
100103
// However, there are some cases where interaction with the bottom inventory may cause changes to the top inventory
101104
// Because of this, we will cancel the event for some click types
102-
if (clickedInventory.equals(event.getView().getBottomInventory())) {
103-
switch (event.getClick()) {
105+
if (clickedInventory.equals(clickEvent.getView().getBottomInventory())) {
106+
switch (clickEvent.getClick()) {
104107
case SHIFT_LEFT:
105108
case SHIFT_RIGHT:
106-
ItemStack clicked = event.getCurrentItem();
107-
if (clicked != null) {
108-
Inventory guiInventory = gui.getInventory();
109+
ItemStack clicked = clickEvent.getCurrentItem();
110+
if (clicked == null) {
111+
clickEvent.setCancelled(true);
112+
return;
113+
}
109114

110-
int size = guiInventory.getSize();
111-
int totalAmount = clicked.getAmount();
115+
Inventory guiInventory = gui.getInventory();
112116

113-
for (int slot = 0; slot < size; slot++) {
114-
if (totalAmount <= 0) {
115-
return;
116-
}
117+
int size = guiInventory.getSize();
118+
int totalAmount = clicked.getAmount();
117119

118-
ItemStack item = guiInventory.getItem(slot);
119-
if (item != null && item.getType() != Material.AIR && item.isSimilar(clicked) && item.getAmount() < item.getMaxStackSize()) {
120-
InventoryClickEvent clickEvent = getClickEventWithSlot(event, slot);
121-
122-
if (!gui.isChangeable(gui.convert(slot))) {
123-
event.setCancelled(true);
124-
return;
125-
} else {
126-
eventHandler.onChange(clickEvent);
127-
totalAmount -= item.getMaxStackSize() - item.getAmount();
128-
}
120+
List<Integer> changedSlots = new ArrayList<>();
121+
for (int slot = 0; slot < size; slot++) {
122+
ItemStack item = guiInventory.getItem(slot);
123+
if (item != null && item.getType() != Material.AIR && item.isSimilar(clicked) && item.getAmount() < item.getMaxStackSize()) {
124+
if (!gui.isChangeable(gui.convert(slot))) { // Would result in a non-changeable slot being changed, thus block
125+
clickEvent.setCancelled(true);
126+
return;
129127
}
130-
128+
// slot will have some amount distributed to it
129+
changedSlots.add(slot);
130+
totalAmount -= item.getMaxStackSize() - item.getAmount();
131+
}
132+
if (totalAmount <= 0) {
133+
break;
131134
}
135+
}
132136

137+
if (totalAmount > 0) {
133138
int firstEmpty = guiInventory.firstEmpty();
134-
if (firstEmpty != -1 && gui.isChangeable(gui.convert(firstEmpty))) { // Safe to be moved into the GUI
135-
InventoryClickEvent clickEvent = getClickEventWithSlot(event, firstEmpty);
136-
eventHandler.onChange(clickEvent);
137-
return;
139+
if (firstEmpty != -1) {
140+
if (!gui.isChangeable(gui.convert(firstEmpty))) { // slot would be illegally modified
141+
clickEvent.setCancelled(true);
142+
return;
143+
}
144+
// the rest of the item can go in this slot
145+
changedSlots.add(firstEmpty);
138146
}
139-
140147
}
141148

142-
event.setCancelled(true);
149+
for (int slot : changedSlots) {
150+
eventHandler.onChange(getClickEventWithSlot(clickEvent, slot));
151+
}
143152
return;
144153
case DOUBLE_CLICK:
145-
// Only cancel if this will cause a change to the GUI itself
146-
// We are checking if our GUI contains an item that could be merged with the event item
147-
// If that item is mergeable, but it isn't changeable, we will cancel the event now
148-
handleDoubleClick(gui, event);
154+
handleDoubleClick(gui, clickEvent);
149155
return;
150156
default:
151157
return;
152158
}
153-
} else {
154-
// Call onChange if a slot is changed due to interactions within the gui itself
155-
if (event.getClick() == ClickType.DOUBLE_CLICK) {
156-
if (!gui.isChangeable(gui.convert(event.getSlot()))) { // Doesn't change the slots
157-
event.setCancelled(true);
158-
return;
159-
}
160-
161-
handleDoubleClick(gui, event);
162-
}
159+
} else if (clickEvent.getClick() == ClickType.DOUBLE_CLICK && gui.isChangeable(gui.convert(clickEvent.getSlot()))) {
160+
// a double click (merge operation) can only occur if the source slot can be modified
161+
handleDoubleClick(gui, clickEvent);
163162
}
164163

165-
gui.getEventHandler().onClick(event);
164+
gui.getEventHandler().onClick(clickEvent);
166165
}
167166

168167
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
@@ -184,26 +183,26 @@ public void onInventoryDrag(InventoryDragEvent dragEvent) {
184183
}
185184

186185
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
187-
public void onInventoryOpen(InventoryOpenEvent event) {
188-
GUI gui = SkriptGUI.getGUIManager().getGUI(event.getInventory());
186+
public void onInventoryOpen(InventoryOpenEvent openEvent) {
187+
GUI gui = SkriptGUI.getGUIManager().getGUI(openEvent.getInventory());
189188
if (gui != null) {
190-
gui.getEventHandler().onOpen(event);
189+
gui.getEventHandler().onOpen(openEvent);
191190
}
192191
}
193192

194193
@EventHandler(priority = EventPriority.LOWEST)
195-
public void onInventoryClose(InventoryCloseEvent event) {
196-
GUI gui = SkriptGUI.getGUIManager().getGUI(event.getInventory());
194+
public void onInventoryClose(InventoryCloseEvent closeEvent) {
195+
GUI gui = SkriptGUI.getGUIManager().getGUI(closeEvent.getInventory());
197196
if (gui != null) {
198-
gui.getEventHandler().onClose(event);
197+
gui.getEventHandler().onClose(closeEvent);
199198
}
200199
}
201200

202201
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
203-
public void onRecipeBookClick(PlayerRecipeBookClickEvent event) {
204-
GUI gui = SkriptGUI.getGUIManager().getGUI(event.getPlayer().getOpenInventory().getTopInventory());
202+
public void onRecipeBookClick(PlayerRecipeBookClickEvent recipeEvent) {
203+
GUI gui = SkriptGUI.getGUIManager().getGUI(recipeEvent.getPlayer().getOpenInventory().getTopInventory());
205204
if (gui != null) {
206-
event.setCancelled(true);
205+
recipeEvent.setCancelled(true);
207206
}
208207
}
209208

0 commit comments

Comments
 (0)