Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes an exception from being thrown on async events #5699

Merged
merged 14 commits into from
Sep 9, 2023
31 changes: 18 additions & 13 deletions src/main/java/ch/njol/skript/SkriptEventHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import ch.njol.skript.lang.Trigger;
import ch.njol.skript.timings.SkriptTimings;
import ch.njol.skript.util.Task;
import ch.njol.util.NonNullPair;
import org.bukkit.Bukkit;
import org.bukkit.event.Cancellable;
Expand Down Expand Up @@ -104,30 +105,30 @@ private static Iterator<Trigger> getTriggers(Class<? extends Event> event) {
* @param e The Event to check.
* @param priority The priority of the Event.
*/
private static void check(Event e, EventPriority priority) {
Iterator<Trigger> ts = getTriggers(e.getClass());
private static void check(Event event, EventPriority priority) {
Iterator<Trigger> ts = getTriggers(event.getClass());
if (!ts.hasNext())
return;

if (Skript.logVeryHigh()) {
boolean hasTrigger = false;
while (ts.hasNext()) {
Trigger trigger = ts.next();
if (trigger.getEvent().getEventPriority() == priority && trigger.getEvent().check(e)) {
if (trigger.getEvent().getEventPriority() == priority && trigger.getEvent().check(event)) {
hasTrigger = true;
break;
}
}
if (!hasTrigger)
return;
Class<? extends Event> c = e.getClass();
Class<? extends Event> c = event.getClass();
ts = getTriggers(c);

logEventStart(e);
logEventStart(event);
}

boolean isCancelled = e instanceof Cancellable && ((Cancellable) e).isCancelled() && !listenCancelled.contains(e.getClass());
boolean isResultDeny = !(e instanceof PlayerInteractEvent && (((PlayerInteractEvent) e).getAction() == Action.LEFT_CLICK_AIR || ((PlayerInteractEvent) e).getAction() == Action.RIGHT_CLICK_AIR) && ((PlayerInteractEvent) e).useItemInHand() != Result.DENY);
boolean isCancelled = event instanceof Cancellable && ((Cancellable) event).isCancelled() && !listenCancelled.contains(event.getClass());
boolean isResultDeny = !(event instanceof PlayerInteractEvent && (((PlayerInteractEvent) event).getAction() == Action.LEFT_CLICK_AIR || ((PlayerInteractEvent) event).getAction() == Action.RIGHT_CLICK_AIR) && ((PlayerInteractEvent) event).useItemInHand() != Result.DENY);

if (isCancelled && isResultDeny) {
if (Skript.logVeryHigh())
Expand All @@ -136,17 +137,21 @@ private static void check(Event e, EventPriority priority) {
}

while (ts.hasNext()) {
Trigger t = ts.next();
if (t.getEvent().getEventPriority() != priority || !t.getEvent().check(e))
Trigger trigger = ts.next();
if (trigger.getEvent().getEventPriority() != priority || !trigger.getEvent().check(event))
continue;

logTriggerStart(t);
Object timing = SkriptTimings.start(t.getDebugLabel());
logTriggerStart(trigger);
Object timing = SkriptTimings.start(trigger.getDebugLabel());

t.execute(e);
if (!Bukkit.isPrimaryThread() && !trigger.getEvent().allowAsynchronous()) {
Task.callSync(() -> trigger.execute(event));
TheLimeGlass marked this conversation as resolved.
Show resolved Hide resolved
} else {
trigger.execute(event);
}

SkriptTimings.stop(timing);
logTriggerEnd(t);
logTriggerEnd(trigger);
}

logEventEnd();
Expand Down
7 changes: 7 additions & 0 deletions src/main/java/ch/njol/skript/lang/SkriptEvent.java
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,13 @@ public boolean isEventPrioritySupported() {
return true;
}

/**
* Override this method to allow Skript to not force synchronization.
*/
public boolean allowAsynchronous() {
TheLimeGlass marked this conversation as resolved.
Show resolved Hide resolved
return false;
}

/**
* Fixes patterns in event by modifying every {@link ch.njol.skript.patterns.TypePatternElement}
* to be nullable.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/**
* This file is part of Skript.
*
* Skript is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Skript is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Skript. If not, see <http://www.gnu.org/licenses/>.
*
* Copyright Peter Güttinger, SkriptLang team and contributors
*/
package org.skriptlang.skript.test.tests.regression;

import static org.easymock.EasyMock.createMock;

import java.util.concurrent.CompletableFuture;

import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import org.junit.Test;

import com.google.common.collect.Sets;

import ch.njol.skript.test.runner.SkriptJUnitTest;

/**
* Issue #5689 caused an exception when attempting to do a sync required actions on an async event.
*/
@SuppressWarnings("deprecation") // Paper wants AsyncChatEvent for AdventureAPI
public class AsyncEvents_5689 extends SkriptJUnitTest {

private static Player player = createMock(Player.class);

@Test
public void execute() {
AsyncPlayerChatEvent event = new AsyncPlayerChatEvent(true, player, "Issue 5689", Sets.newHashSet(player));
CompletableFuture.runAsync(() -> Bukkit.getPluginManager().callEvent(event));
}

}
13 changes: 13 additions & 0 deletions src/test/skript/tests/junit/AsyncEvents_5689.sk
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
on script load:
ensure junit test "org.skriptlang.skript.test.tests.regression.AsyncEvents_5689" completes "async chat"

on chat:
junit test is "org.skriptlang.skript.test.tests.regression.AsyncEvents_5689"

# Attempting to throw an exception
set {_block} to type of block at spawn of "world"
set block at spawn of "world" to stone
set block at spawn of "world" to {_block}
execute console command "command doesn't exist"
wait a tick
complete objective "async chat" for junit test "org.skriptlang.skript.test.tests.regression.AsyncEvents_5689"