Skip to content

Commit 59d2a67

Browse files
committed
fix: improve error handling on player quit and inventory click events
1 parent 94ff1bf commit 59d2a67

File tree

2 files changed

+66
-79
lines changed

2 files changed

+66
-79
lines changed

inventory-framework-platform-bukkit/src/main/java/me/devnatan/inventoryframework/IFInventoryListener.java

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ public void onPluginDisable(final PluginDisableEvent event) {
3636
viewFrame.unregister();
3737
}
3838

39-
@EventHandler(priority = EventPriority.LOW)
40-
public void onPlayerQuit(PlayerQuitEvent event){
39+
@EventHandler
40+
public void onPlayerQuit(PlayerQuitEvent event) {
4141
final Player player = (Player) event.getPlayer();
4242
final Viewer viewer = viewFrame.getViewer(player);
4343
if (viewer == null) return;
@@ -54,23 +54,33 @@ public void onInventoryClick(final InventoryClickEvent event) {
5454
if (!(event.getWhoClicked() instanceof Player)) return;
5555

5656
final Player player = (Player) event.getWhoClicked();
57-
final Viewer viewer = viewFrame.getViewer(player);
58-
if (viewer == null) return;
59-
60-
final IFRenderContext context = viewer.getActiveContext();
61-
final Component clickedComponent = context.getComponentsAt(event.getRawSlot()).stream()
62-
.filter(Component::isVisible)
63-
.findFirst()
64-
.orElse(null);
65-
final ViewContainer clickedContainer = event.getClickedInventory() instanceof PlayerInventory
66-
? viewer.getSelfContainer()
67-
: context.getContainer();
68-
69-
final RootView root = context.getRoot();
70-
final IFSlotClickContext clickContext = root.getElementFactory()
71-
.createSlotClickContext(event.getRawSlot(), viewer, clickedContainer, clickedComponent, event, false);
72-
73-
root.getPipeline().execute(StandardPipelinePhases.CLICK, clickContext);
57+
try {
58+
final Viewer viewer = viewFrame.getViewer(player);
59+
if (viewer == null) return;
60+
61+
final IFRenderContext context = viewer.getActiveContext();
62+
final Component clickedComponent = context.getComponentsAt(event.getRawSlot()).stream()
63+
.filter(Component::isVisible)
64+
.findFirst()
65+
.orElse(null);
66+
final ViewContainer clickedContainer = event.getClickedInventory() instanceof PlayerInventory
67+
? viewer.getSelfContainer()
68+
: context.getContainer();
69+
70+
final RootView root = context.getRoot();
71+
final IFSlotClickContext clickContext = root.getElementFactory()
72+
.createSlotClickContext(
73+
event.getRawSlot(), viewer, clickedContainer, clickedComponent, event, false);
74+
75+
root.getPipeline().execute(StandardPipelinePhases.CLICK, clickContext);
76+
} catch (Exception e) {
77+
// TODO custom error handling to customize on error behavior
78+
viewFrame
79+
.getOwner()
80+
.getLogger()
81+
.severe("An error occurred while processing an inventory click event: " + e.getMessage());
82+
player.closeInventory();
83+
}
7484
}
7585

7686
@SuppressWarnings("unused")

inventory-framework-platform/src/main/java/me/devnatan/inventoryframework/PlatformView.java

Lines changed: 37 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -2,50 +2,16 @@
22

33
import static java.lang.String.format;
44

5-
import java.util.ArrayList;
6-
import java.util.Collections;
7-
import java.util.Iterator;
8-
import java.util.List;
9-
import java.util.Map;
10-
import java.util.UUID;
5+
import java.util.*;
116
import java.util.concurrent.CompletableFuture;
127
import java.util.function.Function;
138
import java.util.function.Supplier;
149
import me.devnatan.inventoryframework.component.*;
15-
import me.devnatan.inventoryframework.context.IFCloseContext;
16-
import me.devnatan.inventoryframework.context.IFConfinedContext;
17-
import me.devnatan.inventoryframework.context.IFContext;
18-
import me.devnatan.inventoryframework.context.IFOpenContext;
19-
import me.devnatan.inventoryframework.context.IFRenderContext;
20-
import me.devnatan.inventoryframework.context.IFSlotClickContext;
21-
import me.devnatan.inventoryframework.context.IFSlotContext;
22-
import me.devnatan.inventoryframework.context.PlatformRenderContext;
10+
import me.devnatan.inventoryframework.context.*;
2311
import me.devnatan.inventoryframework.internal.ElementFactory;
2412
import me.devnatan.inventoryframework.internal.PlatformUtils;
25-
import me.devnatan.inventoryframework.pipeline.AvailableSlotInterceptor;
26-
import me.devnatan.inventoryframework.pipeline.ComponentClickHandlerCallInterceptor;
27-
import me.devnatan.inventoryframework.pipeline.ContextInvalidationOnCloseInterceptor;
28-
import me.devnatan.inventoryframework.pipeline.FirstRenderInterceptor;
29-
import me.devnatan.inventoryframework.pipeline.LayoutRenderInterceptor;
30-
import me.devnatan.inventoryframework.pipeline.LayoutResolutionInterceptor;
31-
import me.devnatan.inventoryframework.pipeline.Pipeline;
32-
import me.devnatan.inventoryframework.pipeline.PlatformCloseInterceptor;
33-
import me.devnatan.inventoryframework.pipeline.PlatformInitInterceptor;
34-
import me.devnatan.inventoryframework.pipeline.PlatformOpenInterceptor;
35-
import me.devnatan.inventoryframework.pipeline.PlatformRenderInterceptor;
36-
import me.devnatan.inventoryframework.pipeline.PlatformUpdateHandlerInterceptor;
37-
import me.devnatan.inventoryframework.pipeline.ScheduledUpdateStartInterceptor;
38-
import me.devnatan.inventoryframework.pipeline.ScheduledUpdateStopInterceptor;
39-
import me.devnatan.inventoryframework.pipeline.StandardPipelinePhases;
40-
import me.devnatan.inventoryframework.pipeline.UpdateInterceptor;
41-
import me.devnatan.inventoryframework.pipeline.ViewerLastInteractionTrackerInterceptor;
42-
import me.devnatan.inventoryframework.state.InitialDataStateValue;
43-
import me.devnatan.inventoryframework.state.MutableIntState;
44-
import me.devnatan.inventoryframework.state.MutableState;
45-
import me.devnatan.inventoryframework.state.State;
46-
import me.devnatan.inventoryframework.state.StateAccess;
47-
import me.devnatan.inventoryframework.state.StateAccessImpl;
48-
import me.devnatan.inventoryframework.state.StateValue;
13+
import me.devnatan.inventoryframework.pipeline.*;
14+
import me.devnatan.inventoryframework.state.*;
4915
import org.jetbrains.annotations.ApiStatus;
5016
import org.jetbrains.annotations.NotNull;
5117

@@ -70,6 +36,7 @@ protected PlatformView() {
7036
}
7137

7238
// region Open & Close
39+
7340
/**
7441
* Closes all contexts that are currently active in this view.
7542
*/
@@ -111,32 +78,38 @@ final String open(List<Viewer> viewers, Object initialData) {
11178
/**
11279
* Opens an already active context to a viewer.
11380
*
114-
* @param contextId The id of the context.
115-
* @param viewer The viewer to open the context to.
81+
* @param contextId The id of the context.
82+
* @param viewer The viewer to open the context to.
11683
* @param initialData Initial data.
11784
*/
11885
@SuppressWarnings("unchecked")
11986
final void open(String contextId, Viewer viewer, Object initialData) {
120-
IFRenderContext targetContext = null;
121-
for (final IFContext context : getInternalContexts()) {
122-
if (context.getId().toString().equals(contextId)) {
123-
targetContext = (IFRenderContext) context;
124-
break;
87+
try {
88+
IFRenderContext targetContext = null;
89+
for (final IFContext context : getInternalContexts()) {
90+
if (context.getId().toString().equals(contextId)) {
91+
targetContext = (IFRenderContext) context;
92+
break;
93+
}
12594
}
126-
}
127-
128-
if (targetContext == null) throw new IllegalArgumentException("Context not found: " + contextId);
129-
if (!targetContext.isActive()) throw new IllegalStateException("Invalidated");
13095

131-
viewer.setActiveContext(targetContext);
132-
onViewerAdded((TContext) targetContext, (TViewer) viewer.getPlatformInstance(), initialData);
133-
targetContext.addViewer(viewer);
134-
getFramework().addViewer(viewer);
135-
viewer.open(targetContext.getContainer());
96+
if (targetContext == null) throw new IllegalArgumentException("Context not found: " + contextId);
97+
if (!targetContext.isActive()) throw new IllegalStateException("Invalidated");
98+
99+
viewer.setActiveContext(targetContext);
100+
onViewerAdded((TContext) targetContext, (TViewer) viewer.getPlatformInstance(), initialData);
101+
targetContext.addViewer(viewer);
102+
getFramework().addViewer(viewer);
103+
viewer.open(targetContext.getContainer());
104+
} catch (Exception e) {
105+
viewer.close();
106+
e.printStackTrace(); // todo use custom error handler
107+
}
136108
}
137109
// endregion
138110

139111
// region Navigation
112+
140113
/**
141114
* <p><b><i>This is an internal inventory-framework API that should not be used from outside of
142115
* this library. No compatibility guarantees are provided.</i></b>
@@ -236,6 +209,7 @@ public final void back(@NotNull Viewer viewer, Object initialData) {
236209
}
237210

238211
// region Contexts
212+
239213
/**
240214
* Returns the context that is linked to the specified viewer in this view.
241215
* <p>
@@ -387,14 +361,15 @@ public final Iterator<TContext> iterator() {
387361
}
388362

389363
// region Refs API
364+
390365
/**
391366
* Creates a new unassigned reference instance.
392367
* <p>
393368
* <b><i> This API is experimental and is not subject to the general compatibility guarantees
394369
* such API may be changed or may be removed completely in any further release. </i></b>
395370
*
396-
* @return A new unassigned {@link Ref} instance.
397371
* @param <E> Type of the element hold by this reference.
372+
* @return A new unassigned {@link Ref} instance.
398373
* @see <a href="https://github.com/DevNatan/inventory-framework/wiki/refs-api">Refs API on Wiki</a>
399374
*/
400375
@ApiStatus.Experimental
@@ -408,8 +383,8 @@ protected final <E> Ref<E> ref() {
408383
* <b><i> This API is experimental and is not subject to the general compatibility guarantees
409384
* such API may be changed or may be removed completely in any further release. </i></b>
410385
*
411-
* @return A new unassigned {@link Ref} instance.
412386
* @param <E> Type of the element hold by this reference.
387+
* @return A new unassigned {@link Ref} instance.
413388
* @see <a href="https://github.com/DevNatan/inventory-framework/wiki/refs-api">Refs API on Wiki</a>
414389
*/
415390
@ApiStatus.Experimental
@@ -419,6 +394,7 @@ protected final <E> Ref<List<E>> multiRefs() {
419394
// endregion
420395

421396
// region Public Platform Handlers
397+
422398
/**
423399
* Called when the view is about to be configured, the returned object will be the view's
424400
* configuration.
@@ -516,9 +492,9 @@ public void onResume(@NotNull TContext origin, @NotNull TContext target) {}
516492
* <b><i> This API is experimental and is not subject to the general compatibility guarantees
517493
* such API may be changed or may be removed completely in any further release. </i></b>
518494
*
519-
* @param context The context.
520-
* @param viewer Who was added to the context.
521-
* @param data Initial data set wen the viewer was added.
495+
* @param context The context.
496+
* @param viewer Who was added to the context.
497+
* @param data Initial data set wen the viewer was added.
522498
*/
523499
@ApiStatus.OverrideOnly
524500
@ApiStatus.Experimental
@@ -533,14 +509,15 @@ public void onViewerAdded(@NotNull TContext context, @NotNull TViewer viewer, Ob
533509
* such API may be changed or may be removed completely in any further release. </i></b>
534510
*
535511
* @param context The context.
536-
* @param viewer Who was removed from the context.
512+
* @param viewer Who was removed from the context.
537513
*/
538514
@ApiStatus.OverrideOnly
539515
@ApiStatus.Experimental
540516
public void onViewerRemoved(@NotNull TContext context, @NotNull TViewer viewer) {}
541517
// endregion
542518

543519
// region Internals
520+
544521
/**
545522
* <p><b><i>This is an internal inventory-framework API that should not be used from outside of
546523
* this library. No compatibility guarantees are provided.</i></b>

0 commit comments

Comments
 (0)