diff --git a/src/main/java/ch/njol/skript/CustomEvents.java b/src/main/java/ch/njol/skript/CustomEvents.java new file mode 100644 index 00000000000..3963721e923 --- /dev/null +++ b/src/main/java/ch/njol/skript/CustomEvents.java @@ -0,0 +1,149 @@ +/** + * 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 . + * + * Copyright Peter Güttinger, SkriptLang team and contributors + */ +package ch.njol.skript; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +import org.bukkit.event.Event; + +import ch.njol.skript.config.Config; +import ch.njol.skript.config.Node; +import ch.njol.skript.config.OptionSection; +import ch.njol.skript.config.SectionNode; +import ch.njol.skript.lang.util.SimpleEvent; +import ch.njol.skript.log.SkriptLogger; +import ch.njol.skript.util.FileUtils; + +public class CustomEvents { + + public static final OptionSection events = new OptionSection("events"); + + private static boolean loaded; + + @SuppressWarnings("unchecked") + public static void load(File file) { + if (loaded) + return; + loaded = true; + File eventsFile = new File(Skript.getInstance().getDataFolder(), "custom-events.sk"); + Config configuration = null; + if (eventsFile.exists()) { + try { + configuration = new Config(eventsFile, false, false, ":"); + } catch (IOException e) { + Skript.exception(e, "Failed to load custom-events.sk"); + } + } else { + try (ZipFile zip = new ZipFile(file)) { + File saveTo = null; + ZipEntry entry = zip.getEntry("custom-events.sk"); + if (entry != null) { + File destination = new File(Skript.getInstance().getDataFolder(), entry.getName()); + if (!destination.exists()) + saveTo = destination; + } if (saveTo != null) { + try (InputStream in = zip.getInputStream(entry)) { + FileUtils.save(in, saveTo); + } + } + } catch (IOException e) { + if (Skript.debug()) + Skript.exception(e); + } finally { + eventsFile = new File(Skript.getInstance().getDataFolder(), "custom-events.sk"); + try { + configuration = new Config(eventsFile, false, false, ":"); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + if (configuration != null) { + configuration.load(CustomEvents.class); + // When we need to change values in the future of this file, bump the version node. + String version = configuration.get("version"); + if (version != null && version.isEmpty() || !version.equalsIgnoreCase("1")) { + Skript.warning("Your custom-events.sk config file is outdated. " + + "Backup any changes you've made, and delete your custom-events.sk in the Skript folder to update it. " + + "After, re-add any nodes you've changed."); + } + SectionNode section = (SectionNode) configuration.getMainNode().get("events"); + if (section != null && !section.isEmpty()) { + for (Node node : section) { + if (!(node instanceof SectionNode)) { + Skript.error("Event node '" + node.getKey() + "' was not a section, ignoring."); + continue; + } + SectionNode eventSection = (SectionNode) node; + String name = node.getKey(); + if (name.isEmpty()) { + Skript.error("Event node '" + node.getKey() + "' is empty/blank."); + continue; + } + String enabled = eventSection.get("enabled", "true"); + if (enabled.equalsIgnoreCase("false")) + continue; + String description = eventSection.get("description", "custom event '" + name + "'"); + String pattern = eventSection.getValue("pattern"); + if (pattern == null) { + Skript.warning("Event node '" + name + "' did not contain a 'pattern' value."); + continue; + } + if (pattern.contains("%")) { + SkriptLogger.setNode(eventSection.get("pattern")); + Skript.warning("Event node '" + name + "' cannot contain any expressions in the pattern '" + pattern + "'"); + continue; + } + String eventClass = eventSection.getValue("class"); + if (eventClass == null) { + Skript.warning("Event node '" + name + "' did not contain a 'class' value."); + continue; + } + + // Everything below this should be dedicated to the class node. + SkriptLogger.setNode(eventSection.get("class")); + Class event; + try { + event = Class.forName(eventClass); + } catch (Exception e) { + if (Skript.logVeryHigh() || Skript.debug()) { + Skript.exception(e, "Class '" + eventClass + "' for event node '" + name + "' had an exception loading."); + } else { + Skript.error("Failed to find class '" + eventClass + "' for event node '" + name + "'"); + } + continue; + } + if (!(Event.class.isAssignableFrom(event))) { + Skript.error("Class '" + eventClass + "' for event node '" + name + "' was not a valid Event class!"); + continue; + } + Skript.registerEvent(name, SimpleEvent.class, (Class) event, pattern) + .requiredPlugins("Custom Skript Event") + .description(description); + } + } + } + } + +} diff --git a/src/main/java/ch/njol/skript/Skript.java b/src/main/java/ch/njol/skript/Skript.java index 83fa4a93ccb..194681d0a0a 100644 --- a/src/main/java/ch/njol/skript/Skript.java +++ b/src/main/java/ch/njol/skript/Skript.java @@ -549,6 +549,9 @@ public void onEnable() { return; } + // Must load after loadClasses + CustomEvents.load(getFile()); + Commands.registerListeners(); if (logNormal()) diff --git a/src/main/resources/custom-events.sk b/src/main/resources/custom-events.sk new file mode 100644 index 00000000000..f617e9a8ade --- /dev/null +++ b/src/main/resources/custom-events.sk @@ -0,0 +1,38 @@ + +# This file allows you to register custom events that aren't already registered under Skript. +# The event classes you want to register must exist in the server class loader. So events from Paper/Spigot. +# If you want to register an event from a plugin API, you must edit the plugin.yml in the jar of Skript to include: +# +# softdepend: [YourPlugin, SQLibrary, Vault, WorldGuard, Residence, PreciousStones, GriefPrevention] +# +# Reminder to maintain any existing defined plugins in this array as this example should not be directly copied. +#! Additions or changes to this file requires a server restart. + +#! Internal version of this configuration. Don't modify. +version: 1 + +# The format must include a section where the section name is the event name. +# The event section must include: +# description - describing the event +# class - the class name to search for +# pattern - the syntax pattern of the event +# The optional pattern [on] gets prefixed on every Skript event. +# Pattern cannot have expressions inside currently. +# event-values of subclass events will be automatically applied. +# If you need more info, make an issue report at https://github.com/SkriptLang/Skript/issues + +# Examples are placed below. The 'enabled' node is not required, it's just to disable examples. +events: + # [on] beacon effect apply + beacon effect: + enabled: false + description: "Called when entities receive potion effects from a beacon" + class: com.destroystokyo.paper.event.block.BeaconEffectEvent + pattern: beacon effect apply [to player[s]] + + # [on] campfire start cooking + campfire cooking: + enabled: false + description: "Called when a campfire starts cooking" + class: org.bukkit.event.block.CampfireStartEvent + pattern: campfire start[ing] cooking diff --git a/src/test/java/org/skriptlang/skript/test/tests/files/FilesGenerate.java b/src/test/java/org/skriptlang/skript/test/tests/files/FilesGenerate.java index a6bcabcea71..2cb83e29ae1 100644 --- a/src/test/java/org/skriptlang/skript/test/tests/files/FilesGenerate.java +++ b/src/test/java/org/skriptlang/skript/test/tests/files/FilesGenerate.java @@ -41,6 +41,7 @@ public void checkFiles() { assertTrue(skript.getScriptsFolder().isDirectory()); assertTrue(new File(dataFolder, "config.sk").exists()); assertTrue(new File(dataFolder, "features.sk").exists()); + assertTrue(new File(dataFolder, "custom-events.sk").exists()); File lang = new File(dataFolder, "lang"); assertTrue(lang.exists()); assertTrue(lang.isDirectory());