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

Internal Events API #5552

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
7e806f8
Combine activity events and add unload event
APickledWalrus Mar 25, 2023
d2c75fc
Add global script events
APickledWalrus Mar 25, 2023
18aae27
Add EventRegister API
APickledWalrus Mar 25, 2023
82ac723
Javadoc improvements
APickledWalrus Mar 25, 2023
a01b0bb
Merge branch 'master' into feature/script-event-updates
APickledWalrus Jul 19, 2023
254a799
Refactoring
APickledWalrus Jul 19, 2023
c391d9b
Cleanup and additional refactoring
APickledWalrus Jul 19, 2023
9312100
Add ScriptLoadEvent and ScriptInitEvent
APickledWalrus Jul 19, 2023
4df1644
Add PreScriptInitEvent
APickledWalrus Jul 19, 2023
c24ca0a
Minor javadoc corrections
APickledWalrus Jul 19, 2023
8759556
Oopsie! add license headers
APickledWalrus Jul 19, 2023
e9d8810
Requested formatting changes
APickledWalrus Jul 19, 2023
efd6362
Merge branch 'dev/feature' into feature/script-event-updates
APickledWalrus Dec 19, 2023
a5cde98
Javadoc tweaks
APickledWalrus Dec 19, 2023
f32e529
Merge branch 'dev/feature' into feature/script-event-updates
APickledWalrus Jul 14, 2024
fde7dfe
Fix script load triggering
APickledWalrus Jul 14, 2024
af02f81
Remove license headers
APickledWalrus Jul 14, 2024
478276b
Update class and method names
APickledWalrus Jul 14, 2024
48272bd
Formatting tweaks
APickledWalrus Jul 14, 2024
3d11e8b
Refactor event classes into appropriate locations
APickledWalrus Jul 14, 2024
7bac33a
Merge branch 'dev/feature' into feature/script-event-updates
APickledWalrus Sep 22, 2024
50128e9
Add Event parent class for type restriction
APickledWalrus Sep 22, 2024
37bb18d
Merge branch 'dev/feature' into feature/script-event-updates
sovdeeth Oct 13, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 121 additions & 2 deletions src/main/java/ch/njol/skript/ScriptLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
import org.bukkit.Bukkit;
import org.bukkit.event.Event;
import org.jetbrains.annotations.Nullable;
import org.skriptlang.skript.util.event.EventRegistry;
import org.skriptlang.skript.lang.script.Script;
import org.skriptlang.skript.lang.structure.Structure;

Expand All @@ -58,6 +59,7 @@
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
Expand Down Expand Up @@ -488,6 +490,9 @@ private static CompletableFuture<ScriptInfo> loadScripts(List<Config> configs, O
if (configs.isEmpty()) // Nothing to load
return CompletableFuture.completedFuture(new ScriptInfo());

eventRegistry().events(ScriptPreInitEvent.class)
.forEach(event -> event.onPreInit(configs));
//noinspection deprecation - we still need to call it
Bukkit.getPluginManager().callEvent(new PreScriptLoadEvent(configs));

ScriptInfo scriptInfo = new ScriptInfo();
Expand Down Expand Up @@ -605,6 +610,20 @@ private static CompletableFuture<ScriptInfo> loadScripts(List<Config> configs, O
});
parser.setInactive();

// trigger events
scripts.forEach(loadingInfo -> {
Script script = loadingInfo.script;

parser.setActive(script);
parser.setNode(script.getConfig().getMainNode());

ScriptLoader.eventRegistry().events(ScriptLoadEvent.class)
.forEach(event -> event.onLoad(parser, script));
script.eventRegistry().events(ScriptLoadEvent.class)
.forEach(event -> event.onLoad(parser, script));
});
parser.setInactive();

