Skip to content

Commit b007177

Browse files
Catch exceptions thrown in handlers and properties
1 parent d83c577 commit b007177

15 files changed

+234
-118
lines changed

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

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,7 @@
1010
import org.jspecify.annotations.Nullable;
1111
import xyz.xenondevs.invui.Click;
1212
import xyz.xenondevs.invui.internal.ViewerAtSlot;
13-
import xyz.xenondevs.invui.internal.util.ArrayUtils;
14-
import xyz.xenondevs.invui.internal.util.InventoryUtils;
15-
import xyz.xenondevs.invui.internal.util.ItemUtils2;
16-
import xyz.xenondevs.invui.internal.util.SlotUtils;
13+
import xyz.xenondevs.invui.internal.util.*;
1714
import xyz.xenondevs.invui.inventory.Inventory;
1815
import xyz.xenondevs.invui.inventory.ObscuredInventory;
1916
import xyz.xenondevs.invui.inventory.OperationCategory;
@@ -43,6 +40,10 @@ public sealed abstract class AbstractGui
4340
permits NormalGuiImpl, AbstractPagedGui, AbstractScrollGui, TabGuiImpl
4441
{
4542

43+
private static final boolean DEFAULT_FROZEN = false;
44+
private static final boolean DEFAULT_IGNORE_OBSCURED_INVENTORY_SLOTS = true;
45+
private static final @Nullable ItemProvider DEFAULT_BACKGROUND = null;
46+
4647
private final int width;
4748
private final int height;
4849
private final int size;
@@ -459,7 +460,7 @@ private Map<? extends Inventory, Set<Integer>> getAllActiveInventorySlots(Invent
459460

460461
@Override
461462
public @Unmodifiable Collection<Inventory> getInventories(Inventory... ignored) {
462-
if (!ignoreObscuredInventorySlots.get())
463+
if (!isIgnoreObscuredInventorySlots())
463464
return Collections.unmodifiableCollection(getAllActiveInventorySlots(ignored).keySet());
464465

465466
ArrayList<Inventory> inventories = new ArrayList<>();
@@ -741,7 +742,7 @@ public void addItems(Item... items) {
741742

742743
@Override
743744
public @Nullable ItemProvider getBackground() {
744-
return background.get();
745+
return FuncUtils.getSafely(background, DEFAULT_BACKGROUND);
745746
}
746747

747748
@Override
@@ -778,7 +779,7 @@ public void setFrozen(boolean frozen) {
778779

779780
@Override
780781
public boolean isFrozen() {
781-
return frozen.get() || (animation != null && animation.isFreezing());
782+
return FuncUtils.getSafely(frozen, DEFAULT_FROZEN) || (animation != null && animation.isFreezing());
782783
}
783784

784785
@Override
@@ -788,7 +789,7 @@ public void setIgnoreObscuredInventorySlots(boolean ignoreObscuredInventorySlots
788789

789790
@Override
790791
public boolean isIgnoreObscuredInventorySlots() {
791-
return ignoreObscuredInventorySlots.get();
792+
return FuncUtils.getSafely(ignoreObscuredInventorySlots, DEFAULT_IGNORE_OBSCURED_INVENTORY_SLOTS);
792793
}
793794

794795
//<editor-fold desc="ingredient-key-based methods">
@@ -1056,9 +1057,9 @@ static sealed abstract class AbstractBuilder<G extends Gui, S extends Builder<G,
10561057

10571058
protected @Nullable Structure structure;
10581059
protected @Nullable List<Consumer<? super G>> modifiers;
1059-
protected MutableProperty<@Nullable ItemProvider> background = MutableProperty.of(null);
1060-
protected MutableProperty<Boolean> frozen = MutableProperty.of(false);
1061-
protected MutableProperty<Boolean> ignoreObscuredInventorySlots = MutableProperty.of(true);
1060+
protected MutableProperty<@Nullable ItemProvider> background = MutableProperty.of(DEFAULT_BACKGROUND);
1061+
protected MutableProperty<Boolean> frozen = MutableProperty.of(DEFAULT_FROZEN);
1062+
protected MutableProperty<Boolean> ignoreObscuredInventorySlots = MutableProperty.of(DEFAULT_IGNORE_OBSCURED_INVENTORY_SLOTS);
10621063

10631064
@Override
10641065
public S setStructure(int width, int height, String structureData) {

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

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import org.jspecify.annotations.Nullable;
66
import xyz.xenondevs.invui.internal.util.CollectionUtils;
77
import xyz.xenondevs.invui.internal.util.SlotUtils;
8+
import xyz.xenondevs.invui.internal.util.FuncUtils;
89
import xyz.xenondevs.invui.item.ItemProvider;
910
import xyz.xenondevs.invui.state.MutableProperty;
1011

@@ -20,6 +21,8 @@ sealed abstract class AbstractPagedGui<C>
2021
permits PagedInventoriesGuiImpl, PagedItemsGuiImpl, PagedNestedGuiImpl
2122
{
2223

24+
private static final int DEFAULT_PAGE = 0;
25+
2326
protected int[] contentListSlots;
2427

2528
private final MutableProperty<Integer> page;
@@ -35,7 +38,7 @@ public AbstractPagedGui(
3538
MutableProperty<List<? extends C>> content
3639
) {
3740
super(width, height);
38-
this.page = MutableProperty.of(0);
41+
this.page = MutableProperty.of(DEFAULT_PAGE);
3942
page.observeWeak(this, AbstractPagedGui::handlePageChange);
4043
this.content = content;
4144
content.observeWeak(this, AbstractPagedGui::bake);
@@ -78,16 +81,21 @@ public void setContentListSlots(SequencedSet<Slot> slots) {
7881
}
7982

8083
private void handlePageChange() {
81-
int targetPage = page.get();
84+
int targetPage = getPage();
8285
int correctedPage = correctPage(targetPage);
8386
if (targetPage != correctedPage) {
8487
page.set(correctedPage);
8588
return;
8689
}
8790

8891
updateContent();
89-
if (targetPage != previousPage)
90-
pageChangeHandlers.forEach(handler -> handler.accept(previousPage, targetPage));
92+
if (targetPage != previousPage) {
93+
CollectionUtils.forEachCatching(
94+
pageChangeHandlers,
95+
handler -> handler.accept(previousPage, targetPage),
96+
"Failed to handle page change from " + previousPage + " to " + targetPage
97+
);
98+
}
9199
previousPage = targetPage;
92100
}
93101

@@ -113,14 +121,16 @@ public void setBakedPages(@Nullable List<? extends List<SlotElement>> pages) {
113121
this.pages = pages;
114122
int newPageCount = getPageCount();
115123

116-
for (var handler : pageCountChangeHandlers) {
117-
handler.accept(prevPageCount, newPageCount);
118-
}
124+
CollectionUtils.forEachCatching(
125+
pageCountChangeHandlers,
126+
handler -> handler.accept(prevPageCount, newPageCount),
127+
"Failed to handle page count change from " + prevPageCount + " to " + newPageCount
128+
);
119129
}
120130

121131
@Override
122132
public @UnmodifiableView List<C> getContent() {
123-
return Collections.unmodifiableList(content.get());
133+
return Collections.unmodifiableList(FuncUtils.getSafely(content, List.of()));
124134
}
125135

126136
@Override
@@ -135,7 +145,7 @@ public void setPage(int page) {
135145

136146
@Override
137147
public int getPage() {
138-
return page.get();
148+
return FuncUtils.getSafely(page, DEFAULT_PAGE);
139149
}
140150

141151
@Override
@@ -198,7 +208,7 @@ public static sealed abstract class AbstractBuilder<C>
198208

199209
private final Constructor<C> ctor;
200210
private MutableProperty<List<? extends C>> content = MutableProperty.of(List.of());
201-
private MutableProperty<Integer> page = MutableProperty.of(0);
211+
private MutableProperty<Integer> page = MutableProperty.of(DEFAULT_PAGE);
202212
private List<BiConsumer<? super Integer, ? super Integer>> pageChangeHandlers = new ArrayList<>(0);
203213
private List<BiConsumer<? super Integer, ? super Integer>> pageCountChangeHandlers = new ArrayList<>(0);
204214

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

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import xyz.xenondevs.invui.internal.util.ArrayUtils;
77
import xyz.xenondevs.invui.internal.util.CollectionUtils;
88
import xyz.xenondevs.invui.internal.util.SlotUtils;
9+
import xyz.xenondevs.invui.internal.util.FuncUtils;
910
import xyz.xenondevs.invui.item.ItemProvider;
1011
import xyz.xenondevs.invui.state.MutableProperty;
1112

@@ -21,6 +22,8 @@ sealed abstract class AbstractScrollGui<C>
2122
permits ScrollItemsGuiImpl, ScrollNestedGuiImpl, ScrollInventoryGuiImpl
2223
{
2324

25+
private static final int DEFAULT_LINE = 0;
26+
2427
private int lineLength;
2528
private int[] contentListSlots = new int[0];
2629

@@ -38,7 +41,7 @@ public AbstractScrollGui(
3841
MutableProperty<List<? extends C>> content
3942
) {
4043
super(width, height);
41-
this.line = MutableProperty.of(0);
44+
this.line = MutableProperty.of(DEFAULT_LINE);
4245
line.observeWeak(this, AbstractScrollGui::handleLineChange);
4346
this.content = content;
4447
content.observeWeak(this, AbstractScrollGui::bake);
@@ -111,16 +114,21 @@ private void setContentListSlots(SequencedSet<Integer> slots, boolean horizontal
111114
}
112115

113116
private void handleLineChange() {
114-
int targetLine = line.get();
117+
int targetLine = getLine();
115118
int correctedLine = correctLine(targetLine);
116119
if (correctedLine != targetLine) {
117120
line.set(correctedLine);
118121
return;
119122
}
120123

121124
updateContent();
122-
if (targetLine != previousLine)
123-
scrollHandlers.forEach(handler -> handler.accept(previousLine, targetLine));
125+
if (targetLine != previousLine) {
126+
CollectionUtils.forEachCatching(
127+
scrollHandlers,
128+
handler -> handler.accept(previousLine, targetLine),
129+
"Failed to handle scroll from line " + previousLine + " to line " + targetLine
130+
);
131+
}
124132
previousLine = targetLine;
125133
}
126134

@@ -167,19 +175,21 @@ public void setElements(@Nullable List<SlotElement> elements) {
167175
this.elements = elements;
168176
int newLineCount = getLineCount();
169177

170-
for (var handler : lineCountChangeHandlers) {
171-
handler.accept(previousLineCount, newLineCount);
172-
}
178+
CollectionUtils.forEachCatching(
179+
lineCountChangeHandlers,
180+
handler -> handler.accept(previousLineCount, newLineCount),
181+
"Failed to handle line count change from " + previousLineCount + " to " + newLineCount
182+
);
173183
}
174184

175185
@Override
176186
public @UnmodifiableView List<C> getContent() {
177-
return Collections.unmodifiableList(content.get());
187+
return Collections.unmodifiableList(FuncUtils.getSafely(content, List.of()));
178188
}
179189

180190
@Override
181191
public int getLine() {
182-
return line.get();
192+
return FuncUtils.getSafely(line, DEFAULT_LINE);
183193
}
184194

185195
@Override
@@ -249,7 +259,7 @@ public static sealed abstract class AbstractBuilder<C>
249259

250260
private final Constructor<C> ctor;
251261
private MutableProperty<List<? extends C>> content = MutableProperty.of(List.of());
252-
private MutableProperty<Integer> line = MutableProperty.of(0);
262+
private MutableProperty<Integer> line = MutableProperty.of(DEFAULT_LINE);
253263
private List<BiConsumer<? super Integer, ? super Integer>> scrollHandlers = new ArrayList<>(0);
254264
private List<BiConsumer<? super Integer, ? super Integer>> lineCountChangeHandlers = new ArrayList<>(0);
255265

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

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@
33
import org.bukkit.entity.Player;
44
import org.bukkit.inventory.ItemStack;
55
import org.jspecify.annotations.Nullable;
6+
import xyz.xenondevs.invui.InvUI;
67
import xyz.xenondevs.invui.i18n.Languages;
78
import xyz.xenondevs.invui.inventory.Inventory;
89
import xyz.xenondevs.invui.item.ItemProvider;
910

1011
import java.util.ArrayList;
1112
import java.util.Collections;
1213
import java.util.List;
14+
import java.util.logging.Level;
1315

1416
/**
1517
* Represents an element in a slot in a {@link Gui}.
@@ -42,8 +44,14 @@ public sealed interface SlotElement {
4244
record Item(xyz.xenondevs.invui.item.Item item) implements SlotElement {
4345

4446
@Override
45-
public ItemStack getItemStack(Player player) {
46-
return item.getItemProvider(player).get(Languages.getInstance().getLocale(player));
47+
public @Nullable ItemStack getItemStack(Player player) {
48+
try {
49+
return item.getItemProvider(player).get(Languages.getInstance().getLocale(player));
50+
} catch (Throwable t) {
51+
InvUI.getInstance().getLogger().log(Level.SEVERE, "Failed to get item stack for item slot element", t);
52+
}
53+
54+
return null;
4755
}
4856

4957
@Override

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

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import org.jetbrains.annotations.UnmodifiableView;
55
import org.jspecify.annotations.Nullable;
66
import xyz.xenondevs.invui.internal.util.CollectionUtils;
7+
import xyz.xenondevs.invui.internal.util.FuncUtils;
78
import xyz.xenondevs.invui.internal.util.SlotUtils;
89
import xyz.xenondevs.invui.item.ItemProvider;
910
import xyz.xenondevs.invui.state.MutableProperty;
@@ -16,6 +17,8 @@
1617

1718
final class TabGuiImpl extends AbstractGui implements TabGui {
1819

20+
private static final int DEFAULT_TAB = -1;
21+
1922
private int[] contentListSlots;
2023

2124
private final MutableProperty<Integer> tab;
@@ -32,7 +35,7 @@ public TabGuiImpl(
3235
super(width, height);
3336
if (contentListSlots.isEmpty())
3437
throw new IllegalArgumentException("Content list slots must not be empty");
35-
this.tab = MutableProperty.of(0);
38+
this.tab = MutableProperty.of(DEFAULT_TAB);
3639
tab.observeWeak(this, TabGuiImpl::handleTabChange);
3740
this.tabs = tabs;
3841
tabs.observeWeak(this, TabGuiImpl::bake);
@@ -79,7 +82,7 @@ public void setContentListSlots(SequencedSet<Slot> slots) {
7982
@Override
8083
public void bake() {
8184
List<@Nullable List<SlotElement.GuiLink>> linkingElements = new ArrayList<>();
82-
for (var gui : tabs.get()) {
85+
for (var gui : getTabs()) {
8386
if (gui != null) {
8487
List<SlotElement.GuiLink> elements = new ArrayList<>();
8588
for (int slot = 0; slot < gui.getSize(); slot++) {
@@ -97,16 +100,21 @@ public void bake() {
97100
}
98101

99102
private void handleTabChange() {
100-
int targetTab = tab.get();
103+
int targetTab = getTab();
101104
int correctedTab = correctTab(targetTab);
102105
if (correctedTab != targetTab) {
103106
tab.set(correctedTab);
104107
return;
105108
}
106109

107110
updateContent();
108-
if (targetTab != previousTab)
109-
tabChangeHandlers.forEach(handler -> handler.accept(previousTab, targetTab));
111+
if (targetTab != previousTab) {
112+
CollectionUtils.forEachCatching(
113+
tabChangeHandlers,
114+
handler -> handler.accept(previousTab, targetTab),
115+
"Failed to handle tab change from " + previousTab + " to " + targetTab
116+
);
117+
}
110118
previousTab = targetTab;
111119
}
112120

@@ -160,7 +168,7 @@ public void setTab(int tab) {
160168
}
161169

162170
public int getTab() {
163-
return tab.get();
171+
return FuncUtils.getSafely(tab, DEFAULT_TAB);
164172
}
165173

166174
@Override
@@ -170,7 +178,7 @@ public void setTabs(List<? extends @Nullable Gui> tabs) {
170178

171179
@Override
172180
public @UnmodifiableView List<@Nullable Gui> getTabs() {
173-
return Collections.unmodifiableList(tabs.get());
181+
return Collections.unmodifiableList(FuncUtils.getSafely(tabs, List.of()));
174182
}
175183

176184
@Override
@@ -200,7 +208,7 @@ public static final class Builder
200208
{
201209

202210
private MutableProperty<List<? extends @Nullable Gui>> tabs = MutableProperty.of(List.of());
203-
private MutableProperty<Integer> tab = MutableProperty.of(0);
211+
private MutableProperty<Integer> tab = MutableProperty.of(DEFAULT_TAB);
204212
private List<BiConsumer<? super Integer, ? super Integer>> tabChangeHandlers = new ArrayList<>(0);
205213

206214
@Override

0 commit comments

Comments
 (0)