return scriptInfo;
} catch (Exception e) {
// Something went wrong, we need to make sure the exception is printed
Expand Down Expand Up @@ -700,10 +719,13 @@ private static LoadingScriptInfo loadScript(Config config) {
assert file != null;
File disabledFile = new File(file.getParentFile(), DISABLED_SCRIPT_PREFIX + file.getName());
disabledScripts.remove(disabledFile);

// Add to loaded files to use for future reloads
loadedScripts.add(script);


ScriptLoader.eventRegistry().events(ScriptInitEvent.class)
.forEach(event -> event.onInit(script));

return null;
};
if (isAsync()) { // Need to delegate to main thread
Expand Down Expand Up @@ -848,6 +870,13 @@ public static ScriptInfo unloadScripts(Set<Script> scripts) {
// initial unload stage
for (Script script : scripts) {
parser.setActive(script);

// trigger unload event before beginning
eventRegistry().events(ScriptUnloadEvent.class)
.forEach(event -> event.onUnload(parser, script));
script.eventRegistry().events(ScriptUnloadEvent.class)
.forEach(event -> event.onUnload(parser, script));

for (Structure structure : script.getStructures())
structure.unload();
}
Expand Down Expand Up @@ -1043,6 +1072,96 @@ public static FileFilter getDisabledScriptsFilter() {
return disabledScriptFilter;
}

/*
* Global Script Event API
*/

// ScriptLoader Events

/**
* Used for listening to events involving a ScriptLoader.
* @see #eventRegistry()
*/
public interface LoaderEvent extends org.skriptlang.skript.util.event.Event { }

/**
* Called when {@link ScriptLoader} is preparing to load {@link Config}s into {@link Script}s.
* @see #loadScripts(File, OpenCloseable)
* @see #loadScripts(Set, OpenCloseable)
*/
@FunctionalInterface
public interface ScriptPreInitEvent extends LoaderEvent {

/**
* The method that is called when this event triggers.
* Modifications to the given collection will affect what is loaded.
* @param configs The Configs to be loaded.
*/
void onPreInit(Collection<Config> configs);

}

/**
* Called when a {@link Script} is created and preloaded in the {@link ScriptLoader}.
* The initializing script may contain {@link Structure}s that are not fully loaded.
* @see #loadScripts(File, OpenCloseable)
* @see #loadScripts(Set, OpenCloseable)
*/
@FunctionalInterface
public interface ScriptInitEvent extends LoaderEvent {

/**
* The method that is called when this event triggers.
* @param script The Script being initialized.
*/
void onInit(Script script);

}

/**
* Called when a {@link Script} is loaded in the {@link ScriptLoader}.
* This event will trigger <b>after</b> the script is completely loaded ({@link Structure} initialization finished).
* @see #loadScripts(File, OpenCloseable)
* @see #loadScripts(Set, OpenCloseable)
*/
@FunctionalInterface
public interface ScriptLoadEvent extends LoaderEvent, Script.Event {

/**
* The method that is called when this event triggers.
* @param parser The ParserInstance handling the loading of <code>script</code>.
* @param script The Script being loaded.
*/
void onLoad(ParserInstance parser, Script script);

}

/**
* Called when a {@link Script} is unloaded in the {@link ScriptLoader}.
* This event will trigger <b>before</b> the script is unloaded.
* @see #unloadScript(Script)
*/
@FunctionalInterface
public interface ScriptUnloadEvent extends LoaderEvent, Script.Event {

/**
* The method that is called when this event triggers.
* @param parser The ParserInstance handling the unloading of <code>script</code>.
* @param script The Script being unloaded.
*/
void onUnload(ParserInstance parser, Script script);

}

private static final EventRegistry<LoaderEvent> eventRegistry = new EventRegistry<>();

/**
* @return An EventRegistry for the ScriptLoader's events.
*/
public static EventRegistry<LoaderEvent> eventRegistry() {
return eventRegistry;
}

/*
* Deprecated stuff
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,14 @@

import ch.njol.skript.config.Config;
import ch.njol.util.Validate;
import ch.njol.skript.ScriptLoader;

/**
* This event has no guarantee of being on the main thread.
* Please do not use bukkit api before checking {@link Bukkit#isPrimaryThread()}
* @deprecated Use {@link ScriptLoader.ScriptPreInitEvent}.
*/

@Deprecated
public class PreScriptLoadEvent extends Event {

private final List<Config> scripts;
Expand Down
44 changes: 36 additions & 8 deletions src/main/java/ch/njol/skript/lang/parser/ParserInstance.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@
import org.skriptlang.skript.lang.experiment.ExperimentSet;
import org.skriptlang.skript.lang.experiment.Experimented;
import org.skriptlang.skript.lang.script.Script;
import org.skriptlang.skript.lang.script.ScriptEvent;
import org.skriptlang.skript.lang.structure.Structure;

import java.io.File;
Expand Down Expand Up @@ -130,12 +129,18 @@ private void setCurrentScript(@Nullable Script currentScript) {
);

// "Script" events
if (previous != null)
previous.getEvents(ScriptEvent.ScriptInactiveEvent.class)
.forEach(eventHandler -> eventHandler.onInactive(currentScript));
if (currentScript != null)
currentScript.getEvents(ScriptEvent.ScriptActiveEvent.class)
.forEach(eventHandler -> eventHandler.onActive(previous));
if (previous != null) { // 'previous' is becoming inactive
ScriptLoader.eventRegistry().events(ScriptActivityChangeEvent.class)
.forEach(event -> event.onActivityChange(this, previous, false, currentScript));
previous.eventRegistry().events(ScriptActivityChangeEvent.class)
.forEach(event -> event.onActivityChange(this, previous, false, currentScript));
}
if (currentScript != null) { // 'currentScript' is becoming active
ScriptLoader.eventRegistry().events(ScriptActivityChangeEvent.class)
.forEach(event -> event.onActivityChange(this, currentScript, true, previous));
currentScript.eventRegistry().events(ScriptActivityChangeEvent.class)
.forEach(event -> event.onActivityChange(this, currentScript, true, previous));
}
}

/**
Expand Down Expand Up @@ -483,7 +488,7 @@ protected final ParserInstance getParser() {
}

/**
* @deprecated See {@link ScriptEvent}.
* @deprecated See {@link ScriptLoader.LoaderEvent}.
*/
@Deprecated
public void onCurrentScriptChange(@Nullable Config currentScript) { }
Expand Down Expand Up @@ -540,6 +545,29 @@ private List<? extends Data> getDataInstances() {
return dataList;
}

/**
* Called when a {@link Script} is made active or inactive in a {@link ParserInstance}.
* This event will trigger <b>after</b> the change in activity has occurred.
* @see #isActive()
*/
@FunctionalInterface
public interface ScriptActivityChangeEvent extends ScriptLoader.LoaderEvent, Script.Event {

/**
* The method that is called when this event triggers.
* @param parser The ParserInstance where the activity change occurred.
* @param script The Script this event was registered for.
* @param active Whether <code>script</code> became active or inactive within <code>parser</code>.
* @param other The Script that was made active or inactive.
* Whether it was made active or inactive is the negation of the <code>active</code>.
* That is to say, if <code>script</code> became active, then <code>other</code> became inactive.
* Null if <code>parser</code> was inactive (meaning no script became inactive)
* or became inactive (meaning no script became active).
*/
void onActivityChange(ParserInstance parser, Script script, boolean active, @Nullable Script other);

}

// Backup API

/**
Expand Down
78 changes: 8 additions & 70 deletions src/main/java/org/skriptlang/skript/lang/script/Script.java
Original file line number Diff line number Diff line change
@@ -1,27 +1,10 @@
/**
* 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.lang.script;

import ch.njol.skript.config.Config;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Unmodifiable;
import org.skriptlang.skript.util.event.EventRegistry;
import org.skriptlang.skript.lang.structure.Structure;

import java.util.Collections;
Expand All @@ -31,7 +14,6 @@
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/**
* Scripts are the primary container of all code.
Expand Down Expand Up @@ -160,63 +142,19 @@ public <Value extends ScriptData> Value getData(Class<? extends Value> dataType,

// Script Events

private final Set<ScriptEvent> eventHandlers = new HashSet<>(5);

/**
* <b>This API is experimental and subject to change.</b>
* Adds the provided event to this Script.
* @param event The event to add.
*/
@ApiStatus.Experimental
public void registerEvent(ScriptEvent event) {
eventHandlers.add(event);
}

/**
* <b>This API is experimental and subject to change.</b>
* Adds the provided event to this Script.
* @param eventType The type of event being added. This is useful for registering the event through lambdas.
* @param event The event to add.
*/
@ApiStatus.Experimental
public <T extends ScriptEvent> void registerEvent(Class<T> eventType, T event) {
eventHandlers.add(event);
}

/**
* <b>This API is experimental and subject to change.</b>
* Removes the provided event from this Script.
* @param event The event to remove.
* Used for listening to events involving a Script.
* @see #eventRegistry()
*/
@ApiStatus.Experimental
public void unregisterEvent(ScriptEvent event) {
eventHandlers.remove(event);
}
public interface Event extends org.skriptlang.skript.util.event.Event { }

/**
* <b>This API is experimental and subject to change.</b>
* @return An unmodifiable set of all events.
*/
@ApiStatus.Experimental
@Unmodifiable
public Set<ScriptEvent> getEvents() {
return Collections.unmodifiableSet(eventHandlers);
}
private final EventRegistry<Event> eventRegistry = new EventRegistry<>();

/**
* <b>This API is experimental and subject to change.</b>
* @param type The type of events to get.
* @return An unmodifiable set of all events of the specified type.
* @return An EventRegistry for this Script's events.
*/
@ApiStatus.Experimental
@Unmodifiable
@SuppressWarnings("unchecked")
public <T extends ScriptEvent> Set<T> getEvents(Class<T> type) {
return Collections.unmodifiableSet(
(Set<T>) eventHandlers.stream()
.filter(event -> type.isAssignableFrom(event.getClass()))
.collect(Collectors.toSet())
);
public EventRegistry<Event> eventRegistry() {
return eventRegistry;
}

}
Loading