From 66893c58f68bdfb82c4824ad751833e37ce8b8d6 Mon Sep 17 00:00:00 2001 From: _tud <98935832+UnderscoreTud@users.noreply.github.com> Date: Tue, 31 Dec 2024 05:41:19 +0300 Subject: [PATCH 1/2] Replace all space indentations with tabs --- .editorconfig | 4 +- build.gradle | 46 +- .../com/btk5h/skriptmirror/Descriptor.java | 294 +-- .../btk5h/skriptmirror/FunctionWrapper.java | 54 +- .../skriptmirror/ImportNotFoundException.java | 16 +- .../btk5h/skriptmirror/JavaCallException.java | 14 +- .../java/com/btk5h/skriptmirror/JavaType.java | 44 +- .../com/btk5h/skriptmirror/LibraryLoader.java | 70 +- .../java/com/btk5h/skriptmirror/Metrics.java | 1390 +++++++------- .../java/com/btk5h/skriptmirror/Null.java | 12 +- .../com/btk5h/skriptmirror/ObjectWrapper.java | 128 +- .../skriptmirror/ParseOrderWorkarounds.java | 64 +- .../com/btk5h/skriptmirror/SkriptMirror.java | 206 +-- .../com/btk5h/skriptmirror/WrappedEvent.java | 34 +- .../skript/CondExpressionStatement.java | 138 +- .../skriptmirror/skript/CondIsInstanceOf.java | 56 +- .../skript/EffExpressionStatement.java | 90 +- .../skriptmirror/skript/ExprArrayAccess.java | 386 ++-- .../btk5h/skriptmirror/skript/ExprBits.java | 246 +-- .../skriptmirror/skript/ExprCollect.java | 150 +- .../skriptmirror/skript/ExprFunction.java | 88 +- .../btk5h/skriptmirror/skript/ExprPlugin.java | 88 +- .../btk5h/skriptmirror/skript/ExprSpread.java | 320 ++-- .../skriptmirror/skript/LitNullObject.java | 30 +- .../com/btk5h/skriptmirror/skript/Types.java | 383 ++-- .../skript/custom/Continuable.java | 8 +- .../skript/custom/CustomSyntaxEvent.java | 50 +- .../skript/custom/CustomSyntaxExpression.java | 92 +- .../skript/custom/EffContinue.java | 82 +- .../skript/custom/ExprEventClasses.java | 62 +- .../skript/custom/ExprExpression.java | 354 ++-- .../skript/custom/ExprMatchedPattern.java | 70 +- .../skript/custom/ExprParseMark.java | 70 +- .../skript/custom/ExprParseRegex.java | 108 +- .../skript/custom/ExprParseTags.java | 80 +- .../skript/custom/ExprRawExpression.java | 98 +- .../skript/custom/SyntaxParseEvent.java | 76 +- .../skript/reflect/ExprClassReference.java | 74 +- .../skript/reflect/ExprEvent.java | 60 +- .../skript/reflect/ExprJavaCall.java | 1614 ++++++++--------- .../skript/reflect/ExprJavaError.java | 50 +- .../skript/reflect/ExprJavaType.java | 88 +- .../skript/reflect/ExprJavaTypeOf.java | 72 +- .../skript/reflect/ExprMemberNames.java | 82 +- .../skript/reflect/ExprMembers.java | 88 +- .../skript/reflect/ExprNewArray.java | 74 +- .../skript/reflect/ExprProxy.java | 350 ++-- .../reflect/sections/EffRunSection.java | 248 +-- .../skript/reflect/sections/SecSection.java | 160 +- .../skript/reflect/sections/Section.java | 72 +- .../skript/reflect/sections/SectionEvent.java | 36 +- .../skriptmirror/util/JavaTypeWrapper.java | 94 +- .../com/btk5h/skriptmirror/util/JavaUtil.java | 742 ++++---- .../com/btk5h/skriptmirror/util/LRUCache.java | 18 +- .../skriptmirror/util/SkriptMirrorUtil.java | 216 +-- .../skriptmirror/util/SkriptReflection.java | 562 +++--- .../btk5h/skriptmirror/util/SkriptUtil.java | 280 +-- .../skriptmirror/util/StringSimilarity.java | 254 +-- .../util/lookup/LookupGetter.java | 6 +- .../java/elements/events/EvtByReflection.java | 270 +-- .../elements/structures/StructImport.java | 342 ++-- .../reflect/syntax/CustomSyntaxStructure.java | 478 ++--- .../reflect/syntax/PatternsEntryData.java | 48 +- .../syntax/condition/ConditionCheckEvent.java | 68 +- .../syntax/condition/ConditionSyntaxInfo.java | 86 +- .../condition/elements/CustomCondition.java | 180 +- .../elements/EffNegateCondition.java | 42 +- .../elements/StructCustomCondition.java | 266 +-- .../syntax/effect/EffectSyntaxInfo.java | 42 +- .../syntax/effect/EffectTriggerEvent.java | 90 +- .../syntax/effect/elements/CustomEffect.java | 180 +- .../effect/elements/EffDelayEffect.java | 40 +- .../effect/elements/StructCustomEffect.java | 226 +-- .../syntax/event/BukkitCustomEvent.java | 154 +- .../reflect/syntax/event/EventSyntaxInfo.java | 50 +- .../syntax/event/EventTriggerEvent.java | 62 +- .../syntax/event/EventValuesEntryData.java | 70 +- .../event/elements/CondEventCancelled.java | 22 +- .../syntax/event/elements/CustomEvent.java | 128 +- .../event/elements/CustomEventUtils.java | 74 +- .../syntax/event/elements/EffCallEvent.java | 44 +- .../event/elements/ExprCustomEvent.java | 166 +- .../event/elements/ExprCustomEventValue.java | 154 +- .../syntax/event/elements/ExprEventData.java | 82 +- .../elements/ExprReplacedEventValue.java | 104 +- .../event/elements/StructCustomEvent.java | 266 +-- .../syntax/expression/ChangerEntryData.java | 80 +- .../syntax/expression/ConstantGetEvent.java | 22 +- .../syntax/expression/ConstantSyntaxInfo.java | 44 +- .../expression/ExpressionChangeEvent.java | 34 +- .../syntax/expression/ExpressionGetEvent.java | 38 +- .../expression/ExpressionSyntaxInfo.java | 192 +- .../expression/elements/CustomExpression.java | 552 +++--- .../syntax/expression/elements/EffReturn.java | 188 +- .../expression/elements/ExprChangeValue.java | 306 ++-- .../elements/StructCustomConstant.java | 84 +- .../elements/StructCustomExpression.java | 438 ++--- 97 files changed, 8226 insertions(+), 8227 deletions(-) diff --git a/.editorconfig b/.editorconfig index e5080f23..3dfeb8a1 100644 --- a/.editorconfig +++ b/.editorconfig @@ -2,8 +2,8 @@ root = true [*] -indent_style = space -indent_size = 2 +indent_style = tab +indent_size = 4 end_of_line = lf charset = utf-8 trim_trailing_whitespace = true diff --git a/build.gradle b/build.gradle index beab3d35..258cb62e 100644 --- a/build.gradle +++ b/build.gradle @@ -6,35 +6,35 @@ version '2.4' apply plugin: 'java' repositories { - mavenCentral() - maven { - url 'https://hub.spigotmc.org/nexus/content/repositories/snapshots/' - } - maven { - url 'https://oss.sonatype.org/content/groups/public/' - } - maven { - url 'https://repo.destroystokyo.com/repository/maven-public/' - } - maven { - url 'https://repo.skriptlang.org/releases' - } + mavenCentral() + maven { + url 'https://hub.spigotmc.org/nexus/content/repositories/snapshots/' + } + maven { + url 'https://oss.sonatype.org/content/groups/public/' + } + maven { + url 'https://repo.destroystokyo.com/repository/maven-public/' + } + maven { + url 'https://repo.skriptlang.org/releases' + } } processResources { - filter ReplaceTokens, tokens: [ - "version": version - ] + filter ReplaceTokens, tokens: [ + "version": version + ] } -compileJava { - sourceCompatibility = '1.8' - targetCompatibility = '1.8' - options.encoding = 'UTF-8' +compileJava { + sourceCompatibility = '1.8' + targetCompatibility = '1.8' + options.encoding = 'UTF-8' } dependencies { - implementation 'org.spigotmc:spigot-api:1.13.2-R0.1-SNAPSHOT' - implementation 'com.github.SkriptLang:Skript:2.8.0' - implementation 'org.eclipse.jdt:org.eclipse.jdt.annotation:1.1.0' + implementation 'org.spigotmc:spigot-api:1.13.2-R0.1-SNAPSHOT' + implementation 'com.github.SkriptLang:Skript:2.8.0' + implementation 'org.eclipse.jdt:org.eclipse.jdt.annotation:1.1.0' } diff --git a/src/main/java/com/btk5h/skriptmirror/Descriptor.java b/src/main/java/com/btk5h/skriptmirror/Descriptor.java index 40c6e7c2..ada2e821 100644 --- a/src/main/java/com/btk5h/skriptmirror/Descriptor.java +++ b/src/main/java/com/btk5h/skriptmirror/Descriptor.java @@ -20,152 +20,152 @@ */ public final class Descriptor { - /** - * A regex string for a list of array symbols, e.g. {@code [][][]}. - */ - private static final String PACKAGE_ARRAY = SkriptMirrorUtil.PACKAGE + "(?:\\[])*"; - - /** - * A regex {@link Pattern} for a single array symbol, matches only {@code []}. - */ - private static final Pattern PACKAGE_ARRAY_SINGLE = Pattern.compile("\\[]"); - - /** - * A regex {@link Pattern} for a {@link Descriptor}. - */ - private static final Pattern DESCRIPTOR = - Pattern.compile("" + - "(?:\\[(" + SkriptMirrorUtil.PACKAGE + ")])?" + - "(" + SkriptMirrorUtil.IDENTIFIER + ")" + - "(?:\\[((?:" + PACKAGE_ARRAY + "\\s*,\\s*)*(?:" + PACKAGE_ARRAY + "))])?" - ); - - private final Class javaClass; - private final String name; - private final Class[] parameterTypes; - - public Descriptor(Class javaClass, String name, Class[] parameterTypes) { - this.javaClass = javaClass; - this.name = name; - this.parameterTypes = parameterTypes; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - Descriptor that = (Descriptor) o; - return Objects.equals(javaClass, that.javaClass) && - Objects.equals(name, that.name); - } - - @Override - public int hashCode() { - return Objects.hash(javaClass, name); - } - - public Class getJavaClass() { - return javaClass; - } - - public String getName() { - return name; - } - - public Class[] getParameterTypes() { - return parameterTypes; - } - - @Override - public String toString() { - return toString(false); - } - - public String toString(boolean isStatic) { - return javaClass == null ? "(unspecified)" : SkriptMirrorUtil.getDebugName(javaClass) - + (isStatic ? "." : "#") - + name; - } - - /** - * Returns a new descriptor with a new {@link #javaClass}. - * If this Descriptors {@link #javaClass} is not null, it will instead return itself. - */ - public Descriptor orDefaultClass(Class cls) { - if (javaClass != null) { - return this; - } - - return new Descriptor(cls, name, parameterTypes); - } - - /** - * Parses the given {@link String} as a {@link Descriptor}. The script parameter is to get the imports. - */ - public static Descriptor parse(String desc, Script script) throws ImportNotFoundException { - Matcher m = DESCRIPTOR.matcher(desc); - - if (m.matches()) { - String cls = m.group(1); - Class javaClass = cls == null ? null : lookupClass(script, cls); - - String name = m.group(2); - - String args = m.group(3); - Class[] parameterTypes = args == null ? null : parseParams(args, script); - - return new Descriptor(javaClass, name, parameterTypes); - } - - return null; - } - - /** - * Parses a list of imported names, returning a class array containing the classes in the given string. - */ - private static Class[] parseParams(String args, Script script) throws ImportNotFoundException { - String[] rawClasses = args.split(","); - - Class[] parsedClasses = new Class[rawClasses.length]; - - for (int i = 0; i < rawClasses.length; i++) { - String userType = rawClasses[i].trim(); - - // Calculate array depth with regex - Matcher arrayDepthMatcher = PACKAGE_ARRAY_SINGLE.matcher(userType); - int arrayDepth = 0; - while (arrayDepthMatcher.find()) { - arrayDepth++; - } - - // Remove array's square brackets - userType = userType.substring(0, userType.length() - (2 * arrayDepth)); - - Class cls; - if (JavaUtil.PRIMITIVE_CLASS_NAMES.containsKey(userType)) { - cls = JavaUtil.PRIMITIVE_CLASS_NAMES.get(userType); - } else { - cls = lookupClass(script, userType); - } - - // Convert class to array class with calculated depth - cls = JavaUtil.getArrayClass(cls, arrayDepth); - - parsedClasses[i] = cls; - } - - return parsedClasses; - } - - /** - * Looks up a class from its imported name in the given file. - */ - private static Class lookupClass(Script script, String userType) throws ImportNotFoundException { - JavaType customImport = StructImport.lookup(script, userType); - if (customImport == null) - throw new ImportNotFoundException(userType); - - return customImport.getJavaClass(); - } + /** + * A regex string for a list of array symbols, e.g. {@code [][][]}. + */ + private static final String PACKAGE_ARRAY = SkriptMirrorUtil.PACKAGE + "(?:\\[])*"; + + /** + * A regex {@link Pattern} for a single array symbol, matches only {@code []}. + */ + private static final Pattern PACKAGE_ARRAY_SINGLE = Pattern.compile("\\[]"); + + /** + * A regex {@link Pattern} for a {@link Descriptor}. + */ + private static final Pattern DESCRIPTOR = + Pattern.compile("" + + "(?:\\[(" + SkriptMirrorUtil.PACKAGE + ")])?" + + "(" + SkriptMirrorUtil.IDENTIFIER + ")" + + "(?:\\[((?:" + PACKAGE_ARRAY + "\\s*,\\s*)*(?:" + PACKAGE_ARRAY + "))])?" + ); + + private final Class javaClass; + private final String name; + private final Class[] parameterTypes; + + public Descriptor(Class javaClass, String name, Class[] parameterTypes) { + this.javaClass = javaClass; + this.name = name; + this.parameterTypes = parameterTypes; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Descriptor that = (Descriptor) o; + return Objects.equals(javaClass, that.javaClass) && + Objects.equals(name, that.name); + } + + @Override + public int hashCode() { + return Objects.hash(javaClass, name); + } + + public Class getJavaClass() { + return javaClass; + } + + public String getName() { + return name; + } + + public Class[] getParameterTypes() { + return parameterTypes; + } + + @Override + public String toString() { + return toString(false); + } + + public String toString(boolean isStatic) { + return javaClass == null ? "(unspecified)" : SkriptMirrorUtil.getDebugName(javaClass) + + (isStatic ? "." : "#") + + name; + } + + /** + * Returns a new descriptor with a new {@link #javaClass}. + * If this Descriptors {@link #javaClass} is not null, it will instead return itself. + */ + public Descriptor orDefaultClass(Class cls) { + if (javaClass != null) { + return this; + } + + return new Descriptor(cls, name, parameterTypes); + } + + /** + * Parses the given {@link String} as a {@link Descriptor}. The script parameter is to get the imports. + */ + public static Descriptor parse(String desc, Script script) throws ImportNotFoundException { + Matcher m = DESCRIPTOR.matcher(desc); + + if (m.matches()) { + String cls = m.group(1); + Class javaClass = cls == null ? null : lookupClass(script, cls); + + String name = m.group(2); + + String args = m.group(3); + Class[] parameterTypes = args == null ? null : parseParams(args, script); + + return new Descriptor(javaClass, name, parameterTypes); + } + + return null; + } + + /** + * Parses a list of imported names, returning a class array containing the classes in the given string. + */ + private static Class[] parseParams(String args, Script script) throws ImportNotFoundException { + String[] rawClasses = args.split(","); + + Class[] parsedClasses = new Class[rawClasses.length]; + + for (int i = 0; i < rawClasses.length; i++) { + String userType = rawClasses[i].trim(); + + // Calculate array depth with regex + Matcher arrayDepthMatcher = PACKAGE_ARRAY_SINGLE.matcher(userType); + int arrayDepth = 0; + while (arrayDepthMatcher.find()) { + arrayDepth++; + } + + // Remove array's square brackets + userType = userType.substring(0, userType.length() - (2 * arrayDepth)); + + Class cls; + if (JavaUtil.PRIMITIVE_CLASS_NAMES.containsKey(userType)) { + cls = JavaUtil.PRIMITIVE_CLASS_NAMES.get(userType); + } else { + cls = lookupClass(script, userType); + } + + // Convert class to array class with calculated depth + cls = JavaUtil.getArrayClass(cls, arrayDepth); + + parsedClasses[i] = cls; + } + + return parsedClasses; + } + + /** + * Looks up a class from its imported name in the given file. + */ + private static Class lookupClass(Script script, String userType) throws ImportNotFoundException { + JavaType customImport = StructImport.lookup(script, userType); + if (customImport == null) + throw new ImportNotFoundException(userType); + + return customImport.getJavaClass(); + } } diff --git a/src/main/java/com/btk5h/skriptmirror/FunctionWrapper.java b/src/main/java/com/btk5h/skriptmirror/FunctionWrapper.java index acc79dc2..07f54760 100644 --- a/src/main/java/com/btk5h/skriptmirror/FunctionWrapper.java +++ b/src/main/java/com/btk5h/skriptmirror/FunctionWrapper.java @@ -7,33 +7,33 @@ public class FunctionWrapper { - private final String name; - private final Object[] arguments; - - public FunctionWrapper(String name, Object[] arguments) { - this.name = name; - this.arguments = arguments; - } - - public String getName() { - return name; - } - - public Object[] getArguments() { - return arguments; - } - - @Nullable - public Function getFunction() { - // Get current script file name - String script = null; - ParserInstance parserInstance = ParserInstance.get(); - if (parserInstance.isActive()) { - script = parserInstance.getCurrentScript().getConfig().getFileName(); - } - - return Functions.getFunction(name, script); - } + private final String name; + private final Object[] arguments; + + public FunctionWrapper(String name, Object[] arguments) { + this.name = name; + this.arguments = arguments; + } + + public String getName() { + return name; + } + + public Object[] getArguments() { + return arguments; + } + + @Nullable + public Function getFunction() { + // Get current script file name + String script = null; + ParserInstance parserInstance = ParserInstance.get(); + if (parserInstance.isActive()) { + script = parserInstance.getCurrentScript().getConfig().getFileName(); + } + + return Functions.getFunction(name, script); + } } diff --git a/src/main/java/com/btk5h/skriptmirror/ImportNotFoundException.java b/src/main/java/com/btk5h/skriptmirror/ImportNotFoundException.java index 0abfbae0..415c29b8 100644 --- a/src/main/java/com/btk5h/skriptmirror/ImportNotFoundException.java +++ b/src/main/java/com/btk5h/skriptmirror/ImportNotFoundException.java @@ -6,15 +6,15 @@ */ public class ImportNotFoundException extends Exception { - private final String userType; + private final String userType; - public ImportNotFoundException(String userType) { - super("Import not found: " + userType); - this.userType = userType; - } + public ImportNotFoundException(String userType) { + super("Import not found: " + userType); + this.userType = userType; + } - public String getUserType() { - return userType; - } + public String getUserType() { + return userType; + } } diff --git a/src/main/java/com/btk5h/skriptmirror/JavaCallException.java b/src/main/java/com/btk5h/skriptmirror/JavaCallException.java index 216ab5b8..5ad3ddaf 100644 --- a/src/main/java/com/btk5h/skriptmirror/JavaCallException.java +++ b/src/main/java/com/btk5h/skriptmirror/JavaCallException.java @@ -1,12 +1,12 @@ package com.btk5h.skriptmirror; public class JavaCallException extends RuntimeException { - public JavaCallException(String message) { - super(message); - } + public JavaCallException(String message) { + super(message); + } - @Override - public synchronized Throwable fillInStackTrace() { - return this; - } + @Override + public synchronized Throwable fillInStackTrace() { + return this; + } } diff --git a/src/main/java/com/btk5h/skriptmirror/JavaType.java b/src/main/java/com/btk5h/skriptmirror/JavaType.java index 2e529db4..20e307ee 100644 --- a/src/main/java/com/btk5h/skriptmirror/JavaType.java +++ b/src/main/java/com/btk5h/skriptmirror/JavaType.java @@ -4,27 +4,27 @@ public final class JavaType { - private final Class javaClass; - - public JavaType(Class javaClass) { - this.javaClass = javaClass; - } - - public Class getJavaClass() { - return javaClass; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - JavaType javaType1 = (JavaType) o; - return Objects.equals(javaClass, javaType1.javaClass); - } - - @Override - public int hashCode() { - return Objects.hash(javaClass); - } + private final Class javaClass; + + public JavaType(Class javaClass) { + this.javaClass = javaClass; + } + + public Class getJavaClass() { + return javaClass; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + JavaType javaType1 = (JavaType) o; + return Objects.equals(javaClass, javaType1.javaClass); + } + + @Override + public int hashCode() { + return Objects.hash(javaClass); + } } diff --git a/src/main/java/com/btk5h/skriptmirror/LibraryLoader.java b/src/main/java/com/btk5h/skriptmirror/LibraryLoader.java index 35026bfb..f5e383a5 100644 --- a/src/main/java/com/btk5h/skriptmirror/LibraryLoader.java +++ b/src/main/java/com/btk5h/skriptmirror/LibraryLoader.java @@ -16,39 +16,39 @@ import java.util.List; public class LibraryLoader { - private static ClassLoader classLoader = LibraryLoader.class.getClassLoader(); - - private static final PathMatcher MATCHER = - FileSystems.getDefault().getPathMatcher("glob:**/*.jar"); - - private static class LibraryVisitor extends SimpleFileVisitor { - private List urls = new ArrayList<>(); - - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { - if (MATCHER.matches(file)) { - Skript.info("Loaded external library " + file.getFileName()); - urls.add(file.toUri().toURL()); - } - return super.visitFile(file, attrs); - } - - public URL[] getUrls() { - return urls.toArray(new URL[urls.size()]); - } - } - - public static void loadLibraries(Path dataFolder) throws IOException { - if (Files.isDirectory(dataFolder)) { - LibraryVisitor visitor = new LibraryVisitor(); - Files.walkFileTree(dataFolder, visitor); - classLoader = new URLClassLoader(visitor.getUrls(), LibraryLoader.class.getClassLoader()); - } else { - Files.createDirectory(dataFolder); - } - } - - public static ClassLoader getClassLoader() { - return classLoader; - } + private static ClassLoader classLoader = LibraryLoader.class.getClassLoader(); + + private static final PathMatcher MATCHER = + FileSystems.getDefault().getPathMatcher("glob:**/*.jar"); + + private static class LibraryVisitor extends SimpleFileVisitor { + private List urls = new ArrayList<>(); + + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + if (MATCHER.matches(file)) { + Skript.info("Loaded external library " + file.getFileName()); + urls.add(file.toUri().toURL()); + } + return super.visitFile(file, attrs); + } + + public URL[] getUrls() { + return urls.toArray(new URL[urls.size()]); + } + } + + public static void loadLibraries(Path dataFolder) throws IOException { + if (Files.isDirectory(dataFolder)) { + LibraryVisitor visitor = new LibraryVisitor(); + Files.walkFileTree(dataFolder, visitor); + classLoader = new URLClassLoader(visitor.getUrls(), LibraryLoader.class.getClassLoader()); + } else { + Files.createDirectory(dataFolder); + } + } + + public static ClassLoader getClassLoader() { + return classLoader; + } } diff --git a/src/main/java/com/btk5h/skriptmirror/Metrics.java b/src/main/java/com/btk5h/skriptmirror/Metrics.java index 1d67a321..9291c1d3 100644 --- a/src/main/java/com/btk5h/skriptmirror/Metrics.java +++ b/src/main/java/com/btk5h/skriptmirror/Metrics.java @@ -43,700 +43,700 @@ @SuppressWarnings({"WeakerAccess", "unused"}) public class Metrics { - static { - // You can use the property to disable the check in your test environment - if (System.getProperty("bstats.relocatecheck") == null || !System.getProperty("bstats.relocatecheck").equals("false")) { - // Maven's Relocate is clever and changes strings, too. So we have to use this little "trick" ... :D - final String defaultPackage = new String( - new byte[]{'o', 'r', 'g', '.', 'b', 's', 't', 'a', 't', 's', '.', 'b', 'u', 'k', 'k', 'i', 't'}); - final String examplePackage = new String(new byte[]{'y', 'o', 'u', 'r', '.', 'p', 'a', 'c', 'k', 'a', 'g', 'e'}); - // We want to make sure nobody just copy & pastes the example and use the wrong package names - if (Metrics.class.getPackage().getName().equals(defaultPackage) || Metrics.class.getPackage().getName().equals(examplePackage)) { - throw new IllegalStateException("bStats Metrics class has not been relocated correctly!"); - } - } - } - - // This ThreadFactory enforces the naming convention for our Threads - private final ThreadFactory threadFactory = task -> new Thread(task, "bStats-Metrics"); - - // Executor service for requests - // We use an executor service because the Bukkit scheduler is affected by server lags - private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1, threadFactory); - - // The version of this bStats class - public static final int B_STATS_VERSION = 1; - - // The url to which the data is sent - private static final String URL = "https://bStats.org/submitData/bukkit"; - - // Is bStats enabled on this server? - private boolean enabled; - - // Should failed requests be logged? - private static boolean logFailedRequests; - - // Should the sent data be logged? - private static boolean logSentData; - - // Should the response text be logged? - private static boolean logResponseStatusText; - - // The uuid of the server - private static String serverUUID; - - // The plugin - private final Plugin plugin; - - // The plugin id - private final int pluginId; - - // A list with all custom charts - private final List charts = new ArrayList<>(); - - /** - * Class constructor. - * - * @param plugin The plugin which stats should be submitted. - * @param pluginId The id of the plugin. - * It can be found at What is my plugin id? - */ - public Metrics(Plugin plugin, int pluginId) { - if (plugin == null) { - throw new IllegalArgumentException("Plugin cannot be null!"); - } - this.plugin = plugin; - this.pluginId = pluginId; - - // Get the config file - File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats"); - File configFile = new File(bStatsFolder, "config.yml"); - YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile); - - // Check if the config file exists - if (!config.isSet("serverUuid")) { - - // Add default values - config.addDefault("enabled", true); - // Every server gets it's unique random id. - config.addDefault("serverUuid", UUID.randomUUID().toString()); - // Should failed request be logged? - config.addDefault("logFailedRequests", false); - // Should the sent data be logged? - config.addDefault("logSentData", false); - // Should the response text be logged? - config.addDefault("logResponseStatusText", false); - - // Inform the server owners about bStats - config.options().header( - "bStats collects some data for plugin authors like how many servers are using their plugins.\n" + - "To honor their work, you should not disable it.\n" + - "This has nearly no effect on the server performance!\n" + - "Check out https://bStats.org/ to learn more :)" - ).copyDefaults(true); - try { - config.save(configFile); - } catch (IOException ignored) { } - } - - // Load the data - enabled = config.getBoolean("enabled", true); - serverUUID = config.getString("serverUuid"); - logFailedRequests = config.getBoolean("logFailedRequests", false); - logSentData = config.getBoolean("logSentData", false); - logResponseStatusText = config.getBoolean("logResponseStatusText", false); - - if (enabled) { - boolean found = false; - // Search for all other bStats Metrics classes to see if we are the first one - for (Class service : Bukkit.getServicesManager().getKnownServices()) { - try { - service.getField("B_STATS_VERSION"); // Our identifier :) - found = true; // We aren't the first - break; - } catch (NoSuchFieldException ignored) { } - } - // Register our service - Bukkit.getServicesManager().register(Metrics.class, this, plugin, ServicePriority.Normal); - if (!found) { - // We are the first! - startSubmitting(); - } - } - } - - /** - * Checks if bStats is enabled. - * - * @return Whether bStats is enabled or not. - */ - public boolean isEnabled() { - return enabled; - } - - /** - * Adds a custom chart. - * - * @param chart The chart to add. - */ - public void addCustomChart(CustomChart chart) { - if (chart == null) { - throw new IllegalArgumentException("Chart cannot be null!"); - } - charts.add(chart); - } - - /** - * Starts the Scheduler which submits our data every 30 minutes. - */ - private void startSubmitting() { - final Runnable submitTask = () -> { - if (!plugin.isEnabled()) { // Plugin was disabled - scheduler.shutdown(); - return; - } - // Nevertheless we want our code to run in the Bukkit main thread, so we have to use the Bukkit scheduler - // Don't be afraid! The connection to the bStats server is still async, only the stats collection is sync ;) - Bukkit.getScheduler().runTask(plugin, this::submitData); - }; - - // Many servers tend to restart at a fixed time at xx:00 which causes an uneven distribution of requests on the - // bStats backend. To circumvent this problem, we introduce some randomness into the initial and second delay. - // WARNING: You must not modify and part of this Metrics class, including the submit delay or frequency! - // WARNING: Modifying this code will get your plugin banned on bStats. Just don't do it! - long initialDelay = (long) (1000 * 60 * (3 + Math.random() * 3)); - long secondDelay = (long) (1000 * 60 * (Math.random() * 30)); - scheduler.schedule(submitTask, initialDelay, TimeUnit.MILLISECONDS); - scheduler.scheduleAtFixedRate(submitTask, initialDelay + secondDelay, 1000 * 60 * 30, TimeUnit.MILLISECONDS); - } - - /** - * Gets the plugin specific data. - * This method is called using Reflection. - * - * @return The plugin specific data. - */ - public JsonObject getPluginData() { - JsonObject data = new JsonObject(); - - String pluginName = plugin.getDescription().getName(); - String pluginVersion = plugin.getDescription().getVersion(); - - data.addProperty("pluginName", pluginName); // Append the name of the plugin - data.addProperty("id", pluginId); // Append the id of the plugin - data.addProperty("pluginVersion", pluginVersion); // Append the version of the plugin - JsonArray customCharts = new JsonArray(); - for (CustomChart customChart : charts) { - // Add the data of the custom charts - JsonObject chart = customChart.getRequestJsonObject(); - if (chart == null) { // If the chart is null, we skip it - continue; - } - customCharts.add(chart); - } - data.add("customCharts", customCharts); - - return data; - } - - /** - * Gets the server specific data. - * - * @return The server specific data. - */ - private JsonObject getServerData() { - // Minecraft specific data - int playerAmount; - try { - // Around MC 1.8 the return type was changed to a collection from an array, - // This fixes java.lang.NoSuchMethodError: org.bukkit.Bukkit.getOnlinePlayers()Ljava/util/Collection; - Method onlinePlayersMethod = Class.forName("org.bukkit.Server").getMethod("getOnlinePlayers"); - playerAmount = onlinePlayersMethod.getReturnType().equals(Collection.class) - ? ((Collection) onlinePlayersMethod.invoke(Bukkit.getServer())).size() - : ((Player[]) onlinePlayersMethod.invoke(Bukkit.getServer())).length; - } catch (Exception e) { - playerAmount = Bukkit.getOnlinePlayers().size(); // Just use the new method if the Reflection failed - } - int onlineMode = Bukkit.getOnlineMode() ? 1 : 0; - String bukkitVersion = Bukkit.getVersion(); - String bukkitName = Bukkit.getName(); - - // OS/Java specific data - String javaVersion = System.getProperty("java.version"); - String osName = System.getProperty("os.name"); - String osArch = System.getProperty("os.arch"); - String osVersion = System.getProperty("os.version"); - int coreCount = Runtime.getRuntime().availableProcessors(); - - JsonObject data = new JsonObject(); - - data.addProperty("serverUUID", serverUUID); - - data.addProperty("playerAmount", playerAmount); - data.addProperty("onlineMode", onlineMode); - data.addProperty("bukkitVersion", bukkitVersion); - data.addProperty("bukkitName", bukkitName); - - data.addProperty("javaVersion", javaVersion); - data.addProperty("osName", osName); - data.addProperty("osArch", osArch); - data.addProperty("osVersion", osVersion); - data.addProperty("coreCount", coreCount); - - return data; - } - - /** - * Collects the data and sends it afterwards. - */ - private void submitData() { - final JsonObject data = getServerData(); - - JsonArray pluginData = new JsonArray(); - // Search for all other bStats Metrics classes to get their plugin data - for (Class service : Bukkit.getServicesManager().getKnownServices()) { - try { - service.getField("B_STATS_VERSION"); // Our identifier :) - - for (RegisteredServiceProvider provider : Bukkit.getServicesManager().getRegistrations(service)) { - try { - Object plugin = provider.getService().getMethod("getPluginData").invoke(provider.getProvider()); - if (plugin instanceof JsonObject) { - pluginData.add((JsonObject) plugin); - } else { // old bstats version compatibility - try { - Class jsonObjectJsonSimple = Class.forName("org.json.simple.JSONObject"); - if (plugin.getClass().isAssignableFrom(jsonObjectJsonSimple)) { - Method jsonStringGetter = jsonObjectJsonSimple.getDeclaredMethod("toJSONString"); - jsonStringGetter.setAccessible(true); - String jsonString = (String) jsonStringGetter.invoke(plugin); - JsonObject object = new JsonParser().parse(jsonString).getAsJsonObject(); - pluginData.add(object); - } - } catch (ClassNotFoundException e) { - // minecraft version 1.14+ - if (logFailedRequests) { - this.plugin.getLogger().log(Level.SEVERE, "Encountered unexpected exception", e); - } - } - } - } catch (NullPointerException | NoSuchMethodException | IllegalAccessException | InvocationTargetException ignored) { } - } - } catch (NoSuchFieldException ignored) { } - } - - data.add("plugins", pluginData); - - // Create a new thread for the connection to the bStats server - new Thread(() -> { - try { - // Send the data - sendData(plugin, data); - } catch (Exception e) { - // Something went wrong! :( - if (logFailedRequests) { - plugin.getLogger().log(Level.WARNING, "Could not submit plugin stats of " + plugin.getName(), e); - } - } - }).start(); - } - - /** - * Sends the data to the bStats server. - * - * @param plugin Any plugin. It's just used to get a logger instance. - * @param data The data to send. - * @throws Exception If the request failed. - */ - private static void sendData(Plugin plugin, JsonObject data) throws Exception { - if (data == null) { - throw new IllegalArgumentException("Data cannot be null!"); - } - if (Bukkit.isPrimaryThread()) { - throw new IllegalAccessException("This method must not be called from the main thread!"); - } - if (logSentData) { - plugin.getLogger().info("Sending data to bStats: " + data); - } - HttpsURLConnection connection = (HttpsURLConnection) new URL(URL).openConnection(); - - // Compress the data to save bandwidth - byte[] compressedData = compress(data.toString()); - - // Add headers - connection.setRequestMethod("POST"); - connection.addRequestProperty("Accept", "application/json"); - connection.addRequestProperty("Connection", "close"); - connection.addRequestProperty("Content-Encoding", "gzip"); // We gzip our request - connection.addRequestProperty("Content-Length", String.valueOf(compressedData.length)); - connection.setRequestProperty("Content-Type", "application/json"); // We send our data in JSON format - connection.setRequestProperty("User-Agent", "MC-Server/" + B_STATS_VERSION); - - // Send data - connection.setDoOutput(true); - try (DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream())) { - outputStream.write(compressedData); - } - - StringBuilder builder = new StringBuilder(); - try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) { - String line; - while ((line = bufferedReader.readLine()) != null) { - builder.append(line); - } - } - - if (logResponseStatusText) { - plugin.getLogger().info("Sent data to bStats and received response: " + builder); - } - } - - /** - * Gzips the given String. - * - * @param str The string to gzip. - * @return The gzipped String. - * @throws IOException If the compression failed. - */ - private static byte[] compress(final String str) throws IOException { - if (str == null) { - return null; - } - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - try (GZIPOutputStream gzip = new GZIPOutputStream(outputStream)) { - gzip.write(str.getBytes(StandardCharsets.UTF_8)); - } - return outputStream.toByteArray(); - } - - /** - * Represents a custom chart. - */ - public static abstract class CustomChart { - - // The id of the chart - final String chartId; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - */ - CustomChart(String chartId) { - if (chartId == null || chartId.isEmpty()) { - throw new IllegalArgumentException("ChartId cannot be null or empty!"); - } - this.chartId = chartId; - } - - private JsonObject getRequestJsonObject() { - JsonObject chart = new JsonObject(); - chart.addProperty("chartId", chartId); - try { - JsonObject data = getChartData(); - if (data == null) { - // If the data is null we don't send the chart. - return null; - } - chart.add("data", data); - } catch (Throwable t) { - if (logFailedRequests) { - Bukkit.getLogger().log(Level.WARNING, "Failed to get data for custom chart with id " + chartId, t); - } - return null; - } - return chart; - } - - protected abstract JsonObject getChartData() throws Exception; - - } - - /** - * Represents a custom simple pie. - */ - public static class SimplePie extends CustomChart { - - private final Callable callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public SimplePie(String chartId, Callable callable) { - super(chartId); - this.callable = callable; - } - - @Override - protected JsonObject getChartData() throws Exception { - JsonObject data = new JsonObject(); - String value = callable.call(); - if (value == null || value.isEmpty()) { - // Null = skip the chart - return null; - } - data.addProperty("value", value); - return data; - } - } - - /** - * Represents a custom advanced pie. - */ - public static class AdvancedPie extends CustomChart { - - private final Callable> callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public AdvancedPie(String chartId, Callable> callable) { - super(chartId); - this.callable = callable; - } - - @Override - protected JsonObject getChartData() throws Exception { - JsonObject data = new JsonObject(); - JsonObject values = new JsonObject(); - Map map = callable.call(); - if (map == null || map.isEmpty()) { - // Null = skip the chart - return null; - } - boolean allSkipped = true; - for (Map.Entry entry : map.entrySet()) { - if (entry.getValue() == 0) { - continue; // Skip this invalid - } - allSkipped = false; - values.addProperty(entry.getKey(), entry.getValue()); - } - if (allSkipped) { - // Null = skip the chart - return null; - } - data.add("values", values); - return data; - } - } - - /** - * Represents a custom drilldown pie. - */ - public static class DrilldownPie extends CustomChart { - - private final Callable>> callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public DrilldownPie(String chartId, Callable>> callable) { - super(chartId); - this.callable = callable; - } - - @Override - public JsonObject getChartData() throws Exception { - JsonObject data = new JsonObject(); - JsonObject values = new JsonObject(); - Map> map = callable.call(); - if (map == null || map.isEmpty()) { - // Null = skip the chart - return null; - } - boolean reallyAllSkipped = true; - for (Map.Entry> entryValues : map.entrySet()) { - JsonObject value = new JsonObject(); - boolean allSkipped = true; - for (Map.Entry valueEntry : map.get(entryValues.getKey()).entrySet()) { - value.addProperty(valueEntry.getKey(), valueEntry.getValue()); - allSkipped = false; - } - if (!allSkipped) { - reallyAllSkipped = false; - values.add(entryValues.getKey(), value); - } - } - if (reallyAllSkipped) { - // Null = skip the chart - return null; - } - data.add("values", values); - return data; - } - } - - /** - * Represents a custom single line chart. - */ - public static class SingleLineChart extends CustomChart { - - private final Callable callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public SingleLineChart(String chartId, Callable callable) { - super(chartId); - this.callable = callable; - } - - @Override - protected JsonObject getChartData() throws Exception { - JsonObject data = new JsonObject(); - int value = callable.call(); - if (value == 0) { - // Null = skip the chart - return null; - } - data.addProperty("value", value); - return data; - } - - } - - /** - * Represents a custom multi line chart. - */ - public static class MultiLineChart extends CustomChart { - - private final Callable> callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public MultiLineChart(String chartId, Callable> callable) { - super(chartId); - this.callable = callable; - } - - @Override - protected JsonObject getChartData() throws Exception { - JsonObject data = new JsonObject(); - JsonObject values = new JsonObject(); - Map map = callable.call(); - if (map == null || map.isEmpty()) { - // Null = skip the chart - return null; - } - boolean allSkipped = true; - for (Map.Entry entry : map.entrySet()) { - if (entry.getValue() == 0) { - continue; // Skip this invalid - } - allSkipped = false; - values.addProperty(entry.getKey(), entry.getValue()); - } - if (allSkipped) { - // Null = skip the chart - return null; - } - data.add("values", values); - return data; - } - - } - - /** - * Represents a custom simple bar chart. - */ - public static class SimpleBarChart extends CustomChart { - - private final Callable> callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public SimpleBarChart(String chartId, Callable> callable) { - super(chartId); - this.callable = callable; - } - - @Override - protected JsonObject getChartData() throws Exception { - JsonObject data = new JsonObject(); - JsonObject values = new JsonObject(); - Map map = callable.call(); - if (map == null || map.isEmpty()) { - // Null = skip the chart - return null; - } - for (Map.Entry entry : map.entrySet()) { - JsonArray categoryValues = new JsonArray(); - categoryValues.add(new JsonPrimitive(entry.getValue())); - values.add(entry.getKey(), categoryValues); - } - data.add("values", values); - return data; - } - - } - - /** - * Represents a custom advanced bar chart. - */ - public static class AdvancedBarChart extends CustomChart { - - private final Callable> callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public AdvancedBarChart(String chartId, Callable> callable) { - super(chartId); - this.callable = callable; - } - - @Override - protected JsonObject getChartData() throws Exception { - JsonObject data = new JsonObject(); - JsonObject values = new JsonObject(); - Map map = callable.call(); - if (map == null || map.isEmpty()) { - // Null = skip the chart - return null; - } - boolean allSkipped = true; - for (Map.Entry entry : map.entrySet()) { - if (entry.getValue().length == 0) { - continue; // Skip this invalid - } - allSkipped = false; - JsonArray categoryValues = new JsonArray(); - for (int categoryValue : entry.getValue()) { - categoryValues.add(new JsonPrimitive(categoryValue)); - } - values.add(entry.getKey(), categoryValues); - } - if (allSkipped) { - // Null = skip the chart - return null; - } - data.add("values", values); - return data; - } - } + static { + // You can use the property to disable the check in your test environment + if (System.getProperty("bstats.relocatecheck") == null || !System.getProperty("bstats.relocatecheck").equals("false")) { + // Maven's Relocate is clever and changes strings, too. So we have to use this little "trick" ... :D + final String defaultPackage = new String( + new byte[]{'o', 'r', 'g', '.', 'b', 's', 't', 'a', 't', 's', '.', 'b', 'u', 'k', 'k', 'i', 't'}); + final String examplePackage = new String(new byte[]{'y', 'o', 'u', 'r', '.', 'p', 'a', 'c', 'k', 'a', 'g', 'e'}); + // We want to make sure nobody just copy & pastes the example and use the wrong package names + if (Metrics.class.getPackage().getName().equals(defaultPackage) || Metrics.class.getPackage().getName().equals(examplePackage)) { + throw new IllegalStateException("bStats Metrics class has not been relocated correctly!"); + } + } + } + + // This ThreadFactory enforces the naming convention for our Threads + private final ThreadFactory threadFactory = task -> new Thread(task, "bStats-Metrics"); + + // Executor service for requests + // We use an executor service because the Bukkit scheduler is affected by server lags + private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1, threadFactory); + + // The version of this bStats class + public static final int B_STATS_VERSION = 1; + + // The url to which the data is sent + private static final String URL = "https://bStats.org/submitData/bukkit"; + + // Is bStats enabled on this server? + private boolean enabled; + + // Should failed requests be logged? + private static boolean logFailedRequests; + + // Should the sent data be logged? + private static boolean logSentData; + + // Should the response text be logged? + private static boolean logResponseStatusText; + + // The uuid of the server + private static String serverUUID; + + // The plugin + private final Plugin plugin; + + // The plugin id + private final int pluginId; + + // A list with all custom charts + private final List charts = new ArrayList<>(); + + /** + * Class constructor. + * + * @param plugin The plugin which stats should be submitted. + * @param pluginId The id of the plugin. + * It can be found at What is my plugin id? + */ + public Metrics(Plugin plugin, int pluginId) { + if (plugin == null) { + throw new IllegalArgumentException("Plugin cannot be null!"); + } + this.plugin = plugin; + this.pluginId = pluginId; + + // Get the config file + File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats"); + File configFile = new File(bStatsFolder, "config.yml"); + YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile); + + // Check if the config file exists + if (!config.isSet("serverUuid")) { + + // Add default values + config.addDefault("enabled", true); + // Every server gets it's unique random id. + config.addDefault("serverUuid", UUID.randomUUID().toString()); + // Should failed request be logged? + config.addDefault("logFailedRequests", false); + // Should the sent data be logged? + config.addDefault("logSentData", false); + // Should the response text be logged? + config.addDefault("logResponseStatusText", false); + + // Inform the server owners about bStats + config.options().header( + "bStats collects some data for plugin authors like how many servers are using their plugins.\n" + + "To honor their work, you should not disable it.\n" + + "This has nearly no effect on the server performance!\n" + + "Check out https://bStats.org/ to learn more :)" + ).copyDefaults(true); + try { + config.save(configFile); + } catch (IOException ignored) { } + } + + // Load the data + enabled = config.getBoolean("enabled", true); + serverUUID = config.getString("serverUuid"); + logFailedRequests = config.getBoolean("logFailedRequests", false); + logSentData = config.getBoolean("logSentData", false); + logResponseStatusText = config.getBoolean("logResponseStatusText", false); + + if (enabled) { + boolean found = false; + // Search for all other bStats Metrics classes to see if we are the first one + for (Class service : Bukkit.getServicesManager().getKnownServices()) { + try { + service.getField("B_STATS_VERSION"); // Our identifier :) + found = true; // We aren't the first + break; + } catch (NoSuchFieldException ignored) { } + } + // Register our service + Bukkit.getServicesManager().register(Metrics.class, this, plugin, ServicePriority.Normal); + if (!found) { + // We are the first! + startSubmitting(); + } + } + } + + /** + * Checks if bStats is enabled. + * + * @return Whether bStats is enabled or not. + */ + public boolean isEnabled() { + return enabled; + } + + /** + * Adds a custom chart. + * + * @param chart The chart to add. + */ + public void addCustomChart(CustomChart chart) { + if (chart == null) { + throw new IllegalArgumentException("Chart cannot be null!"); + } + charts.add(chart); + } + + /** + * Starts the Scheduler which submits our data every 30 minutes. + */ + private void startSubmitting() { + final Runnable submitTask = () -> { + if (!plugin.isEnabled()) { // Plugin was disabled + scheduler.shutdown(); + return; + } + // Nevertheless we want our code to run in the Bukkit main thread, so we have to use the Bukkit scheduler + // Don't be afraid! The connection to the bStats server is still async, only the stats collection is sync ;) + Bukkit.getScheduler().runTask(plugin, this::submitData); + }; + + // Many servers tend to restart at a fixed time at xx:00 which causes an uneven distribution of requests on the + // bStats backend. To circumvent this problem, we introduce some randomness into the initial and second delay. + // WARNING: You must not modify and part of this Metrics class, including the submit delay or frequency! + // WARNING: Modifying this code will get your plugin banned on bStats. Just don't do it! + long initialDelay = (long) (1000 * 60 * (3 + Math.random() * 3)); + long secondDelay = (long) (1000 * 60 * (Math.random() * 30)); + scheduler.schedule(submitTask, initialDelay, TimeUnit.MILLISECONDS); + scheduler.scheduleAtFixedRate(submitTask, initialDelay + secondDelay, 1000 * 60 * 30, TimeUnit.MILLISECONDS); + } + + /** + * Gets the plugin specific data. + * This method is called using Reflection. + * + * @return The plugin specific data. + */ + public JsonObject getPluginData() { + JsonObject data = new JsonObject(); + + String pluginName = plugin.getDescription().getName(); + String pluginVersion = plugin.getDescription().getVersion(); + + data.addProperty("pluginName", pluginName); // Append the name of the plugin + data.addProperty("id", pluginId); // Append the id of the plugin + data.addProperty("pluginVersion", pluginVersion); // Append the version of the plugin + JsonArray customCharts = new JsonArray(); + for (CustomChart customChart : charts) { + // Add the data of the custom charts + JsonObject chart = customChart.getRequestJsonObject(); + if (chart == null) { // If the chart is null, we skip it + continue; + } + customCharts.add(chart); + } + data.add("customCharts", customCharts); + + return data; + } + + /** + * Gets the server specific data. + * + * @return The server specific data. + */ + private JsonObject getServerData() { + // Minecraft specific data + int playerAmount; + try { + // Around MC 1.8 the return type was changed to a collection from an array, + // This fixes java.lang.NoSuchMethodError: org.bukkit.Bukkit.getOnlinePlayers()Ljava/util/Collection; + Method onlinePlayersMethod = Class.forName("org.bukkit.Server").getMethod("getOnlinePlayers"); + playerAmount = onlinePlayersMethod.getReturnType().equals(Collection.class) + ? ((Collection) onlinePlayersMethod.invoke(Bukkit.getServer())).size() + : ((Player[]) onlinePlayersMethod.invoke(Bukkit.getServer())).length; + } catch (Exception e) { + playerAmount = Bukkit.getOnlinePlayers().size(); // Just use the new method if the Reflection failed + } + int onlineMode = Bukkit.getOnlineMode() ? 1 : 0; + String bukkitVersion = Bukkit.getVersion(); + String bukkitName = Bukkit.getName(); + + // OS/Java specific data + String javaVersion = System.getProperty("java.version"); + String osName = System.getProperty("os.name"); + String osArch = System.getProperty("os.arch"); + String osVersion = System.getProperty("os.version"); + int coreCount = Runtime.getRuntime().availableProcessors(); + + JsonObject data = new JsonObject(); + + data.addProperty("serverUUID", serverUUID); + + data.addProperty("playerAmount", playerAmount); + data.addProperty("onlineMode", onlineMode); + data.addProperty("bukkitVersion", bukkitVersion); + data.addProperty("bukkitName", bukkitName); + + data.addProperty("javaVersion", javaVersion); + data.addProperty("osName", osName); + data.addProperty("osArch", osArch); + data.addProperty("osVersion", osVersion); + data.addProperty("coreCount", coreCount); + + return data; + } + + /** + * Collects the data and sends it afterwards. + */ + private void submitData() { + final JsonObject data = getServerData(); + + JsonArray pluginData = new JsonArray(); + // Search for all other bStats Metrics classes to get their plugin data + for (Class service : Bukkit.getServicesManager().getKnownServices()) { + try { + service.getField("B_STATS_VERSION"); // Our identifier :) + + for (RegisteredServiceProvider provider : Bukkit.getServicesManager().getRegistrations(service)) { + try { + Object plugin = provider.getService().getMethod("getPluginData").invoke(provider.getProvider()); + if (plugin instanceof JsonObject) { + pluginData.add((JsonObject) plugin); + } else { // old bstats version compatibility + try { + Class jsonObjectJsonSimple = Class.forName("org.json.simple.JSONObject"); + if (plugin.getClass().isAssignableFrom(jsonObjectJsonSimple)) { + Method jsonStringGetter = jsonObjectJsonSimple.getDeclaredMethod("toJSONString"); + jsonStringGetter.setAccessible(true); + String jsonString = (String) jsonStringGetter.invoke(plugin); + JsonObject object = new JsonParser().parse(jsonString).getAsJsonObject(); + pluginData.add(object); + } + } catch (ClassNotFoundException e) { + // minecraft version 1.14+ + if (logFailedRequests) { + this.plugin.getLogger().log(Level.SEVERE, "Encountered unexpected exception", e); + } + } + } + } catch (NullPointerException | NoSuchMethodException | IllegalAccessException | InvocationTargetException ignored) { } + } + } catch (NoSuchFieldException ignored) { } + } + + data.add("plugins", pluginData); + + // Create a new thread for the connection to the bStats server + new Thread(() -> { + try { + // Send the data + sendData(plugin, data); + } catch (Exception e) { + // Something went wrong! :( + if (logFailedRequests) { + plugin.getLogger().log(Level.WARNING, "Could not submit plugin stats of " + plugin.getName(), e); + } + } + }).start(); + } + + /** + * Sends the data to the bStats server. + * + * @param plugin Any plugin. It's just used to get a logger instance. + * @param data The data to send. + * @throws Exception If the request failed. + */ + private static void sendData(Plugin plugin, JsonObject data) throws Exception { + if (data == null) { + throw new IllegalArgumentException("Data cannot be null!"); + } + if (Bukkit.isPrimaryThread()) { + throw new IllegalAccessException("This method must not be called from the main thread!"); + } + if (logSentData) { + plugin.getLogger().info("Sending data to bStats: " + data); + } + HttpsURLConnection connection = (HttpsURLConnection) new URL(URL).openConnection(); + + // Compress the data to save bandwidth + byte[] compressedData = compress(data.toString()); + + // Add headers + connection.setRequestMethod("POST"); + connection.addRequestProperty("Accept", "application/json"); + connection.addRequestProperty("Connection", "close"); + connection.addRequestProperty("Content-Encoding", "gzip"); // We gzip our request + connection.addRequestProperty("Content-Length", String.valueOf(compressedData.length)); + connection.setRequestProperty("Content-Type", "application/json"); // We send our data in JSON format + connection.setRequestProperty("User-Agent", "MC-Server/" + B_STATS_VERSION); + + // Send data + connection.setDoOutput(true); + try (DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream())) { + outputStream.write(compressedData); + } + + StringBuilder builder = new StringBuilder(); + try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) { + String line; + while ((line = bufferedReader.readLine()) != null) { + builder.append(line); + } + } + + if (logResponseStatusText) { + plugin.getLogger().info("Sent data to bStats and received response: " + builder); + } + } + + /** + * Gzips the given String. + * + * @param str The string to gzip. + * @return The gzipped String. + * @throws IOException If the compression failed. + */ + private static byte[] compress(final String str) throws IOException { + if (str == null) { + return null; + } + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + try (GZIPOutputStream gzip = new GZIPOutputStream(outputStream)) { + gzip.write(str.getBytes(StandardCharsets.UTF_8)); + } + return outputStream.toByteArray(); + } + + /** + * Represents a custom chart. + */ + public static abstract class CustomChart { + + // The id of the chart + final String chartId; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + */ + CustomChart(String chartId) { + if (chartId == null || chartId.isEmpty()) { + throw new IllegalArgumentException("ChartId cannot be null or empty!"); + } + this.chartId = chartId; + } + + private JsonObject getRequestJsonObject() { + JsonObject chart = new JsonObject(); + chart.addProperty("chartId", chartId); + try { + JsonObject data = getChartData(); + if (data == null) { + // If the data is null we don't send the chart. + return null; + } + chart.add("data", data); + } catch (Throwable t) { + if (logFailedRequests) { + Bukkit.getLogger().log(Level.WARNING, "Failed to get data for custom chart with id " + chartId, t); + } + return null; + } + return chart; + } + + protected abstract JsonObject getChartData() throws Exception; + + } + + /** + * Represents a custom simple pie. + */ + public static class SimplePie extends CustomChart { + + private final Callable callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public SimplePie(String chartId, Callable callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObject getChartData() throws Exception { + JsonObject data = new JsonObject(); + String value = callable.call(); + if (value == null || value.isEmpty()) { + // Null = skip the chart + return null; + } + data.addProperty("value", value); + return data; + } + } + + /** + * Represents a custom advanced pie. + */ + public static class AdvancedPie extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public AdvancedPie(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObject getChartData() throws Exception { + JsonObject data = new JsonObject(); + JsonObject values = new JsonObject(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean allSkipped = true; + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue() == 0) { + continue; // Skip this invalid + } + allSkipped = false; + values.addProperty(entry.getKey(), entry.getValue()); + } + if (allSkipped) { + // Null = skip the chart + return null; + } + data.add("values", values); + return data; + } + } + + /** + * Represents a custom drilldown pie. + */ + public static class DrilldownPie extends CustomChart { + + private final Callable>> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public DrilldownPie(String chartId, Callable>> callable) { + super(chartId); + this.callable = callable; + } + + @Override + public JsonObject getChartData() throws Exception { + JsonObject data = new JsonObject(); + JsonObject values = new JsonObject(); + Map> map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean reallyAllSkipped = true; + for (Map.Entry> entryValues : map.entrySet()) { + JsonObject value = new JsonObject(); + boolean allSkipped = true; + for (Map.Entry valueEntry : map.get(entryValues.getKey()).entrySet()) { + value.addProperty(valueEntry.getKey(), valueEntry.getValue()); + allSkipped = false; + } + if (!allSkipped) { + reallyAllSkipped = false; + values.add(entryValues.getKey(), value); + } + } + if (reallyAllSkipped) { + // Null = skip the chart + return null; + } + data.add("values", values); + return data; + } + } + + /** + * Represents a custom single line chart. + */ + public static class SingleLineChart extends CustomChart { + + private final Callable callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public SingleLineChart(String chartId, Callable callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObject getChartData() throws Exception { + JsonObject data = new JsonObject(); + int value = callable.call(); + if (value == 0) { + // Null = skip the chart + return null; + } + data.addProperty("value", value); + return data; + } + + } + + /** + * Represents a custom multi line chart. + */ + public static class MultiLineChart extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public MultiLineChart(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObject getChartData() throws Exception { + JsonObject data = new JsonObject(); + JsonObject values = new JsonObject(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean allSkipped = true; + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue() == 0) { + continue; // Skip this invalid + } + allSkipped = false; + values.addProperty(entry.getKey(), entry.getValue()); + } + if (allSkipped) { + // Null = skip the chart + return null; + } + data.add("values", values); + return data; + } + + } + + /** + * Represents a custom simple bar chart. + */ + public static class SimpleBarChart extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public SimpleBarChart(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObject getChartData() throws Exception { + JsonObject data = new JsonObject(); + JsonObject values = new JsonObject(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + for (Map.Entry entry : map.entrySet()) { + JsonArray categoryValues = new JsonArray(); + categoryValues.add(new JsonPrimitive(entry.getValue())); + values.add(entry.getKey(), categoryValues); + } + data.add("values", values); + return data; + } + + } + + /** + * Represents a custom advanced bar chart. + */ + public static class AdvancedBarChart extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public AdvancedBarChart(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObject getChartData() throws Exception { + JsonObject data = new JsonObject(); + JsonObject values = new JsonObject(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean allSkipped = true; + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue().length == 0) { + continue; // Skip this invalid + } + allSkipped = false; + JsonArray categoryValues = new JsonArray(); + for (int categoryValue : entry.getValue()) { + categoryValues.add(new JsonPrimitive(categoryValue)); + } + values.add(entry.getKey(), categoryValues); + } + if (allSkipped) { + // Null = skip the chart + return null; + } + data.add("values", values); + return data; + } + } } diff --git a/src/main/java/com/btk5h/skriptmirror/Null.java b/src/main/java/com/btk5h/skriptmirror/Null.java index f0fd9679..236e9efe 100644 --- a/src/main/java/com/btk5h/skriptmirror/Null.java +++ b/src/main/java/com/btk5h/skriptmirror/Null.java @@ -1,13 +1,13 @@ package com.btk5h.skriptmirror; public class Null { - private static final Null instance = new Null(); + private static final Null instance = new Null(); - private Null() { - } + private Null() { + } - public static Null getInstance() { - return instance; - } + public static Null getInstance() { + return instance; + } } diff --git a/src/main/java/com/btk5h/skriptmirror/ObjectWrapper.java b/src/main/java/com/btk5h/skriptmirror/ObjectWrapper.java index a928b74d..e8ace818 100644 --- a/src/main/java/com/btk5h/skriptmirror/ObjectWrapper.java +++ b/src/main/java/com/btk5h/skriptmirror/ObjectWrapper.java @@ -7,69 +7,69 @@ public class ObjectWrapper { - protected Object object; - - private ObjectWrapper(Object object) { - this.object = object; - } - - public static ObjectWrapper create(Object object) { - if (object instanceof ObjectWrapper) { - return (ObjectWrapper) object; - } - - return new ObjectWrapper(object); - } - - public static Object wrapIfNecessary(Object returnedValue, boolean forceWrap) { - Class returnedClass = returnedValue.getClass(); - if (returnedClass.isArray()) { - returnedValue = create(JavaUtil.boxPrimitiveArray(returnedValue)); - } else if (forceWrap || Classes.getSuperClassInfo(returnedClass).getC() == Object.class) { - returnedValue = create(returnedValue); - } - return returnedValue; - } - - public static Object unwrapIfNecessary(Object o) { - if (o instanceof ObjectWrapper) { - return ((ObjectWrapper) o).get(); - } - - return o; - } - - public Object get() { - return object; - } - - public boolean isArray() { - if (object != null) { - return object.getClass().isArray(); - } - return false; - } - - @Override - public String toString() { - if (isArray()) { - return JavaUtil.arrayToString(object, Object::toString); - } - - return object.toString(); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - ObjectWrapper that = (ObjectWrapper) o; - return Objects.equals(object, that.object); - } - - @Override - public int hashCode() { - return Objects.hash(object); - } + protected Object object; + + private ObjectWrapper(Object object) { + this.object = object; + } + + public static ObjectWrapper create(Object object) { + if (object instanceof ObjectWrapper) { + return (ObjectWrapper) object; + } + + return new ObjectWrapper(object); + } + + public static Object wrapIfNecessary(Object returnedValue, boolean forceWrap) { + Class returnedClass = returnedValue.getClass(); + if (returnedClass.isArray()) { + returnedValue = create(JavaUtil.boxPrimitiveArray(returnedValue)); + } else if (forceWrap || Classes.getSuperClassInfo(returnedClass).getC() == Object.class) { + returnedValue = create(returnedValue); + } + return returnedValue; + } + + public static Object unwrapIfNecessary(Object o) { + if (o instanceof ObjectWrapper) { + return ((ObjectWrapper) o).get(); + } + + return o; + } + + public Object get() { + return object; + } + + public boolean isArray() { + if (object != null) { + return object.getClass().isArray(); + } + return false; + } + + @Override + public String toString() { + if (isArray()) { + return JavaUtil.arrayToString(object, Object::toString); + } + + return object.toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ObjectWrapper that = (ObjectWrapper) o; + return Objects.equals(object, that.object); + } + + @Override + public int hashCode() { + return Objects.hash(object); + } } diff --git a/src/main/java/com/btk5h/skriptmirror/ParseOrderWorkarounds.java b/src/main/java/com/btk5h/skriptmirror/ParseOrderWorkarounds.java index d9241538..0c7e7d44 100644 --- a/src/main/java/com/btk5h/skriptmirror/ParseOrderWorkarounds.java +++ b/src/main/java/com/btk5h/skriptmirror/ParseOrderWorkarounds.java @@ -21,40 +21,40 @@ * guarantee that another addon's syntax will be parsed before skript-reflect. */ public class ParseOrderWorkarounds { - private static final String[] PARSE_ORDER = { - EffExpressionStatement.class.getCanonicalName(), - CustomEffect.class.getCanonicalName(), - CustomCondition.class.getCanonicalName(), - CustomExpression.class.getCanonicalName(), - "com.w00tmast3r.skquery.elements.conditions.CondBoolean", - "com.pie.tlatoani.Miscellaneous.CondBoolean", - "us.tlatoani.tablisknu.core.base.CondBoolean", - "com.pie.tlatoani.CustomEvent.EvtCustomEvent", - EffReturn.class.getCanonicalName(), - ExprMatchedPattern.class.getCanonicalName(), - "ch.njol.skript.effects.EffContinue", - "com.ankoki.skjade.elements.conditions.CondBoolean" - }; + private static final String[] PARSE_ORDER = { + EffExpressionStatement.class.getCanonicalName(), + CustomEffect.class.getCanonicalName(), + CustomCondition.class.getCanonicalName(), + CustomExpression.class.getCanonicalName(), + "com.w00tmast3r.skquery.elements.conditions.CondBoolean", + "com.pie.tlatoani.Miscellaneous.CondBoolean", + "us.tlatoani.tablisknu.core.base.CondBoolean", + "com.pie.tlatoani.CustomEvent.EvtCustomEvent", + EffReturn.class.getCanonicalName(), + ExprMatchedPattern.class.getCanonicalName(), + "ch.njol.skript.effects.EffContinue", + "com.ankoki.skjade.elements.conditions.CondBoolean" + }; - public static void reorderSyntax() { - for (String c : PARSE_ORDER) { - ensureLast(Skript.getStatements(), o -> o.getElementClass().getName().equals(c)); - ensureLast(Skript.getConditions(), o -> o.getElementClass().getName().equals(c)); - ensureLast(Skript.getEffects(), o -> o.getElementClass().toString().equals(c)); - ensureLast(SkriptReflection.getExpressions(), o -> o.getElementClass().getName().equals(c)); - ensureLast(Skript.getEvents(), o -> o.getElementClass().getName().equals(c)); - } - } + public static void reorderSyntax() { + for (String c : PARSE_ORDER) { + ensureLast(Skript.getStatements(), o -> o.getElementClass().getName().equals(c)); + ensureLast(Skript.getConditions(), o -> o.getElementClass().getName().equals(c)); + ensureLast(Skript.getEffects(), o -> o.getElementClass().toString().equals(c)); + ensureLast(SkriptReflection.getExpressions(), o -> o.getElementClass().getName().equals(c)); + ensureLast(Skript.getEvents(), o -> o.getElementClass().getName().equals(c)); + } + } - private static void ensureLast(Collection elements, Checker checker) { - Optional optionalE = elements.stream() - .filter(checker::check) - .findFirst(); + private static void ensureLast(Collection elements, Checker checker) { + Optional optionalE = elements.stream() + .filter(checker::check) + .findFirst(); - optionalE.ifPresent(value -> { - elements.remove(value); - elements.add(value); - }); - } + optionalE.ifPresent(value -> { + elements.remove(value); + elements.add(value); + }); + } } diff --git a/src/main/java/com/btk5h/skriptmirror/SkriptMirror.java b/src/main/java/com/btk5h/skriptmirror/SkriptMirror.java index 4a2365c5..936830d1 100644 --- a/src/main/java/com/btk5h/skriptmirror/SkriptMirror.java +++ b/src/main/java/com/btk5h/skriptmirror/SkriptMirror.java @@ -25,108 +25,108 @@ public class SkriptMirror extends JavaPlugin { - private static SkriptMirror instance; - private static SkriptAddon addonInstance; - - public SkriptMirror() { - if (instance == null) { - instance = this; - } else { - throw new IllegalStateException(); - } - } - - @Override - public void onEnable() { - if (!Bukkit.getPluginManager().isPluginEnabled("Skript")) { - getLogger().severe("Disabling skript-reflect because Skript is disabled"); - Bukkit.getPluginManager().disablePlugin(this); - return; - } - - if (Skript.getVersion().isSmallerThan(new Version(2, 7))) { - getLogger().severe(""); - getLogger().severe("Your version of Skript (" + Skript.getVersion() + ") is not supported, at least Skript 2.7 is required to run this version of skript-reflect."); - getLogger().severe(""); - Bukkit.getPluginManager().disablePlugin(this); - return; - } - - if (Bukkit.getPluginManager().getPlugin("skript-mirror") != null) { - getLogger().warning("You shouldn't have both skript-mirror and skript-reflect enabled, it will probably cause issues"); - } - - try { - getAddonInstance() - .loadClasses("com.btk5h.skriptmirror.skript") - .loadClasses("org.skriptlang.reflect", "syntax", "java.elements"); - - Path dataFolder = SkriptMirror.getInstance().getDataFolder().toPath(); - LibraryLoader.loadLibraries(dataFolder); - } catch (IOException e) { - e.printStackTrace(); - } - - Comparators.registerComparator(ClassInfo.class, JavaType.class, (classInfo, javaType) -> { - ClassInfo matchingClassInfo = Classes.getExactClassInfo(javaType.getJavaClass()); - if (matchingClassInfo == null) - return Relation.NOT_EQUAL; - return Comparators.compare(classInfo, matchingClassInfo); - }); - - ParseOrderWorkarounds.reorderSyntax(); - - // Disable *all* and/or warnings - SkriptReflection.disableAndOrWarnings(); - - Metrics metrics = new Metrics(this, 10157); - - metrics.addCustomChart(new Metrics.DrilldownPie("skript_version", () -> { - Map> map = new HashMap<>(); - - Version version = Skript.getVersion(); - Map entry = new HashMap<>(); - entry.put(version.toString(), 1); - - map.put("" + version.getMajor() + "." + version.getMinor(), entry); - - return map; - })); - - metrics.addCustomChart(new Metrics.SingleLineChart("java_calls_made", () -> { - int i = ExprJavaCall.javaCallsMade; - ExprJavaCall.javaCallsMade = 0; - return i; - })); - - metrics.addCustomChart(new Metrics.SimplePie("custom_conditions_used", - () -> "" + StructCustomCondition.customConditionsUsed)); - metrics.addCustomChart(new Metrics.SimplePie("custom_effects_used", - () -> "" + StructCustomEffect.customEffectsUsed)); - metrics.addCustomChart(new Metrics.SimplePie("custom_events_used", - () -> "" + StructCustomEvent.customEventsUsed)); - metrics.addCustomChart(new Metrics.SimplePie("custom_expressions_used", - () -> "" + StructCustomExpression.customExpressionsUsed)); - - metrics.addCustomChart(new Metrics.SimplePie("proxies_used", - () -> "" + ExprProxy.proxiesUsed)); - metrics.addCustomChart(new Metrics.SimplePie("sections_used", - () -> "" + SecSection.sectionsUsed)); - - } - - public static SkriptAddon getAddonInstance() { - if (addonInstance == null) { - addonInstance = Skript.registerAddon(getInstance()).setLanguageFileDirectory("lang"); - } - return addonInstance; - } - - public static SkriptMirror getInstance() { - if (instance == null) { - throw new IllegalStateException(); - } - return instance; - } + private static SkriptMirror instance; + private static SkriptAddon addonInstance; + + public SkriptMirror() { + if (instance == null) { + instance = this; + } else { + throw new IllegalStateException(); + } + } + + @Override + public void onEnable() { + if (!Bukkit.getPluginManager().isPluginEnabled("Skript")) { + getLogger().severe("Disabling skript-reflect because Skript is disabled"); + Bukkit.getPluginManager().disablePlugin(this); + return; + } + + if (Skript.getVersion().isSmallerThan(new Version(2, 7))) { + getLogger().severe(""); + getLogger().severe("Your version of Skript (" + Skript.getVersion() + ") is not supported, at least Skript 2.7 is required to run this version of skript-reflect."); + getLogger().severe(""); + Bukkit.getPluginManager().disablePlugin(this); + return; + } + + if (Bukkit.getPluginManager().getPlugin("skript-mirror") != null) { + getLogger().warning("You shouldn't have both skript-mirror and skript-reflect enabled, it will probably cause issues"); + } + + try { + getAddonInstance() + .loadClasses("com.btk5h.skriptmirror.skript") + .loadClasses("org.skriptlang.reflect", "syntax", "java.elements"); + + Path dataFolder = SkriptMirror.getInstance().getDataFolder().toPath(); + LibraryLoader.loadLibraries(dataFolder); + } catch (IOException e) { + e.printStackTrace(); + } + + Comparators.registerComparator(ClassInfo.class, JavaType.class, (classInfo, javaType) -> { + ClassInfo matchingClassInfo = Classes.getExactClassInfo(javaType.getJavaClass()); + if (matchingClassInfo == null) + return Relation.NOT_EQUAL; + return Comparators.compare(classInfo, matchingClassInfo); + }); + + ParseOrderWorkarounds.reorderSyntax(); + + // Disable *all* and/or warnings + SkriptReflection.disableAndOrWarnings(); + + Metrics metrics = new Metrics(this, 10157); + + metrics.addCustomChart(new Metrics.DrilldownPie("skript_version", () -> { + Map> map = new HashMap<>(); + + Version version = Skript.getVersion(); + Map entry = new HashMap<>(); + entry.put(version.toString(), 1); + + map.put("" + version.getMajor() + "." + version.getMinor(), entry); + + return map; + })); + + metrics.addCustomChart(new Metrics.SingleLineChart("java_calls_made", () -> { + int i = ExprJavaCall.javaCallsMade; + ExprJavaCall.javaCallsMade = 0; + return i; + })); + + metrics.addCustomChart(new Metrics.SimplePie("custom_conditions_used", + () -> "" + StructCustomCondition.customConditionsUsed)); + metrics.addCustomChart(new Metrics.SimplePie("custom_effects_used", + () -> "" + StructCustomEffect.customEffectsUsed)); + metrics.addCustomChart(new Metrics.SimplePie("custom_events_used", + () -> "" + StructCustomEvent.customEventsUsed)); + metrics.addCustomChart(new Metrics.SimplePie("custom_expressions_used", + () -> "" + StructCustomExpression.customExpressionsUsed)); + + metrics.addCustomChart(new Metrics.SimplePie("proxies_used", + () -> "" + ExprProxy.proxiesUsed)); + metrics.addCustomChart(new Metrics.SimplePie("sections_used", + () -> "" + SecSection.sectionsUsed)); + + } + + public static SkriptAddon getAddonInstance() { + if (addonInstance == null) { + addonInstance = Skript.registerAddon(getInstance()).setLanguageFileDirectory("lang"); + } + return addonInstance; + } + + public static SkriptMirror getInstance() { + if (instance == null) { + throw new IllegalStateException(); + } + return instance; + } } diff --git a/src/main/java/com/btk5h/skriptmirror/WrappedEvent.java b/src/main/java/com/btk5h/skriptmirror/WrappedEvent.java index 07ba2749..68b21d1e 100644 --- a/src/main/java/com/btk5h/skriptmirror/WrappedEvent.java +++ b/src/main/java/com/btk5h/skriptmirror/WrappedEvent.java @@ -3,26 +3,26 @@ import org.bukkit.event.Event; public abstract class WrappedEvent extends Event { - private final Event event; + private final Event event; - protected WrappedEvent(Event event) { - this.event = event; - } + protected WrappedEvent(Event event) { + this.event = event; + } - protected WrappedEvent(Event event, boolean isAsynchronous) { - super(isAsynchronous); - this.event = event; - } + protected WrappedEvent(Event event, boolean isAsynchronous) { + super(isAsynchronous); + this.event = event; + } - public Event getEvent() { - if (event instanceof WrappedEvent) { - return ((WrappedEvent) event).getEvent(); - } - return event; - } + public Event getEvent() { + if (event instanceof WrappedEvent) { + return ((WrappedEvent) event).getEvent(); + } + return event; + } - public Event getDirectEvent() { - return event; - } + public Event getDirectEvent() { + return event; + } } diff --git a/src/main/java/com/btk5h/skriptmirror/skript/CondExpressionStatement.java b/src/main/java/com/btk5h/skriptmirror/skript/CondExpressionStatement.java index b9706ca4..3460808c 100644 --- a/src/main/java/com/btk5h/skriptmirror/skript/CondExpressionStatement.java +++ b/src/main/java/com/btk5h/skriptmirror/skript/CondExpressionStatement.java @@ -23,73 +23,73 @@ public class CondExpressionStatement extends Condition { - static { - Skript.registerCondition(CondExpressionStatement.class, "[(1¦await)] %~javaobject%"); - } - - private static final ExecutorService threadPool = Executors.newCachedThreadPool(); - - private Expression arg; - private boolean isAsynchronous; - private boolean isCondition; - - @Override - public boolean check(Event e) { - Object result = ObjectWrapper.unwrapIfNecessary(arg.getSingle(e)); - return !isCondition || isTruthy(result); - } - - private boolean isTruthy(Object o) { - return o != Boolean.FALSE - && o != null - && (!(o instanceof Number) || !(((Number) o).doubleValue() == 0 || Double.isNaN(((Number) o).doubleValue()))); - } - - @Override - protected TriggerItem walk(Event e) { - if (isAsynchronous) { - Delay.addDelayedEvent(e); - - Object localVariables = SkriptReflection.getLocals(e); - CompletableFuture.runAsync(() -> { - SkriptReflection.putLocals(localVariables, e); - check(e); - }, threadPool) - .thenAccept(res -> Bukkit.getScheduler().runTask(SkriptMirror.getInstance(), () -> { - if (getNext() != null) - TriggerItem.walk(getNext(), e); - - SkriptReflection.removeLocals(e); - })); - return null; - } - return super.walk(e); - } - - @Override - public String toString(Event e, boolean debug) { - return arg.toString(e, debug); - } - - @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, - SkriptParser.ParseResult parseResult) { - arg = SkriptUtil.defendExpression(exprs[0]); - - if (!(arg instanceof ExprJavaCall)) - return false; - - isAsynchronous = (parseResult.mark & 1) == 1; - isCondition = SkriptLogger.getNode() instanceof SectionNode; - - if (isCondition && isAsynchronous) { - Skript.error("Asynchronous java calls may not be used as conditions."); - return false; - } - - if (isAsynchronous) - getParser().setHasDelayBefore(Kleenean.TRUE); - - return SkriptUtil.canInitSafely(arg); - } + static { + Skript.registerCondition(CondExpressionStatement.class, "[(1¦await)] %~javaobject%"); + } + + private static final ExecutorService threadPool = Executors.newCachedThreadPool(); + + private Expression arg; + private boolean isAsynchronous; + private boolean isCondition; + + @Override + public boolean check(Event e) { + Object result = ObjectWrapper.unwrapIfNecessary(arg.getSingle(e)); + return !isCondition || isTruthy(result); + } + + private boolean isTruthy(Object o) { + return o != Boolean.FALSE + && o != null + && (!(o instanceof Number) || !(((Number) o).doubleValue() == 0 || Double.isNaN(((Number) o).doubleValue()))); + } + + @Override + protected TriggerItem walk(Event e) { + if (isAsynchronous) { + Delay.addDelayedEvent(e); + + Object localVariables = SkriptReflection.getLocals(e); + CompletableFuture.runAsync(() -> { + SkriptReflection.putLocals(localVariables, e); + check(e); + }, threadPool) + .thenAccept(res -> Bukkit.getScheduler().runTask(SkriptMirror.getInstance(), () -> { + if (getNext() != null) + TriggerItem.walk(getNext(), e); + + SkriptReflection.removeLocals(e); + })); + return null; + } + return super.walk(e); + } + + @Override + public String toString(Event e, boolean debug) { + return arg.toString(e, debug); + } + + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, + SkriptParser.ParseResult parseResult) { + arg = SkriptUtil.defendExpression(exprs[0]); + + if (!(arg instanceof ExprJavaCall)) + return false; + + isAsynchronous = (parseResult.mark & 1) == 1; + isCondition = SkriptLogger.getNode() instanceof SectionNode; + + if (isCondition && isAsynchronous) { + Skript.error("Asynchronous java calls may not be used as conditions."); + return false; + } + + if (isAsynchronous) + getParser().setHasDelayBefore(Kleenean.TRUE); + + return SkriptUtil.canInitSafely(arg); + } } diff --git a/src/main/java/com/btk5h/skriptmirror/skript/CondIsInstanceOf.java b/src/main/java/com/btk5h/skriptmirror/skript/CondIsInstanceOf.java index 1507e7fa..ca3babb6 100644 --- a/src/main/java/com/btk5h/skriptmirror/skript/CondIsInstanceOf.java +++ b/src/main/java/com/btk5h/skriptmirror/skript/CondIsInstanceOf.java @@ -11,36 +11,36 @@ import org.bukkit.event.Event; public class CondIsInstanceOf extends Condition { - static { - Skript.registerCondition(CondIsInstanceOf.class, - "%objects% (is|are) [a[n]] instance[s] of %javatypes%", - "%objects% (is not|isn't|are not|aren't) [a[n]] instance[s] of %javatypes%"); - } + static { + Skript.registerCondition(CondIsInstanceOf.class, + "%objects% (is|are) [a[n]] instance[s] of %javatypes%", + "%objects% (is not|isn't|are not|aren't) [a[n]] instance[s] of %javatypes%"); + } - private Expression objects; - private Expression type; + private Expression objects; + private Expression type; - @Override - public boolean check(Event e) { - return objects.check(e, o -> - type.check(e, t -> - t.getJavaClass().isAssignableFrom(SkriptMirrorUtil.getClass(o)), - isNegated() - ) - ); - } + @Override + public boolean check(Event e) { + return objects.check(e, o -> + type.check(e, t -> + t.getJavaClass().isAssignableFrom(SkriptMirrorUtil.getClass(o)), + isNegated() + ) + ); + } - @Override - public String toString(Event e, boolean debug) { - return String.format("%s instanceof %s", objects.toString(e, debug), type.toString(e, debug)); - } + @Override + public String toString(Event e, boolean debug) { + return String.format("%s instanceof %s", objects.toString(e, debug), type.toString(e, debug)); + } - @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, - SkriptParser.ParseResult parseResult) { - objects = SkriptUtil.defendExpression(exprs[0]); - type = SkriptUtil.defendExpression(exprs[1]); - setNegated(matchedPattern == 1); - return true; - } + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, + SkriptParser.ParseResult parseResult) { + objects = SkriptUtil.defendExpression(exprs[0]); + type = SkriptUtil.defendExpression(exprs[1]); + setNegated(matchedPattern == 1); + return true; + } } diff --git a/src/main/java/com/btk5h/skriptmirror/skript/EffExpressionStatement.java b/src/main/java/com/btk5h/skriptmirror/skript/EffExpressionStatement.java index ecf53399..1b76ea5a 100644 --- a/src/main/java/com/btk5h/skriptmirror/skript/EffExpressionStatement.java +++ b/src/main/java/com/btk5h/skriptmirror/skript/EffExpressionStatement.java @@ -19,59 +19,59 @@ import java.util.concurrent.Executors; public class EffExpressionStatement extends Effect { - static { - Skript.registerEffect(EffExpressionStatement.class, "[(1¦await)] %~javaobject%"); - } + static { + Skript.registerEffect(EffExpressionStatement.class, "[(1¦await)] %~javaobject%"); + } - private static final ExecutorService threadPool = - Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); + private static final ExecutorService threadPool = + Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); - private Expression arg; - private boolean isAsynchronous; + private Expression arg; + private boolean isAsynchronous; - @Override - protected void execute(Event e) { - arg.getAll(e); - } + @Override + protected void execute(Event e) { + arg.getAll(e); + } - @Override - protected TriggerItem walk(Event e) { - if (isAsynchronous) { - Delay.addDelayedEvent(e); + @Override + protected TriggerItem walk(Event e) { + if (isAsynchronous) { + Delay.addDelayedEvent(e); - Object localVariables = SkriptReflection.getLocals(e); - CompletableFuture.runAsync(() -> { - SkriptReflection.putLocals(localVariables, e); - execute(e); - }, threadPool) - .thenAccept(res -> Bukkit.getScheduler().runTask(SkriptMirror.getInstance(), () -> { - if (getNext() != null) - TriggerItem.walk(getNext(), e); + Object localVariables = SkriptReflection.getLocals(e); + CompletableFuture.runAsync(() -> { + SkriptReflection.putLocals(localVariables, e); + execute(e); + }, threadPool) + .thenAccept(res -> Bukkit.getScheduler().runTask(SkriptMirror.getInstance(), () -> { + if (getNext() != null) + TriggerItem.walk(getNext(), e); - SkriptReflection.removeLocals(e); - })); - return null; - } - return super.walk(e); - } + SkriptReflection.removeLocals(e); + })); + return null; + } + return super.walk(e); + } - @Override - public String toString(Event e, boolean debug) { - return arg.toString(e, debug); - } + @Override + public String toString(Event e, boolean debug) { + return arg.toString(e, debug); + } - @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, - SkriptParser.ParseResult parseResult) { - arg = SkriptUtil.defendExpression(exprs[0]); + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, + SkriptParser.ParseResult parseResult) { + arg = SkriptUtil.defendExpression(exprs[0]); - if (!(arg instanceof ExprJavaCall)) { - return false; - } + if (!(arg instanceof ExprJavaCall)) { + return false; + } - isAsynchronous = (parseResult.mark & 1) == 1; - if (isAsynchronous) - getParser().setHasDelayBefore(Kleenean.TRUE); - return SkriptUtil.canInitSafely(arg); - } + isAsynchronous = (parseResult.mark & 1) == 1; + if (isAsynchronous) + getParser().setHasDelayBefore(Kleenean.TRUE); + return SkriptUtil.canInitSafely(arg); + } } diff --git a/src/main/java/com/btk5h/skriptmirror/skript/ExprArrayAccess.java b/src/main/java/com/btk5h/skriptmirror/skript/ExprArrayAccess.java index c859c5b7..14a7f844 100644 --- a/src/main/java/com/btk5h/skriptmirror/skript/ExprArrayAccess.java +++ b/src/main/java/com/btk5h/skriptmirror/skript/ExprArrayAccess.java @@ -20,198 +20,198 @@ public class ExprArrayAccess implements Expression { - static { - //noinspection unchecked - Skript.registerExpression(ExprArrayAccess.class, Object.class, ExpressionType.COMBINED, - "%javaobject%\\[%number%\\]"); - } - - private Expression arrays; - private Expression index; - - private final ExprArrayAccess source; - private final Class[] types; - private final Class superType; - - @SuppressWarnings("unchecked") - public ExprArrayAccess() { - this(null, (Class) Object.class); - } - - @SuppressWarnings("unchecked") - @SafeVarargs - private ExprArrayAccess(ExprArrayAccess source, Class... types) { - this.source = source; - - if (source != null) { - this.arrays = source.arrays; - this.index = source.index; - } - - this.types = types; - this.superType = (Class) Utils.getSuperType(types); - } - - @SuppressWarnings("unchecked") - @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, - SkriptParser.ParseResult parseResult) { - arrays = (Expression) exprs[0]; - index = (Expression) exprs[1]; - return true; - } - - @Override - public T getSingle(Event e) { - ObjectWrapper wrapper = arrays.getSingle(e); - Number number = index.getSingle(e); - - if (wrapper == null || number == null || !wrapper.isArray()) { - return null; - } - - Object array = wrapper.get(); - int length = Array.getLength(array); - - int i = number.intValue(); - if (i < 0 || i >= length) { - return null; - } - - return Converters.convert(Array.get(array, i), types); - } - - @Override - public T[] getArray(Event e) { - T single = getSingle(e); - - if (single == null) { - return JavaUtil.newArray(superType, 0); - } - - T[] all = JavaUtil.newArray(superType, 1); - all[0] = single; - - return all; - } - - @Override - public T[] getAll(Event e) { - return getArray(e); - } - - @Override - public boolean isSingle() { - return true; - } - - @Override - public boolean check(Event e, Checker c, boolean negated) { - return SimpleExpression.check(getAll(e), c, negated, getAnd()); - } - - @Override - public boolean check(Event e, Checker c) { - return SimpleExpression.check(getAll(e), c, false, getAnd()); - } - - @Override - public Expression getConvertedExpression(Class[] to) { - return new ExprArrayAccess<>(this, to); - } - - @Override - public Class getReturnType() { - return superType; - } - - @Override - public boolean getAnd() { - return true; - } - - @Override - public boolean setTime(int time) { - return false; - } - - @Override - public int getTime() { - return 0; - } - - @Override - public boolean isDefault() { - return false; - } - - @Override - public Iterator iterator(Event e) { - return new ArrayIterator<>(getAll(e)); - } - - @Override - public boolean isLoopOf(String s) { - return false; - } - - @Override - public Expression getSource() { - return source == null ? this : source; - } - - @Override - public Expression simplify() { - return this; - } - - @Override - public Class[] acceptChange(Changer.ChangeMode mode) { - if (mode == Changer.ChangeMode.SET || mode == Changer.ChangeMode.DELETE) { - return new Class[]{Object.class}; - } - return null; - } - - @Override - public void change(Event e, Object[] delta, Changer.ChangeMode mode) { - ObjectWrapper wrapper = arrays.getSingle(e); - Number number = index.getSingle(e); - - if (wrapper == null || number == null || !wrapper.isArray()) { - return; - } - - Object array = wrapper.get(); - int length = Array.getLength(array); - - int i = number.intValue(); - if (i < 0 || i >= length) { - return; - } - - switch (mode) { - case SET: - Class to = array.getClass().getComponentType(); - if (JavaUtil.canConvert(delta[0], to)) { - Object converted = JavaUtil.convert(delta[0], to); - Array.set(array, i, converted); - } - break; - case DELETE: - Array.set(array, i, null); - break; - } - } - - @Override - public String toString(Event e, boolean debug) { - return arrays.toString(e, debug) + "[" + index.toString(e, debug) + "]"; - } - - @Override - public String toString() { - return toString(null, false); - } + static { + //noinspection unchecked + Skript.registerExpression(ExprArrayAccess.class, Object.class, ExpressionType.COMBINED, + "%javaobject%\\[%number%\\]"); + } + + private Expression arrays; + private Expression index; + + private final ExprArrayAccess source; + private final Class[] types; + private final Class superType; + + @SuppressWarnings("unchecked") + public ExprArrayAccess() { + this(null, (Class) Object.class); + } + + @SuppressWarnings("unchecked") + @SafeVarargs + private ExprArrayAccess(ExprArrayAccess source, Class... types) { + this.source = source; + + if (source != null) { + this.arrays = source.arrays; + this.index = source.index; + } + + this.types = types; + this.superType = (Class) Utils.getSuperType(types); + } + + @SuppressWarnings("unchecked") + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, + SkriptParser.ParseResult parseResult) { + arrays = (Expression) exprs[0]; + index = (Expression) exprs[1]; + return true; + } + + @Override + public T getSingle(Event e) { + ObjectWrapper wrapper = arrays.getSingle(e); + Number number = index.getSingle(e); + + if (wrapper == null || number == null || !wrapper.isArray()) { + return null; + } + + Object array = wrapper.get(); + int length = Array.getLength(array); + + int i = number.intValue(); + if (i < 0 || i >= length) { + return null; + } + + return Converters.convert(Array.get(array, i), types); + } + + @Override + public T[] getArray(Event e) { + T single = getSingle(e); + + if (single == null) { + return JavaUtil.newArray(superType, 0); + } + + T[] all = JavaUtil.newArray(superType, 1); + all[0] = single; + + return all; + } + + @Override + public T[] getAll(Event e) { + return getArray(e); + } + + @Override + public boolean isSingle() { + return true; + } + + @Override + public boolean check(Event e, Checker c, boolean negated) { + return SimpleExpression.check(getAll(e), c, negated, getAnd()); + } + + @Override + public boolean check(Event e, Checker c) { + return SimpleExpression.check(getAll(e), c, false, getAnd()); + } + + @Override + public Expression getConvertedExpression(Class[] to) { + return new ExprArrayAccess<>(this, to); + } + + @Override + public Class getReturnType() { + return superType; + } + + @Override + public boolean getAnd() { + return true; + } + + @Override + public boolean setTime(int time) { + return false; + } + + @Override + public int getTime() { + return 0; + } + + @Override + public boolean isDefault() { + return false; + } + + @Override + public Iterator iterator(Event e) { + return new ArrayIterator<>(getAll(e)); + } + + @Override + public boolean isLoopOf(String s) { + return false; + } + + @Override + public Expression getSource() { + return source == null ? this : source; + } + + @Override + public Expression simplify() { + return this; + } + + @Override + public Class[] acceptChange(Changer.ChangeMode mode) { + if (mode == Changer.ChangeMode.SET || mode == Changer.ChangeMode.DELETE) { + return new Class[]{Object.class}; + } + return null; + } + + @Override + public void change(Event e, Object[] delta, Changer.ChangeMode mode) { + ObjectWrapper wrapper = arrays.getSingle(e); + Number number = index.getSingle(e); + + if (wrapper == null || number == null || !wrapper.isArray()) { + return; + } + + Object array = wrapper.get(); + int length = Array.getLength(array); + + int i = number.intValue(); + if (i < 0 || i >= length) { + return; + } + + switch (mode) { + case SET: + Class to = array.getClass().getComponentType(); + if (JavaUtil.canConvert(delta[0], to)) { + Object converted = JavaUtil.convert(delta[0], to); + Array.set(array, i, converted); + } + break; + case DELETE: + Array.set(array, i, null); + break; + } + } + + @Override + public String toString(Event e, boolean debug) { + return arrays.toString(e, debug) + "[" + index.toString(e, debug) + "]"; + } + + @Override + public String toString() { + return toString(null, false); + } } diff --git a/src/main/java/com/btk5h/skriptmirror/skript/ExprBits.java b/src/main/java/com/btk5h/skriptmirror/skript/ExprBits.java index e8f1bd67..949b3fa7 100644 --- a/src/main/java/com/btk5h/skriptmirror/skript/ExprBits.java +++ b/src/main/java/com/btk5h/skriptmirror/skript/ExprBits.java @@ -11,127 +11,127 @@ import java.util.Arrays; public class ExprBits extends SimpleExpression { - static { - // parse mark also indicates the offset of the first argument - PropertyExpression.register(ExprBits.class, Number.class, - "(0¦bit %-number%|1¦bit(s| range) [from] %-number%( to |[ ]-[ ])%-number%)", "numbers"); - } - - private Expression numbers; - private Expression from; - private Expression to; - - @Override - protected Number[] get(Event e) { - Number f = from.getSingle(e); - Number t = to.getSingle(e); - - if (f == null || t == null) { - return null; - } - - long mask = getRangeMaskIndexed(f.intValue(), t.intValue()); - - return Arrays.stream(numbers.getArray(e)) - .map(l -> (l.longValue() & mask) >>> f.intValue()) - .toArray(Number[]::new); - } - - private static long getRangeMaskOrdinal(int from) { - if (from <= 0 || from >= Long.SIZE) { - return 0; - } - - return (1L << from) - 1; - } - - private static long getRangeMaskOrdinal(int from, int to) { - if (from > to) { - return 0; - } - - return getRangeMaskOrdinal(to) - getRangeMaskOrdinal(from - 1); - } - - private static long getRangeMaskIndexed(int from, int to) { - return getRangeMaskOrdinal(from + 1, to + 1); - } - - @Override - public boolean isSingle() { - return numbers.isSingle(); - } - - @Override - public String toString(Event e, boolean debug) { - return String.format("the bits %s to %s of %s", - from.toString(e, debug), to.toString(e, debug), numbers.toString(e, debug)); - } - - @Override - public Class getReturnType() { - return Number.class; - } - - @Override - public Class[] acceptChange(Changer.ChangeMode mode) { - if (isSingle() && (mode == Changer.ChangeMode.SET || mode == Changer.ChangeMode.DELETE) - && Changer.ChangerUtils.acceptsChange(numbers, Changer.ChangeMode.SET, Number.class)) { - return new Class[]{Number.class, Boolean.class}; - } - return null; - } - - @Override - public void change(Event e, Object[] delta, Changer.ChangeMode mode) { - Number num = numbers.getSingle(e); - Number f = from.getSingle(e); - Number t = to.getSingle(e); - - if (num == null || f == null || t == null) { - return; - } - - long mask = getRangeMaskIndexed(f.intValue(), t.intValue()); - - long number = num.longValue(); - - switch (mode) { - case SET: - if (delta[0] instanceof Number) { - number &= ~mask; - mask &= (((Number) delta[0]).longValue()) << f.intValue(); - } else if (delta[0] instanceof Boolean) { - if (!((Boolean) delta[0])) { - mask = ~mask; - } - } else { - throw new IllegalStateException(); - } - - number |= mask; - break; - case DELETE: - number &= ~mask; - break; - default: - throw new IllegalStateException(); - } - - numbers.change(e, new Object[]{number}, Changer.ChangeMode.SET); - } - - @SuppressWarnings("unchecked") - @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, - SkriptParser.ParseResult parseResult) { - numbers = (Expression) exprs[matchedPattern == 1 ? 0 : 3]; - - - // it just so happens that we can use matchedPattern to determine the offset of the arguments - from = (Expression) exprs[parseResult.mark + matchedPattern]; - to = parseResult.mark == 0 ? from : (Expression) exprs[2 + matchedPattern]; - - return true; - } + static { + // parse mark also indicates the offset of the first argument + PropertyExpression.register(ExprBits.class, Number.class, + "(0¦bit %-number%|1¦bit(s| range) [from] %-number%( to |[ ]-[ ])%-number%)", "numbers"); + } + + private Expression numbers; + private Expression from; + private Expression to; + + @Override + protected Number[] get(Event e) { + Number f = from.getSingle(e); + Number t = to.getSingle(e); + + if (f == null || t == null) { + return null; + } + + long mask = getRangeMaskIndexed(f.intValue(), t.intValue()); + + return Arrays.stream(numbers.getArray(e)) + .map(l -> (l.longValue() & mask) >>> f.intValue()) + .toArray(Number[]::new); + } + + private static long getRangeMaskOrdinal(int from) { + if (from <= 0 || from >= Long.SIZE) { + return 0; + } + + return (1L << from) - 1; + } + + private static long getRangeMaskOrdinal(int from, int to) { + if (from > to) { + return 0; + } + + return getRangeMaskOrdinal(to) - getRangeMaskOrdinal(from - 1); + } + + private static long getRangeMaskIndexed(int from, int to) { + return getRangeMaskOrdinal(from + 1, to + 1); + } + + @Override + public boolean isSingle() { + return numbers.isSingle(); + } + + @Override + public String toString(Event e, boolean debug) { + return String.format("the bits %s to %s of %s", + from.toString(e, debug), to.toString(e, debug), numbers.toString(e, debug)); + } + + @Override + public Class getReturnType() { + return Number.class; + } + + @Override + public Class[] acceptChange(Changer.ChangeMode mode) { + if (isSingle() && (mode == Changer.ChangeMode.SET || mode == Changer.ChangeMode.DELETE) + && Changer.ChangerUtils.acceptsChange(numbers, Changer.ChangeMode.SET, Number.class)) { + return new Class[]{Number.class, Boolean.class}; + } + return null; + } + + @Override + public void change(Event e, Object[] delta, Changer.ChangeMode mode) { + Number num = numbers.getSingle(e); + Number f = from.getSingle(e); + Number t = to.getSingle(e); + + if (num == null || f == null || t == null) { + return; + } + + long mask = getRangeMaskIndexed(f.intValue(), t.intValue()); + + long number = num.longValue(); + + switch (mode) { + case SET: + if (delta[0] instanceof Number) { + number &= ~mask; + mask &= (((Number) delta[0]).longValue()) << f.intValue(); + } else if (delta[0] instanceof Boolean) { + if (!((Boolean) delta[0])) { + mask = ~mask; + } + } else { + throw new IllegalStateException(); + } + + number |= mask; + break; + case DELETE: + number &= ~mask; + break; + default: + throw new IllegalStateException(); + } + + numbers.change(e, new Object[]{number}, Changer.ChangeMode.SET); + } + + @SuppressWarnings("unchecked") + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, + SkriptParser.ParseResult parseResult) { + numbers = (Expression) exprs[matchedPattern == 1 ? 0 : 3]; + + + // it just so happens that we can use matchedPattern to determine the offset of the arguments + from = (Expression) exprs[parseResult.mark + matchedPattern]; + to = parseResult.mark == 0 ? from : (Expression) exprs[2 + matchedPattern]; + + return true; + } } diff --git a/src/main/java/com/btk5h/skriptmirror/skript/ExprCollect.java b/src/main/java/com/btk5h/skriptmirror/skript/ExprCollect.java index 0b5f29c8..ff4544aa 100644 --- a/src/main/java/com/btk5h/skriptmirror/skript/ExprCollect.java +++ b/src/main/java/com/btk5h/skriptmirror/skript/ExprCollect.java @@ -19,79 +19,79 @@ import java.util.stream.Stream; public class ExprCollect extends SimpleExpression { - static { - Skript.registerExpression(ExprCollect.class, ObjectWrapper.class, ExpressionType.COMBINED, - "\\[%objects%[ as %-javatype%[ ]]\\]"); - } - - private Expression objects; - private Expression type; - - @Override - protected ObjectWrapper[] get(Event e) { - Stream objectStream = Arrays.stream(objects.getArray(e)) - .map(o -> o instanceof Null ? null : o) - .map(ObjectWrapper::unwrapIfNecessary); - - if (type != null) { - JavaType componentType = type.getSingle(e); - if (componentType != null) { - objectStream = objectStream.filter(o -> o == null || componentType.getJavaClass().isInstance(o)); - } - } - - Object[] items = objectStream.toArray(); - Object[] castedItems = JavaUtil.newArray(getCommonSuperclass(items), items.length); - - System.arraycopy(items, 0, castedItems, 0, items.length); - - return new ObjectWrapper[]{ObjectWrapper.create(castedItems)}; - } - - private static Class getCommonSuperclass(Object[] objects) { - Optional firstNonnull = Arrays.stream(objects) - .filter(Objects::nonNull) - .findFirst(); - - if (firstNonnull.isPresent()) { - return Arrays.stream(objects) - .filter(Objects::nonNull) - .map(Object::getClass) - .map(o -> (Class) o) - .reduce(firstNonnull.get().getClass(), ExprCollect::getCommonSuperclass); - } - - return Object.class; - } - - private static Class getCommonSuperclass(Class c1, Class c2) { - while (!c1.isAssignableFrom(c2)) { - c1 = c1.getSuperclass(); - } - return c1; - } - - @Override - public boolean isSingle() { - return true; - } - - @Override - public Class getReturnType() { - return ObjectWrapper.class; - } - - @Override - public String toString(Event e, boolean debug) { - return "array of " + objects.toString(e, debug); - } - - @SuppressWarnings("unchecked") - @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, - SkriptParser.ParseResult parseResult) { - objects = SkriptUtil.defendExpression(exprs[0]); - type = (Expression) exprs[1]; - return SkriptUtil.canInitSafely(objects); - } + static { + Skript.registerExpression(ExprCollect.class, ObjectWrapper.class, ExpressionType.COMBINED, + "\\[%objects%[ as %-javatype%[ ]]\\]"); + } + + private Expression objects; + private Expression type; + + @Override + protected ObjectWrapper[] get(Event e) { + Stream objectStream = Arrays.stream(objects.getArray(e)) + .map(o -> o instanceof Null ? null : o) + .map(ObjectWrapper::unwrapIfNecessary); + + if (type != null) { + JavaType componentType = type.getSingle(e); + if (componentType != null) { + objectStream = objectStream.filter(o -> o == null || componentType.getJavaClass().isInstance(o)); + } + } + + Object[] items = objectStream.toArray(); + Object[] castedItems = JavaUtil.newArray(getCommonSuperclass(items), items.length); + + System.arraycopy(items, 0, castedItems, 0, items.length); + + return new ObjectWrapper[]{ObjectWrapper.create(castedItems)}; + } + + private static Class getCommonSuperclass(Object[] objects) { + Optional firstNonnull = Arrays.stream(objects) + .filter(Objects::nonNull) + .findFirst(); + + if (firstNonnull.isPresent()) { + return Arrays.stream(objects) + .filter(Objects::nonNull) + .map(Object::getClass) + .map(o -> (Class) o) + .reduce(firstNonnull.get().getClass(), ExprCollect::getCommonSuperclass); + } + + return Object.class; + } + + private static Class getCommonSuperclass(Class c1, Class c2) { + while (!c1.isAssignableFrom(c2)) { + c1 = c1.getSuperclass(); + } + return c1; + } + + @Override + public boolean isSingle() { + return true; + } + + @Override + public Class getReturnType() { + return ObjectWrapper.class; + } + + @Override + public String toString(Event e, boolean debug) { + return "array of " + objects.toString(e, debug); + } + + @SuppressWarnings("unchecked") + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, + SkriptParser.ParseResult parseResult) { + objects = SkriptUtil.defendExpression(exprs[0]); + type = (Expression) exprs[1]; + return SkriptUtil.canInitSafely(objects); + } } diff --git a/src/main/java/com/btk5h/skriptmirror/skript/ExprFunction.java b/src/main/java/com/btk5h/skriptmirror/skript/ExprFunction.java index 4f5cba94..432cae41 100644 --- a/src/main/java/com/btk5h/skriptmirror/skript/ExprFunction.java +++ b/src/main/java/com/btk5h/skriptmirror/skript/ExprFunction.java @@ -13,48 +13,48 @@ import java.util.Arrays; public class ExprFunction extends SimpleExpression { - static { - Skript.registerExpression(ExprFunction.class, FunctionWrapper.class, ExpressionType.PROPERTY, - "[the] function(s| [reference[s]]) %strings% [called with [[the] [arg[ument][s]]] %-objects%]"); - } - - private Expression refs; - private Expression args; - - @Override - protected FunctionWrapper[] get(Event e) { - Object[] functionArgs = args == null ? new Object[0] : args.getArray(e); - - return Arrays.stream(refs.getArray(e)) - .map(ref -> new FunctionWrapper(ref, functionArgs)) - .toArray(FunctionWrapper[]::new); - } - - @Override - public boolean isSingle() { - return refs.isSingle(); - } - - @Override - public Class getReturnType() { - return FunctionWrapper.class; - } - - @Override - public String toString(Event e, boolean debug) { - return "function reference of " + refs.toString(e, debug); - } - - @SuppressWarnings("unchecked") - @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, - SkriptParser.ParseResult parseResult) { - refs = SkriptUtil.defendExpression(exprs[0]); - - if (exprs[1] != null) { - args = SkriptUtil.defendExpression(exprs[1]); - } - - return SkriptUtil.canInitSafely(args); - } + static { + Skript.registerExpression(ExprFunction.class, FunctionWrapper.class, ExpressionType.PROPERTY, + "[the] function(s| [reference[s]]) %strings% [called with [[the] [arg[ument][s]]] %-objects%]"); + } + + private Expression refs; + private Expression args; + + @Override + protected FunctionWrapper[] get(Event e) { + Object[] functionArgs = args == null ? new Object[0] : args.getArray(e); + + return Arrays.stream(refs.getArray(e)) + .map(ref -> new FunctionWrapper(ref, functionArgs)) + .toArray(FunctionWrapper[]::new); + } + + @Override + public boolean isSingle() { + return refs.isSingle(); + } + + @Override + public Class getReturnType() { + return FunctionWrapper.class; + } + + @Override + public String toString(Event e, boolean debug) { + return "function reference of " + refs.toString(e, debug); + } + + @SuppressWarnings("unchecked") + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, + SkriptParser.ParseResult parseResult) { + refs = SkriptUtil.defendExpression(exprs[0]); + + if (exprs[1] != null) { + args = SkriptUtil.defendExpression(exprs[1]); + } + + return SkriptUtil.canInitSafely(args); + } } diff --git a/src/main/java/com/btk5h/skriptmirror/skript/ExprPlugin.java b/src/main/java/com/btk5h/skriptmirror/skript/ExprPlugin.java index 107d4ede..f09128e6 100644 --- a/src/main/java/com/btk5h/skriptmirror/skript/ExprPlugin.java +++ b/src/main/java/com/btk5h/skriptmirror/skript/ExprPlugin.java @@ -16,59 +16,59 @@ public class ExprPlugin extends SimplePropertyExpression { - static { - Skript.registerExpression(ExprPlugin.class, ObjectWrapper.class, ExpressionType.PROPERTY, "[(an|the)] instance of [the] plugin %javatype/string%"); - } + static { + Skript.registerExpression(ExprPlugin.class, ObjectWrapper.class, ExpressionType.PROPERTY, "[(an|the)] instance of [the] plugin %javatype/string%"); + } - @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) { - super.init(exprs, matchedPattern, isDelayed, parseResult); + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) { + super.init(exprs, matchedPattern, isDelayed, parseResult); - if (exprs[0] instanceof StructImport.ImportHandler) { - JavaType javaType = ((StructImport.ImportHandler) exprs[0]).getJavaType(); - Class clazz = javaType.getJavaClass(); + if (exprs[0] instanceof StructImport.ImportHandler) { + JavaType javaType = ((StructImport.ImportHandler) exprs[0]).getJavaType(); + Class clazz = javaType.getJavaClass(); - if (!JavaPlugin.class.isAssignableFrom(clazz) || JavaPlugin.class.equals(clazz)) { - Skript.error("The class " + clazz.getSimpleName() + " is not a plugin class"); - return false; - } - } + if (!JavaPlugin.class.isAssignableFrom(clazz) || JavaPlugin.class.equals(clazz)) { + Skript.error("The class " + clazz.getSimpleName() + " is not a plugin class"); + return false; + } + } - return true; - } + return true; + } - @Override - public ObjectWrapper convert(Object plugin) { - if (plugin instanceof String) { - String pluginName = (String) plugin; - for (Plugin pluginInstance : Bukkit.getPluginManager().getPlugins()) { - if (pluginInstance.getName().equalsIgnoreCase(pluginName)) { - return ObjectWrapper.create(pluginInstance); - } - } + @Override + public ObjectWrapper convert(Object plugin) { + if (plugin instanceof String) { + String pluginName = (String) plugin; + for (Plugin pluginInstance : Bukkit.getPluginManager().getPlugins()) { + if (pluginInstance.getName().equalsIgnoreCase(pluginName)) { + return ObjectWrapper.create(pluginInstance); + } + } - return null; - } else { - Class clazz = ((JavaType) plugin).getJavaClass(); + return null; + } else { + Class clazz = ((JavaType) plugin).getJavaClass(); - if (!JavaPlugin.class.isAssignableFrom(clazz) || JavaPlugin.class.equals(clazz)) { - return null; - } + if (!JavaPlugin.class.isAssignableFrom(clazz) || JavaPlugin.class.equals(clazz)) { + return null; + } - return ObjectWrapper.create(JavaPlugin.getPlugin(clazz.asSubclass(JavaPlugin.class))); - } - } + return ObjectWrapper.create(JavaPlugin.getPlugin(clazz.asSubclass(JavaPlugin.class))); + } + } - @Override - @NonNull - public Class getReturnType() { - return ObjectWrapper.class; - } + @Override + @NonNull + public Class getReturnType() { + return ObjectWrapper.class; + } - @Override - @NonNull - protected String getPropertyName() { - return "plugin instance"; - } + @Override + @NonNull + protected String getPropertyName() { + return "plugin instance"; + } } diff --git a/src/main/java/com/btk5h/skriptmirror/skript/ExprSpread.java b/src/main/java/com/btk5h/skriptmirror/skript/ExprSpread.java index 7a4e283d..9852eeb6 100644 --- a/src/main/java/com/btk5h/skriptmirror/skript/ExprSpread.java +++ b/src/main/java/com/btk5h/skriptmirror/skript/ExprSpread.java @@ -23,164 +23,164 @@ import java.util.stream.Stream; public class ExprSpread implements Expression { - static { - //noinspection unchecked - Skript.registerExpression(ExprSpread.class, Object.class, ExpressionType.COMBINED, "...%object%"); - } - - private Expression object; - - private final ExprSpread source; - private final Class[] types; - private final Class superType; - - @SuppressWarnings("unchecked") - public ExprSpread() { - this(null, (Class) Object.class); - } - - @SuppressWarnings("unchecked") - @SafeVarargs - private ExprSpread(ExprSpread source, Class... types) { - this.source = source; - - if (source != null) { - this.object = source.object; - } - - this.types = types; - this.superType = (Class) Utils.getSuperType(types); - } - - @Override - public T getSingle(Event e) { - throw new UnsupportedOperationException(); - } - - @Override - public T[] getArray(Event e) { - return getAll(e); - } - - @Override - public T[] getAll(Event e) { - Object obj = ObjectWrapper.unwrapIfNecessary(object.getSingle(e)); - - if (obj instanceof Collection) { - obj = ((Collection) obj).toArray(); - } else if (obj instanceof Iterable) { - obj = toArray(((Iterable) obj).iterator()); - } else if (obj instanceof Stream) { - obj = toArray(((Stream) obj).iterator()); - } else if (obj instanceof Iterator) { - obj = toArray((Iterator) obj); - } - - if (obj == null || !obj.getClass().isArray()) { - return JavaUtil.newArray(superType, 0); - } - - obj = JavaUtil.boxPrimitiveArray(obj); - - return Converters.convert((Object[]) obj, types, superType); - } - - private Object[] toArray(Iterator iter) { - List list = new ArrayList<>(); - iter.forEachRemaining(list::add); - return list.toArray(); - } - - @Override - public boolean isSingle() { - return false; - } - - @Override - public boolean check(Event e, Checker c, boolean negated) { - return SimpleExpression.check(getAll(e), c, negated, getAnd()); - } - - @Override - public boolean check(Event e, Checker c) { - return SimpleExpression.check(getAll(e), c, false, getAnd()); - } - - @Override - public Expression getConvertedExpression(Class[] to) { - return new ExprSpread<>(this, to); - } - - @Override - public Class getReturnType() { - return superType; - } - - @Override - public boolean getAnd() { - return true; - } - - @Override - public boolean setTime(int time) { - return false; - } - - @Override - public int getTime() { - return 0; - } - - @Override - public boolean isDefault() { - return false; - } - - @Override - public Iterator iterator(Event e) { - return new ArrayIterator<>(getAll(e)); - } - - @Override - public boolean isLoopOf(String s) { - return false; - } - - @Override - public Expression getSource() { - return source == null ? this : source; - } - - @Override - public Expression simplify() { - return this; - } - - @Override - public Class[] acceptChange(Changer.ChangeMode mode) { - return null; - } - - @Override - public void change(Event e, Object[] delta, Changer.ChangeMode mode) { - throw new UnsupportedOperationException(); - } - - @Override - public String toString(Event e, boolean debug) { - return "spread " + object.toString(e, debug); - } - - @Override - public String toString() { - return toString(null, false); - } - - @SuppressWarnings("unchecked") - @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, - SkriptParser.ParseResult parseResult) { - object = SkriptUtil.defendExpression(exprs[0]); - return SkriptUtil.canInitSafely(object); - } + static { + //noinspection unchecked + Skript.registerExpression(ExprSpread.class, Object.class, ExpressionType.COMBINED, "...%object%"); + } + + private Expression object; + + private final ExprSpread source; + private final Class[] types; + private final Class superType; + + @SuppressWarnings("unchecked") + public ExprSpread() { + this(null, (Class) Object.class); + } + + @SuppressWarnings("unchecked") + @SafeVarargs + private ExprSpread(ExprSpread source, Class... types) { + this.source = source; + + if (source != null) { + this.object = source.object; + } + + this.types = types; + this.superType = (Class) Utils.getSuperType(types); + } + + @Override + public T getSingle(Event e) { + throw new UnsupportedOperationException(); + } + + @Override + public T[] getArray(Event e) { + return getAll(e); + } + + @Override + public T[] getAll(Event e) { + Object obj = ObjectWrapper.unwrapIfNecessary(object.getSingle(e)); + + if (obj instanceof Collection) { + obj = ((Collection) obj).toArray(); + } else if (obj instanceof Iterable) { + obj = toArray(((Iterable) obj).iterator()); + } else if (obj instanceof Stream) { + obj = toArray(((Stream) obj).iterator()); + } else if (obj instanceof Iterator) { + obj = toArray((Iterator) obj); + } + + if (obj == null || !obj.getClass().isArray()) { + return JavaUtil.newArray(superType, 0); + } + + obj = JavaUtil.boxPrimitiveArray(obj); + + return Converters.convert((Object[]) obj, types, superType); + } + + private Object[] toArray(Iterator iter) { + List list = new ArrayList<>(); + iter.forEachRemaining(list::add); + return list.toArray(); + } + + @Override + public boolean isSingle() { + return false; + } + + @Override + public boolean check(Event e, Checker c, boolean negated) { + return SimpleExpression.check(getAll(e), c, negated, getAnd()); + } + + @Override + public boolean check(Event e, Checker c) { + return SimpleExpression.check(getAll(e), c, false, getAnd()); + } + + @Override + public Expression getConvertedExpression(Class[] to) { + return new ExprSpread<>(this, to); + } + + @Override + public Class getReturnType() { + return superType; + } + + @Override + public boolean getAnd() { + return true; + } + + @Override + public boolean setTime(int time) { + return false; + } + + @Override + public int getTime() { + return 0; + } + + @Override + public boolean isDefault() { + return false; + } + + @Override + public Iterator iterator(Event e) { + return new ArrayIterator<>(getAll(e)); + } + + @Override + public boolean isLoopOf(String s) { + return false; + } + + @Override + public Expression getSource() { + return source == null ? this : source; + } + + @Override + public Expression simplify() { + return this; + } + + @Override + public Class[] acceptChange(Changer.ChangeMode mode) { + return null; + } + + @Override + public void change(Event e, Object[] delta, Changer.ChangeMode mode) { + throw new UnsupportedOperationException(); + } + + @Override + public String toString(Event e, boolean debug) { + return "spread " + object.toString(e, debug); + } + + @Override + public String toString() { + return toString(null, false); + } + + @SuppressWarnings("unchecked") + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, + SkriptParser.ParseResult parseResult) { + object = SkriptUtil.defendExpression(exprs[0]); + return SkriptUtil.canInitSafely(object); + } } diff --git a/src/main/java/com/btk5h/skriptmirror/skript/LitNullObject.java b/src/main/java/com/btk5h/skriptmirror/skript/LitNullObject.java index ac839a3a..ff331258 100644 --- a/src/main/java/com/btk5h/skriptmirror/skript/LitNullObject.java +++ b/src/main/java/com/btk5h/skriptmirror/skript/LitNullObject.java @@ -10,22 +10,22 @@ import org.bukkit.event.Event; public class LitNullObject extends SimpleLiteral { - static { - Skript.registerExpression(LitNullObject.class, Null.class, ExpressionType.SIMPLE, "null"); - } + static { + Skript.registerExpression(LitNullObject.class, Null.class, ExpressionType.SIMPLE, "null"); + } - public LitNullObject() { - super(Null.getInstance(), false); - } + public LitNullObject() { + super(Null.getInstance(), false); + } - @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, - SkriptParser.ParseResult parseResult) { - return true; - } + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, + SkriptParser.ParseResult parseResult) { + return true; + } - @Override - public String toString(Event e, boolean debug) { - return "null"; - } + @Override + public String toString(Event e, boolean debug) { + return "null"; + } } diff --git a/src/main/java/com/btk5h/skriptmirror/skript/Types.java b/src/main/java/com/btk5h/skriptmirror/skript/Types.java index 81100683..552c3296 100644 --- a/src/main/java/com/btk5h/skriptmirror/skript/Types.java +++ b/src/main/java/com/btk5h/skriptmirror/skript/Types.java @@ -23,197 +23,196 @@ public class Types { - static { - Classes.registerClass(new ClassInfo<>(Event.class, "event") - .user("events?") - .parser(new Parser() { - @Override - public Event parse(String s, ParseContext parseContext) { - return null; - } - - @Override - public boolean canParse(ParseContext context) { - return false; - } - - @Override - public String toString(Event e, int i) { - return e.getEventName(); - } - - @Override - public String toVariableNameString(Event e) { - return e.toString(); - } - - public String getVariableNamePattern() { - return ".+"; - } - })); - - Classes.registerClass(new ClassInfo<>(JavaType.class, "javatype") - .user("javatypes?") - .parser(new Parser() { - @Override - public JavaType parse(String s, ParseContext context) { - Script script = SkriptUtil.getCurrentScript(); - return StructImport.lookup(script, s); - } - - @Override - public boolean canParse(ParseContext context) { - // default context handled in StructImport$ImportHandler - return context != ParseContext.DEFAULT; - } - - @Override - public String toString(JavaType o, int flags) { - return o.getJavaClass().getName(); - } - - @Override - public String toVariableNameString(JavaType o) { - return "type:" + o.getJavaClass().getName(); - } - - }) - .serializer(new Serializer() { - @Override - public Fields serialize(JavaType cls) { - Fields f = new Fields(); - f.putObject("type", cls.getJavaClass().getName()); - return f; - } - - @Override - public void deserialize(JavaType o, Fields f) { - - } - - @Override - protected JavaType deserialize(Fields fields) throws StreamCorruptedException, - NotSerializableException { - try { - return new JavaType(LibraryLoader.getClassLoader().loadClass((String) fields.getObject("type"))); - } catch (ClassNotFoundException e) { - throw new NotSerializableException(); - } - } - - @Override - public boolean mustSyncDeserialization() { - return false; - } - - @Override - public boolean canBeInstantiated(Class aClass) { - return false; - } - - @Override - protected boolean canBeInstantiated() { - return false; - } - })); - - Converters.registerConverter(ClassInfo.class, JavaType.class, c -> new JavaType(c.getC())); - - Classes.registerClass(new ClassInfo<>(Null.class, "null") - .parser(new Parser() { - @Override - public Null parse(String s, ParseContext context) { - return null; - } - - @Override - public boolean canParse(ParseContext context) { - return false; - } - - @Override - public String toString(Null o, int flags) { - return "null"; - } - - @Override - public String toVariableNameString(Null o) { - return "null"; - } - - public String getVariableNamePattern() { - return "null"; - } - }) - .serializer(new Serializer() { - @Override - public Fields serialize(Null o) { - return new Fields(); - } - - @Override - public void deserialize(Null o, Fields f) { - - } - - @Override - protected Null deserialize(Fields fields) { - return Null.getInstance(); - } - - @Override - public boolean mustSyncDeserialization() { - return false; - } - - @Override - public boolean canBeInstantiated(Class c) { - return false; - } - - @Override - protected boolean canBeInstantiated() { - return false; - } - }) - ); - - Classes.registerClass(new ClassInfo<>(ObjectWrapper.class, "javaobject") - .user("javaobjects?") - .parser(new Parser() { - @Override - public ObjectWrapper parse(String s, ParseContext context) { - return null; - } - - @Override - public boolean canParse(ParseContext context) { - return false; - } - - @Override - public String toString(ObjectWrapper objectWrapper, int flags) { - if (objectWrapper.isArray()) { - return JavaUtil.arrayToString(objectWrapper.get(), Classes::toString); - } - - return Classes.toString(objectWrapper.get()); - } - - @Override - public String toVariableNameString(ObjectWrapper o) { - return o.toString(); - } - - public String getVariableNamePattern() { - return ".+"; - } - }) - ); - - Classes.registerClass(new ClassInfo<>(Section.class, "section") - .user("sections?") - ); - } + static { + Classes.registerClass(new ClassInfo<>(Event.class, "event") + .user("events?") + .parser(new Parser() { + @Override + public Event parse(String s, ParseContext parseContext) { + return null; + } + + @Override + public boolean canParse(ParseContext context) { + return false; + } + + @Override + public String toString(Event e, int i) { + return e.getEventName(); + } + + @Override + public String toVariableNameString(Event e) { + return e.toString(); + } + + public String getVariableNamePattern() { + return ".+"; + } + })); + + Classes.registerClass(new ClassInfo<>(JavaType.class, "javatype") + .user("javatypes?") + .parser(new Parser() { + @Override + public JavaType parse(String s, ParseContext context) { + Script script = SkriptUtil.getCurrentScript(); + return StructImport.lookup(script, s); + } + + @Override + public boolean canParse(ParseContext context) { + // default context handled in StructImport$ImportHandler + return context != ParseContext.DEFAULT; + } + + @Override + public String toString(JavaType o, int flags) { + return o.getJavaClass().getName(); + } + + @Override + public String toVariableNameString(JavaType o) { + return "type:" + o.getJavaClass().getName(); + } + }) + .serializer(new Serializer() { + @Override + public Fields serialize(JavaType cls) { + Fields f = new Fields(); + f.putObject("type", cls.getJavaClass().getName()); + return f; + } + + @Override + public void deserialize(JavaType o, Fields f) { + + } + + @Override + protected JavaType deserialize(Fields fields) throws StreamCorruptedException, + NotSerializableException { + try { + return new JavaType(LibraryLoader.getClassLoader().loadClass((String) fields.getObject("type"))); + } catch (ClassNotFoundException e) { + throw new NotSerializableException(); + } + } + + @Override + public boolean mustSyncDeserialization() { + return false; + } + + @Override + public boolean canBeInstantiated(Class aClass) { + return false; + } + + @Override + protected boolean canBeInstantiated() { + return false; + } + })); + + Converters.registerConverter(ClassInfo.class, JavaType.class, c -> new JavaType(c.getC())); + + Classes.registerClass(new ClassInfo<>(Null.class, "null") + .parser(new Parser() { + @Override + public Null parse(String s, ParseContext context) { + return null; + } + + @Override + public boolean canParse(ParseContext context) { + return false; + } + + @Override + public String toString(Null o, int flags) { + return "null"; + } + + @Override + public String toVariableNameString(Null o) { + return "null"; + } + + public String getVariableNamePattern() { + return "null"; + } + }) + .serializer(new Serializer() { + @Override + public Fields serialize(Null o) { + return new Fields(); + } + + @Override + public void deserialize(Null o, Fields f) { + + } + + @Override + protected Null deserialize(Fields fields) { + return Null.getInstance(); + } + + @Override + public boolean mustSyncDeserialization() { + return false; + } + + @Override + public boolean canBeInstantiated(Class c) { + return false; + } + + @Override + protected boolean canBeInstantiated() { + return false; + } + }) + ); + + Classes.registerClass(new ClassInfo<>(ObjectWrapper.class, "javaobject") + .user("javaobjects?") + .parser(new Parser() { + @Override + public ObjectWrapper parse(String s, ParseContext context) { + return null; + } + + @Override + public boolean canParse(ParseContext context) { + return false; + } + + @Override + public String toString(ObjectWrapper objectWrapper, int flags) { + if (objectWrapper.isArray()) { + return JavaUtil.arrayToString(objectWrapper.get(), Classes::toString); + } + + return Classes.toString(objectWrapper.get()); + } + + @Override + public String toVariableNameString(ObjectWrapper o) { + return o.toString(); + } + + public String getVariableNamePattern() { + return ".+"; + } + }) + ); + + Classes.registerClass(new ClassInfo<>(Section.class, "section") + .user("sections?") + ); + } } diff --git a/src/main/java/com/btk5h/skriptmirror/skript/custom/Continuable.java b/src/main/java/com/btk5h/skriptmirror/skript/custom/Continuable.java index fd2f5ba9..b6835724 100644 --- a/src/main/java/com/btk5h/skriptmirror/skript/custom/Continuable.java +++ b/src/main/java/com/btk5h/skriptmirror/skript/custom/Continuable.java @@ -2,10 +2,10 @@ public interface Continuable { - default void markContinue() { - setContinue(true); - } + default void markContinue() { + setContinue(true); + } - void setContinue(boolean b); + void setContinue(boolean b); } diff --git a/src/main/java/com/btk5h/skriptmirror/skript/custom/CustomSyntaxEvent.java b/src/main/java/com/btk5h/skriptmirror/skript/custom/CustomSyntaxEvent.java index 9adeb2bd..547c8ed7 100644 --- a/src/main/java/com/btk5h/skriptmirror/skript/custom/CustomSyntaxEvent.java +++ b/src/main/java/com/btk5h/skriptmirror/skript/custom/CustomSyntaxEvent.java @@ -8,30 +8,30 @@ import java.util.Arrays; public abstract class CustomSyntaxEvent extends WrappedEvent { - private final Expression[] expressions; - private final int matchedPattern; - private final SkriptParser.ParseResult parseResult; - - protected CustomSyntaxEvent(Event event, Expression[] expressions, int matchedPattern, - SkriptParser.ParseResult parseResult) { - super(event); - this.expressions = Arrays.stream(expressions) - .map(expr -> CustomSyntaxExpression.wrap(expr, event)) - .toArray(Expression[]::new); - this.matchedPattern = matchedPattern; - this.parseResult = parseResult; - } - - public Expression[] getExpressions() { - return expressions; - } - - public int getMatchedPattern() { - return matchedPattern; - } - - public SkriptParser.ParseResult getParseResult() { - return parseResult; - } + private final Expression[] expressions; + private final int matchedPattern; + private final SkriptParser.ParseResult parseResult; + + protected CustomSyntaxEvent(Event event, Expression[] expressions, int matchedPattern, + SkriptParser.ParseResult parseResult) { + super(event); + this.expressions = Arrays.stream(expressions) + .map(expr -> CustomSyntaxExpression.wrap(expr, event)) + .toArray(Expression[]::new); + this.matchedPattern = matchedPattern; + this.parseResult = parseResult; + } + + public Expression[] getExpressions() { + return expressions; + } + + public int getMatchedPattern() { + return matchedPattern; + } + + public SkriptParser.ParseResult getParseResult() { + return parseResult; + } } diff --git a/src/main/java/com/btk5h/skriptmirror/skript/custom/CustomSyntaxExpression.java b/src/main/java/com/btk5h/skriptmirror/skript/custom/CustomSyntaxExpression.java index 661f8742..e1f5855f 100644 --- a/src/main/java/com/btk5h/skriptmirror/skript/custom/CustomSyntaxExpression.java +++ b/src/main/java/com/btk5h/skriptmirror/skript/custom/CustomSyntaxExpression.java @@ -7,51 +7,51 @@ import org.bukkit.event.Event; public class CustomSyntaxExpression extends SimpleExpression { - private final Expression source; - private final Event realEvent; - private final Object[] value; - - public CustomSyntaxExpression(Expression source, Event realEvent) { - this.source = source; - this.realEvent = realEvent; - this.value = source == null ? new Object[0] : source.getAll(realEvent); - } - - public static CustomSyntaxExpression wrap(Expression source, Event realEvent) { - if (source instanceof CustomSyntaxExpression) { - return (CustomSyntaxExpression) source; - } - return new CustomSyntaxExpression(source, realEvent); - } - - @Override - protected Object[] get(Event e) { - return value; - } - - @Override - public boolean isSingle() { - return source == null || source.isSingle(); - } - - @Override - public Class getReturnType() { - return source == null ? Object.class : source.getReturnType(); - } - - @Override - public String toString(Event e, boolean debug) { - return source == null ? "" : source.toString(realEvent, debug); - } - - @Override - public Expression getSource() { - return source; - } - - @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) { - throw new UnsupportedOperationException(); - } + private final Expression source; + private final Event realEvent; + private final Object[] value; + + public CustomSyntaxExpression(Expression source, Event realEvent) { + this.source = source; + this.realEvent = realEvent; + this.value = source == null ? new Object[0] : source.getAll(realEvent); + } + + public static CustomSyntaxExpression wrap(Expression source, Event realEvent) { + if (source instanceof CustomSyntaxExpression) { + return (CustomSyntaxExpression) source; + } + return new CustomSyntaxExpression(source, realEvent); + } + + @Override + protected Object[] get(Event e) { + return value; + } + + @Override + public boolean isSingle() { + return source == null || source.isSingle(); + } + + @Override + public Class getReturnType() { + return source == null ? Object.class : source.getReturnType(); + } + + @Override + public String toString(Event e, boolean debug) { + return source == null ? "" : source.toString(realEvent, debug); + } + + @Override + public Expression getSource() { + return source; + } + + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) { + throw new UnsupportedOperationException(); + } } diff --git a/src/main/java/com/btk5h/skriptmirror/skript/custom/EffContinue.java b/src/main/java/com/btk5h/skriptmirror/skript/custom/EffContinue.java index f3589278..122d71c1 100644 --- a/src/main/java/com/btk5h/skriptmirror/skript/custom/EffContinue.java +++ b/src/main/java/com/btk5h/skriptmirror/skript/custom/EffContinue.java @@ -13,45 +13,45 @@ public class EffContinue extends Effect { - static { - Skript.registerEffect(EffContinue.class, "continue"); - } - - @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, - SkriptParser.ParseResult parseResult) { - if (!(getParser().isCurrentEvent(EffectTriggerEvent.class) - || CollectionUtils.containsAnySuperclass(new Class[]{Continuable.class}, getParser().getCurrentEvents()))) { - Skript.error("Continue may only be used in loops, custom effects, custom syntax parse sections and custom conditions", ErrorQuality.SEMANTIC_ERROR); - return false; - } - - return true; - } - - @Override - protected void execute(Event e) { - throw new UnsupportedOperationException(); - } - - @Override - protected TriggerItem walk(Event e) { - if (e instanceof EffectTriggerEvent) { - EffectTriggerEvent effectTriggerEvent = (EffectTriggerEvent) e; - if (effectTriggerEvent.isSync()) { - Skript.warning("Synchronous events should not be continued. Call 'delay effect' to delay the effect's execution."); - } else { - effectTriggerEvent.setContinued(); - TriggerItem.walk(effectTriggerEvent.getNext(), effectTriggerEvent.getDirectEvent()); - } - } else if (e instanceof Continuable) { - ((Continuable) e).markContinue(); - } - return null; - } - - @Override - public String toString(Event e, boolean debug) { - return "continue"; - } + static { + Skript.registerEffect(EffContinue.class, "continue"); + } + + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, + SkriptParser.ParseResult parseResult) { + if (!(getParser().isCurrentEvent(EffectTriggerEvent.class) + || CollectionUtils.containsAnySuperclass(new Class[]{Continuable.class}, getParser().getCurrentEvents()))) { + Skript.error("Continue may only be used in loops, custom effects, custom syntax parse sections and custom conditions", ErrorQuality.SEMANTIC_ERROR); + return false; + } + + return true; + } + + @Override + protected void execute(Event e) { + throw new UnsupportedOperationException(); + } + + @Override + protected TriggerItem walk(Event e) { + if (e instanceof EffectTriggerEvent) { + EffectTriggerEvent effectTriggerEvent = (EffectTriggerEvent) e; + if (effectTriggerEvent.isSync()) { + Skript.warning("Synchronous events should not be continued. Call 'delay effect' to delay the effect's execution."); + } else { + effectTriggerEvent.setContinued(); + TriggerItem.walk(effectTriggerEvent.getNext(), effectTriggerEvent.getDirectEvent()); + } + } else if (e instanceof Continuable) { + ((Continuable) e).markContinue(); + } + return null; + } + + @Override + public String toString(Event e, boolean debug) { + return "continue"; + } } diff --git a/src/main/java/com/btk5h/skriptmirror/skript/custom/ExprEventClasses.java b/src/main/java/com/btk5h/skriptmirror/skript/custom/ExprEventClasses.java index 1dd98b14..cb4030aa 100644 --- a/src/main/java/com/btk5h/skriptmirror/skript/custom/ExprEventClasses.java +++ b/src/main/java/com/btk5h/skriptmirror/skript/custom/ExprEventClasses.java @@ -12,36 +12,36 @@ import java.util.Arrays; public class ExprEventClasses extends SimpleExpression { - static { - Skript.registerExpression(ExprEventClasses.class, JavaType.class, ExpressionType.SIMPLE, "event-classes"); - } - - @Override - protected JavaType[] get(Event e) { - return Arrays.stream(((SyntaxParseEvent) e).getEventClasses()) - .map(JavaType::new) - .toArray(JavaType[]::new); - } - - @Override - public boolean isSingle() { - return false; - } - - @Override - public Class getReturnType() { - return JavaType.class; - } - - @Override - public String toString(Event e, boolean debug) { - return "event-classes"; - } - - @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, - SkriptParser.ParseResult parseResult) { - return getParser().isCurrentEvent(SyntaxParseEvent.class); - } + static { + Skript.registerExpression(ExprEventClasses.class, JavaType.class, ExpressionType.SIMPLE, "event-classes"); + } + + @Override + protected JavaType[] get(Event e) { + return Arrays.stream(((SyntaxParseEvent) e).getEventClasses()) + .map(JavaType::new) + .toArray(JavaType[]::new); + } + + @Override + public boolean isSingle() { + return false; + } + + @Override + public Class getReturnType() { + return JavaType.class; + } + + @Override + public String toString(Event e, boolean debug) { + return "event-classes"; + } + + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, + SkriptParser.ParseResult parseResult) { + return getParser().isCurrentEvent(SyntaxParseEvent.class); + } } diff --git a/src/main/java/com/btk5h/skriptmirror/skript/custom/ExprExpression.java b/src/main/java/com/btk5h/skriptmirror/skript/custom/ExprExpression.java index 9e8ebb79..8c6c0de3 100644 --- a/src/main/java/com/btk5h/skriptmirror/skript/custom/ExprExpression.java +++ b/src/main/java/com/btk5h/skriptmirror/skript/custom/ExprExpression.java @@ -24,182 +24,182 @@ import java.util.Iterator; public class ExprExpression implements Expression { - static { - //noinspection unchecked - Skript.registerExpression(ExprExpression.class, Object.class, ExpressionType.SIMPLE, - "[the] expr[ession][(1¦s)](-| )<\\d+>"); - } - - private int index; - private boolean plural; - - private final ExprExpression source; - private final Class[] types; - private final Class superType; - - @SuppressWarnings("unchecked") - public ExprExpression() { - this(null, ((Class) Object.class)); - } - - @SuppressWarnings("unchecked") - @SafeVarargs - private ExprExpression(ExprExpression source, Class... types) { - if (source != null) { - index = source.index; - plural = source.plural; - } - - this.source = source; - this.types = types; - this.superType = (Class) Utils.getSuperType(types); - } - - @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, - SkriptParser.ParseResult parseResult) { - if (!getParser().isCurrentEvent( - SyntaxParseEvent.class, - ConditionCheckEvent.class, - EffectTriggerEvent.class, - EventTriggerEvent.class, - ExpressionChangeEvent.class, - ExpressionGetEvent.class - )) { - Skript.error("The expression 'expression' may only be used in a custom syntax.", - ErrorQuality.SEMANTIC_ERROR); - return false; - } - - index = Utils.parseInt(parseResult.regexes.get(0).group(0)); - if (index <= 0) { - Skript.error("The expression index must be a natural number.", ErrorQuality.SEMANTIC_ERROR); - return false; - } - index--; - - plural = parseResult.mark == 1; - - return true; - } - - @Override - public T getSingle(Event e) { - T[] all = getAll(e); - if (all.length == 0) { - return null; - } - return all[0]; - } - - @Override - public T[] getArray(Event e) { - return getAll(e); - } - - @Override - public T[] getAll(Event e) { - Expression expr = getExpression(e); - - if (expr == null) { - return JavaUtil.newArray(superType, 0); - } - - return Converters.convert(expr.getAll(e), types, superType); - } - - @Nullable - Expression getExpression(Event e) { - Expression[] expressions = ((CustomSyntaxEvent) e).getExpressions(); - if (index < expressions.length) { - return expressions[index]; - } - return null; - } - - @Override - public boolean isSingle() { - return !plural; - } - - @Override - public boolean check(Event e, Checker c, boolean negated) { - return SimpleExpression.check(getAll(e), c, negated, getAnd()); - } - - @Override - public boolean check(Event e, Checker c) { - return SimpleExpression.check(getAll(e), c, false, getAnd()); - } - - @Override - public Expression getConvertedExpression(Class[] to) { - return new ExprExpression<>(this, to); - } - - @Override - public Class getReturnType() { - return superType; - } - - @Override - public boolean getAnd() { - return true; - } - - @Override - public boolean setTime(int time) { - return false; - } - - @Override - public int getTime() { - return 0; - } - - @Override - public boolean isDefault() { - return false; - } - - @Override - public Iterator iterator(Event e) { - return new ArrayIterator<>(getAll(e)); - } - - @Override - public boolean isLoopOf(String s) { - return s.equalsIgnoreCase("expression"); - } - - @Override - public Expression getSource() { - return source == null ? this : source; - } - - @Override - public Expression simplify() { - return this; - } - - @Override - public Class[] acceptChange(Changer.ChangeMode mode) { - return null; - } - - @Override - public void change(Event e, Object[] delta, Changer.ChangeMode mode) { - throw new UnsupportedOperationException(); - } - - @Override - public String toString(Event e, boolean debug) { - return "expression " + (index + 1); - } - - @Override - public String toString() { - return toString(null, false); - } + static { + //noinspection unchecked + Skript.registerExpression(ExprExpression.class, Object.class, ExpressionType.SIMPLE, + "[the] expr[ession][(1¦s)](-| )<\\d+>"); + } + + private int index; + private boolean plural; + + private final ExprExpression source; + private final Class[] types; + private final Class superType; + + @SuppressWarnings("unchecked") + public ExprExpression() { + this(null, ((Class) Object.class)); + } + + @SuppressWarnings("unchecked") + @SafeVarargs + private ExprExpression(ExprExpression source, Class... types) { + if (source != null) { + index = source.index; + plural = source.plural; + } + + this.source = source; + this.types = types; + this.superType = (Class) Utils.getSuperType(types); + } + + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, + SkriptParser.ParseResult parseResult) { + if (!getParser().isCurrentEvent( + SyntaxParseEvent.class, + ConditionCheckEvent.class, + EffectTriggerEvent.class, + EventTriggerEvent.class, + ExpressionChangeEvent.class, + ExpressionGetEvent.class + )) { + Skript.error("The expression 'expression' may only be used in a custom syntax.", + ErrorQuality.SEMANTIC_ERROR); + return false; + } + + index = Utils.parseInt(parseResult.regexes.get(0).group(0)); + if (index <= 0) { + Skript.error("The expression index must be a natural number.", ErrorQuality.SEMANTIC_ERROR); + return false; + } + index--; + + plural = parseResult.mark == 1; + + return true; + } + + @Override + public T getSingle(Event e) { + T[] all = getAll(e); + if (all.length == 0) { + return null; + } + return all[0]; + } + + @Override + public T[] getArray(Event e) { + return getAll(e); + } + + @Override + public T[] getAll(Event e) { + Expression expr = getExpression(e); + + if (expr == null) { + return JavaUtil.newArray(superType, 0); + } + + return Converters.convert(expr.getAll(e), types, superType); + } + + @Nullable + Expression getExpression(Event e) { + Expression[] expressions = ((CustomSyntaxEvent) e).getExpressions(); + if (index < expressions.length) { + return expressions[index]; + } + return null; + } + + @Override + public boolean isSingle() { + return !plural; + } + + @Override + public boolean check(Event e, Checker c, boolean negated) { + return SimpleExpression.check(getAll(e), c, negated, getAnd()); + } + + @Override + public boolean check(Event e, Checker c) { + return SimpleExpression.check(getAll(e), c, false, getAnd()); + } + + @Override + public Expression getConvertedExpression(Class[] to) { + return new ExprExpression<>(this, to); + } + + @Override + public Class getReturnType() { + return superType; + } + + @Override + public boolean getAnd() { + return true; + } + + @Override + public boolean setTime(int time) { + return false; + } + + @Override + public int getTime() { + return 0; + } + + @Override + public boolean isDefault() { + return false; + } + + @Override + public Iterator iterator(Event e) { + return new ArrayIterator<>(getAll(e)); + } + + @Override + public boolean isLoopOf(String s) { + return s.equalsIgnoreCase("expression"); + } + + @Override + public Expression getSource() { + return source == null ? this : source; + } + + @Override + public Expression simplify() { + return this; + } + + @Override + public Class[] acceptChange(Changer.ChangeMode mode) { + return null; + } + + @Override + public void change(Event e, Object[] delta, Changer.ChangeMode mode) { + throw new UnsupportedOperationException(); + } + + @Override + public String toString(Event e, boolean debug) { + return "expression " + (index + 1); + } + + @Override + public String toString() { + return toString(null, false); + } } diff --git a/src/main/java/com/btk5h/skriptmirror/skript/custom/ExprMatchedPattern.java b/src/main/java/com/btk5h/skriptmirror/skript/custom/ExprMatchedPattern.java index d5fdc8a2..9f5a4837 100644 --- a/src/main/java/com/btk5h/skriptmirror/skript/custom/ExprMatchedPattern.java +++ b/src/main/java/com/btk5h/skriptmirror/skript/custom/ExprMatchedPattern.java @@ -15,44 +15,44 @@ import org.bukkit.event.Event; public class ExprMatchedPattern extends SimpleExpression { - static { - Skript.registerExpression(ExprMatchedPattern.class, Number.class, ExpressionType.SIMPLE, "[the] [matched] pattern"); - } + static { + Skript.registerExpression(ExprMatchedPattern.class, Number.class, ExpressionType.SIMPLE, "[the] [matched] pattern"); + } - @Override - protected Number[] get(Event e) { - return new Number[]{((CustomSyntaxEvent) e).getMatchedPattern()}; - } + @Override + protected Number[] get(Event e) { + return new Number[]{((CustomSyntaxEvent) e).getMatchedPattern()}; + } - @Override - public boolean isSingle() { - return true; - } + @Override + public boolean isSingle() { + return true; + } - @Override - public Class getReturnType() { - return Number.class; - } + @Override + public Class getReturnType() { + return Number.class; + } - @Override - public String toString(Event e, boolean debug) { - return "matched pattern"; - } + @Override + public String toString(Event e, boolean debug) { + return "matched pattern"; + } - @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, - SkriptParser.ParseResult parseResult) { - if (!getParser().isCurrentEvent( - SyntaxParseEvent.class, - ConditionCheckEvent.class, - EffectTriggerEvent.class, - EventTriggerEvent.class, - ExpressionChangeEvent.class, - ExpressionGetEvent.class - )) { - Skript.error("The matched pattern may only be used in custom syntax.", ErrorQuality.SEMANTIC_ERROR); - return false; - } - return true; - } + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, + SkriptParser.ParseResult parseResult) { + if (!getParser().isCurrentEvent( + SyntaxParseEvent.class, + ConditionCheckEvent.class, + EffectTriggerEvent.class, + EventTriggerEvent.class, + ExpressionChangeEvent.class, + ExpressionGetEvent.class + )) { + Skript.error("The matched pattern may only be used in custom syntax.", ErrorQuality.SEMANTIC_ERROR); + return false; + } + return true; + } } diff --git a/src/main/java/com/btk5h/skriptmirror/skript/custom/ExprParseMark.java b/src/main/java/com/btk5h/skriptmirror/skript/custom/ExprParseMark.java index bf22b999..4b490550 100644 --- a/src/main/java/com/btk5h/skriptmirror/skript/custom/ExprParseMark.java +++ b/src/main/java/com/btk5h/skriptmirror/skript/custom/ExprParseMark.java @@ -14,44 +14,44 @@ import org.bukkit.event.Event; public class ExprParseMark extends SimpleExpression { - static { - Skript.registerExpression(ExprParseMark.class, Number.class, ExpressionType.SIMPLE, - "[the] [parse[r]] mark"); - } + static { + Skript.registerExpression(ExprParseMark.class, Number.class, ExpressionType.SIMPLE, + "[the] [parse[r]] mark"); + } - @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { - if (!getParser().isCurrentEvent( - SyntaxParseEvent.class, - ConditionCheckEvent.class, - EffectTriggerEvent.class, - EventTriggerEvent.class, - ExpressionChangeEvent.class, - ExpressionGetEvent.class - )) { - Skript.error("The parse mark may only be used in custom syntax"); - return false; - } - return true; - } + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + if (!getParser().isCurrentEvent( + SyntaxParseEvent.class, + ConditionCheckEvent.class, + EffectTriggerEvent.class, + EventTriggerEvent.class, + ExpressionChangeEvent.class, + ExpressionGetEvent.class + )) { + Skript.error("The parse mark may only be used in custom syntax"); + return false; + } + return true; + } - @Override - protected Number[] get(Event e) { - return new Number[]{((CustomSyntaxEvent) e).getParseResult().mark}; - } + @Override + protected Number[] get(Event e) { + return new Number[]{((CustomSyntaxEvent) e).getParseResult().mark}; + } - @Override - public boolean isSingle() { - return true; - } + @Override + public boolean isSingle() { + return true; + } - @Override - public Class getReturnType() { - return Number.class; - } + @Override + public Class getReturnType() { + return Number.class; + } - @Override - public String toString(Event e, boolean debug) { - return "parser mark"; - } + @Override + public String toString(Event e, boolean debug) { + return "parser mark"; + } } diff --git a/src/main/java/com/btk5h/skriptmirror/skript/custom/ExprParseRegex.java b/src/main/java/com/btk5h/skriptmirror/skript/custom/ExprParseRegex.java index 30a1c011..ede425e4 100644 --- a/src/main/java/com/btk5h/skriptmirror/skript/custom/ExprParseRegex.java +++ b/src/main/java/com/btk5h/skriptmirror/skript/custom/ExprParseRegex.java @@ -19,67 +19,67 @@ import java.util.regex.MatchResult; public class ExprParseRegex extends SimpleExpression { - static { - Skript.registerExpression(ExprParseRegex.class, String.class, ExpressionType.SIMPLE, - "[the] [parse[r]] (regex|regular expression)(-| )<\\d+>"); - } + static { + Skript.registerExpression(ExprParseRegex.class, String.class, ExpressionType.SIMPLE, + "[the] [parse[r]] (regex|regular expression)(-| )<\\d+>"); + } - private int index; + private int index; - @Override - protected String[] get(Event e) { - List regexes = ((CustomSyntaxEvent) e).getParseResult().regexes; - if (index < regexes.size()) { - MatchResult match = regexes.get(index); - int groupCount = match.groupCount(); - String[] groups = new String[groupCount]; + @Override + protected String[] get(Event e) { + List regexes = ((CustomSyntaxEvent) e).getParseResult().regexes; + if (index < regexes.size()) { + MatchResult match = regexes.get(index); + int groupCount = match.groupCount(); + String[] groups = new String[groupCount]; - for (int i = 1; i <= groupCount; i++) { - groups[i - 1] = match.group(i); - } + for (int i = 1; i <= groupCount; i++) { + groups[i - 1] = match.group(i); + } - return groups; - } - return new String[0]; - } + return groups; + } + return new String[0]; + } - @Override - public boolean isSingle() { - return false; - } + @Override + public boolean isSingle() { + return false; + } - @Override - public Class getReturnType() { - return String.class; - } + @Override + public Class getReturnType() { + return String.class; + } - @Override - public String toString(Event e, boolean debug) { - return "parser mark"; - } + @Override + public String toString(Event e, boolean debug) { + return "parser mark"; + } - @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, - SkriptParser.ParseResult parseResult) { - if (!getParser().isCurrentEvent( - SyntaxParseEvent.class, - ConditionCheckEvent.class, - EffectTriggerEvent.class, - EventTriggerEvent.class, - ExpressionChangeEvent.class, - ExpressionGetEvent.class - )) { - Skript.error("The parsed regular expression may only be used in custom syntax.", - ErrorQuality.SEMANTIC_ERROR); - return false; - } + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, + SkriptParser.ParseResult parseResult) { + if (!getParser().isCurrentEvent( + SyntaxParseEvent.class, + ConditionCheckEvent.class, + EffectTriggerEvent.class, + EventTriggerEvent.class, + ExpressionChangeEvent.class, + ExpressionGetEvent.class + )) { + Skript.error("The parsed regular expression may only be used in custom syntax.", + ErrorQuality.SEMANTIC_ERROR); + return false; + } - index = Utils.parseInt(parseResult.regexes.get(0).group(0)); - if (index <= 0) { - Skript.error("The expression index must be a natural number.", ErrorQuality.SEMANTIC_ERROR); - return false; - } - index--; - return true; - } + index = Utils.parseInt(parseResult.regexes.get(0).group(0)); + if (index <= 0) { + Skript.error("The expression index must be a natural number.", ErrorQuality.SEMANTIC_ERROR); + return false; + } + index--; + return true; + } } diff --git a/src/main/java/com/btk5h/skriptmirror/skript/custom/ExprParseTags.java b/src/main/java/com/btk5h/skriptmirror/skript/custom/ExprParseTags.java index 3442a4b4..0f1385b7 100644 --- a/src/main/java/com/btk5h/skriptmirror/skript/custom/ExprParseTags.java +++ b/src/main/java/com/btk5h/skriptmirror/skript/custom/ExprParseTags.java @@ -16,45 +16,45 @@ public class ExprParseTags extends SimpleExpression { - static { - Skript.registerExpression(ExprParseTags.class, String.class, ExpressionType.SIMPLE, "[the] parse[r] tags"); - } - - @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { - if (!getParser().isCurrentEvent( - SyntaxParseEvent.class, - ConditionCheckEvent.class, - EffectTriggerEvent.class, - EventTriggerEvent.class, - ExpressionChangeEvent.class, - ExpressionGetEvent.class - )) { - Skript.error("The parse tags may only be used in custom syntax"); - return false; - } - return true; - } - - @Override - @Nullable - protected String[] get(Event e) { - return ((CustomSyntaxEvent) e).getParseResult().tags.toArray(new String[0]); - } - - @Override - public boolean isSingle() { - return false; - } - - @Override - public Class getReturnType() { - return String.class; - } - - @Override - public String toString(@Nullable Event e, boolean debug) { - return "parse tags"; - } + static { + Skript.registerExpression(ExprParseTags.class, String.class, ExpressionType.SIMPLE, "[the] parse[r] tags"); + } + + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + if (!getParser().isCurrentEvent( + SyntaxParseEvent.class, + ConditionCheckEvent.class, + EffectTriggerEvent.class, + EventTriggerEvent.class, + ExpressionChangeEvent.class, + ExpressionGetEvent.class + )) { + Skript.error("The parse tags may only be used in custom syntax"); + return false; + } + return true; + } + + @Override + @Nullable + protected String[] get(Event e) { + return ((CustomSyntaxEvent) e).getParseResult().tags.toArray(new String[0]); + } + + @Override + public boolean isSingle() { + return false; + } + + @Override + public Class getReturnType() { + return String.class; + } + + @Override + public String toString(@Nullable Event e, boolean debug) { + return "parse tags"; + } } diff --git a/src/main/java/com/btk5h/skriptmirror/skript/custom/ExprRawExpression.java b/src/main/java/com/btk5h/skriptmirror/skript/custom/ExprRawExpression.java index a4560def..9e1ebbf3 100644 --- a/src/main/java/com/btk5h/skriptmirror/skript/custom/ExprRawExpression.java +++ b/src/main/java/com/btk5h/skriptmirror/skript/custom/ExprRawExpression.java @@ -12,63 +12,63 @@ import org.bukkit.event.Event; public class ExprRawExpression extends SimpleExpression { - static { - Skript.registerExpression(ExprRawExpression.class, Expression.class, ExpressionType.COMBINED, - "[the] raw %objects%"); - } + static { + Skript.registerExpression(ExprRawExpression.class, Expression.class, ExpressionType.COMBINED, + "[the] raw %objects%"); + } - private Expression expr; + private Expression expr; - @Override - protected Expression[] get(Event e) { - Expression expr = this.expr; - if (expr instanceof ExprExpression && e instanceof CustomSyntaxEvent) { - expr = ((ExprExpression) expr).getExpression(e); - if (expr == null) - return null; - expr = expr.getSource(); - } - return new Expression[] {expr}; - } + @Override + protected Expression[] get(Event e) { + Expression expr = this.expr; + if (expr instanceof ExprExpression && e instanceof CustomSyntaxEvent) { + expr = ((ExprExpression) expr).getExpression(e); + if (expr == null) + return null; + expr = expr.getSource(); + } + return new Expression[] {expr}; + } - @Override - public boolean isSingle() { - return true; - } + @Override + public boolean isSingle() { + return true; + } - @Override - public Class getReturnType() { - return Expression.class; - } + @Override + public Class getReturnType() { + return Expression.class; + } - @Override - public Class[] acceptChange(Changer.ChangeMode changeMode) { - return expr instanceof ExprExpression ? new Class[] {Object[].class} : null; - } + @Override + public Class[] acceptChange(Changer.ChangeMode changeMode) { + return expr instanceof ExprExpression ? new Class[] {Object[].class} : null; + } - @Override - public void change(Event event, Object[] delta, Changer.ChangeMode changeMode) { - if (!(expr instanceof ExprExpression && event instanceof CustomSyntaxEvent)) - return; + @Override + public void change(Event event, Object[] delta, Changer.ChangeMode changeMode) { + if (!(expr instanceof ExprExpression && event instanceof CustomSyntaxEvent)) + return; - Expression expr = ((ExprExpression) this.expr).getExpression(event); - if (expr == null) - return; - Expression source = expr.getSource(); + Expression expr = ((ExprExpression) this.expr).getExpression(event); + if (expr == null) + return; + Expression source = expr.getSource(); - event = ((WrappedEvent) event).getDirectEvent(); - source.change(event, delta, changeMode); - } + event = ((WrappedEvent) event).getDirectEvent(); + source.change(event, delta, changeMode); + } - @Override - public String toString(Event e, boolean debug) { - return "raw " + expr.toString(e, debug); - } + @Override + public String toString(Event e, boolean debug) { + return "raw " + expr.toString(e, debug); + } - @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, - SkriptParser.ParseResult parseResult) { - expr = SkriptUtil.defendExpression(exprs[0]); - return SkriptUtil.canInitSafely(expr); - } + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, + SkriptParser.ParseResult parseResult) { + expr = SkriptUtil.defendExpression(exprs[0]); + return SkriptUtil.canInitSafely(expr); + } } diff --git a/src/main/java/com/btk5h/skriptmirror/skript/custom/SyntaxParseEvent.java b/src/main/java/com/btk5h/skriptmirror/skript/custom/SyntaxParseEvent.java index 96de7a9d..355d2434 100644 --- a/src/main/java/com/btk5h/skriptmirror/skript/custom/SyntaxParseEvent.java +++ b/src/main/java/com/btk5h/skriptmirror/skript/custom/SyntaxParseEvent.java @@ -18,52 +18,52 @@ public class SyntaxParseEvent extends CustomSyntaxEvent implements Continuable { - private final static HandlerList handlers = new HandlerList(); - private final Class[] eventClasses; - private boolean markedContinue = false; + private final static HandlerList handlers = new HandlerList(); + private final Class[] eventClasses; + private boolean markedContinue = false; - public SyntaxParseEvent(Expression[] expressions, int matchedPattern, SkriptParser.ParseResult parseResult, - Class[] eventClasses) { - super(null, wrapRawExpressions(expressions), matchedPattern, parseResult); - this.eventClasses = eventClasses; - } + public SyntaxParseEvent(Expression[] expressions, int matchedPattern, SkriptParser.ParseResult parseResult, + Class[] eventClasses) { + super(null, wrapRawExpressions(expressions), matchedPattern, parseResult); + this.eventClasses = eventClasses; + } - private static Expression[] wrapRawExpressions(Expression[] expressions) { - return Arrays.stream(expressions) - .map(expr -> expr == null ? null : new SimpleLiteral<>(expr, false)) - .toArray(Expression[]::new); - } + private static Expression[] wrapRawExpressions(Expression[] expressions) { + return Arrays.stream(expressions) + .map(expr -> expr == null ? null : new SimpleLiteral<>(expr, false)) + .toArray(Expression[]::new); + } - public static HandlerList getHandlerList() { - return handlers; - } + public static HandlerList getHandlerList() { + return handlers; + } - public Class[] getEventClasses() { - return eventClasses; - } + public Class[] getEventClasses() { + return eventClasses; + } - public boolean isMarkedContinue() { - return markedContinue; - } + public boolean isMarkedContinue() { + return markedContinue; + } - @Override - public void setContinue(boolean b) { - markedContinue = b; - } + @Override + public void setContinue(boolean b) { + markedContinue = b; + } - @Override - public HandlerList getHandlers() { - return handlers; - } + @Override + public HandlerList getHandlers() { + return handlers; + } - public static void register(SectionNode parseNode, - List whichInfo, Map parserHandlers) { - ParserInstance.get().setCurrentEvent("custom syntax parser", SyntaxParseEvent.class); - List items = SkriptUtil.getItemsFromNode(parseNode); + public static void register(SectionNode parseNode, + List whichInfo, Map parserHandlers) { + ParserInstance.get().setCurrentEvent("custom syntax parser", SyntaxParseEvent.class); + List items = SkriptUtil.getItemsFromNode(parseNode); - whichInfo.forEach(which -> - parserHandlers.put(which, - new Trigger(ParserInstance.get().getCurrentScript(), "parse " + which.getPattern(), new SimpleEvent(), items))); - } + whichInfo.forEach(which -> + parserHandlers.put(which, + new Trigger(ParserInstance.get().getCurrentScript(), "parse " + which.getPattern(), new SimpleEvent(), items))); + } } diff --git a/src/main/java/com/btk5h/skriptmirror/skript/reflect/ExprClassReference.java b/src/main/java/com/btk5h/skriptmirror/skript/reflect/ExprClassReference.java index 84cde1ca..e3e20a41 100644 --- a/src/main/java/com/btk5h/skriptmirror/skript/reflect/ExprClassReference.java +++ b/src/main/java/com/btk5h/skriptmirror/skript/reflect/ExprClassReference.java @@ -14,42 +14,42 @@ public class ExprClassReference extends SimpleExpression { - static { - Skript.registerExpression(ExprClassReference.class, ObjectWrapper.class, ExpressionType.COMBINED, - "(<(" + JavaTypeWrapper.PRIMITIVE_PATTERNS + ")>|%-javatype%).class"); - } - - private JavaTypeWrapper javaTypeWrapper; - - @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) { - javaTypeWrapper = JavaTypeWrapper.of(exprs[0], parseResult.regexes); - return true; - } - - @Nullable - @Override - protected ObjectWrapper[] get(Event e) { - JavaType javaType = javaTypeWrapper.get(e); - if (javaType == null) { - return null; - } - return new ObjectWrapper[] {ObjectWrapper.create(javaType.getJavaClass())}; - } - - @Override - public boolean isSingle() { - return true; - } - - @Override - public Class getReturnType() { - return ObjectWrapper.class; - } - - @Override - public String toString(@Nullable Event e, boolean debug) { - return javaTypeWrapper.toString(e, debug) + ".class"; - } + static { + Skript.registerExpression(ExprClassReference.class, ObjectWrapper.class, ExpressionType.COMBINED, + "(<(" + JavaTypeWrapper.PRIMITIVE_PATTERNS + ")>|%-javatype%).class"); + } + + private JavaTypeWrapper javaTypeWrapper; + + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) { + javaTypeWrapper = JavaTypeWrapper.of(exprs[0], parseResult.regexes); + return true; + } + + @Nullable + @Override + protected ObjectWrapper[] get(Event e) { + JavaType javaType = javaTypeWrapper.get(e); + if (javaType == null) { + return null; + } + return new ObjectWrapper[] {ObjectWrapper.create(javaType.getJavaClass())}; + } + + @Override + public boolean isSingle() { + return true; + } + + @Override + public Class getReturnType() { + return ObjectWrapper.class; + } + + @Override + public String toString(@Nullable Event e, boolean debug) { + return javaTypeWrapper.toString(e, debug) + ".class"; + } } diff --git a/src/main/java/com/btk5h/skriptmirror/skript/reflect/ExprEvent.java b/src/main/java/com/btk5h/skriptmirror/skript/reflect/ExprEvent.java index 7ea895cc..7f4992c5 100644 --- a/src/main/java/com/btk5h/skriptmirror/skript/reflect/ExprEvent.java +++ b/src/main/java/com/btk5h/skriptmirror/skript/reflect/ExprEvent.java @@ -10,39 +10,39 @@ import org.bukkit.event.Event; public class ExprEvent extends SimpleExpression { - static { - Skript.registerExpression(ExprEvent.class, Event.class, ExpressionType.SIMPLE, "[the] event"); - } + static { + Skript.registerExpression(ExprEvent.class, Event.class, ExpressionType.SIMPLE, "[the] event"); + } - @Override - protected Event[] get(Event e) { - if (e instanceof WrappedEvent) { - return new Event[]{((WrappedEvent) e).getEvent()}; - } - return new Event[]{e}; - } + @Override + protected Event[] get(Event e) { + if (e instanceof WrappedEvent) { + return new Event[]{((WrappedEvent) e).getEvent()}; + } + return new Event[]{e}; + } - @Override - public boolean isSingle() { - return true; - } + @Override + public boolean isSingle() { + return true; + } - @Override - public Class getReturnType() { - return Event.class; - } + @Override + public Class getReturnType() { + return Event.class; + } - @Override - public String toString(Event e, boolean debug) { - if (e == null) { - return "the event"; - } - return e.getEventName(); - } + @Override + public String toString(Event e, boolean debug) { + if (e == null) { + return "the event"; + } + return e.getEventName(); + } - @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, - SkriptParser.ParseResult parseResult) { - return true; - } + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, + SkriptParser.ParseResult parseResult) { + return true; + } } diff --git a/src/main/java/com/btk5h/skriptmirror/skript/reflect/ExprJavaCall.java b/src/main/java/com/btk5h/skriptmirror/skript/reflect/ExprJavaCall.java index 6a9d7eea..5917f1a2 100644 --- a/src/main/java/com/btk5h/skriptmirror/skript/reflect/ExprJavaCall.java +++ b/src/main/java/com/btk5h/skriptmirror/skript/reflect/ExprJavaCall.java @@ -54,812 +54,812 @@ public class ExprJavaCall implements Expression { - public static int javaCallsMade = 0; - - private static final MethodHandles.Lookup LOOKUP = LookupGetter.getLookup(); - private static final Object[] NO_ARGS = new Object[0]; - private static final Descriptor CONSTRUCTOR_DESCRIPTOR = new Descriptor(null, "", null); - - /** - * A regular expression that captures potential descriptors without actually validating the descriptor. This is done - * both for performance reasons and to provide more helpful error messages when using a malformed descriptor. - * See Descriptor's {@code DESCRIPTOR} field for the extended version of this. - */ - private static final String LITE_DESCRIPTOR = "(\\[[\\w.$]*])?" + - "([^0-9. \\[\\]][^. \\[\\]]*\\b)" + - "(\\[[\\w.$, ]*])?"; - - static { - //noinspection unchecked - Skript.registerExpression(ExprJavaCall.class, Object.class, - ExpressionType.PATTERN_MATCHES_EVERYTHING, - "[(2¦try)] %object%..%string%[\\((1¦[%-objects%])\\)]", - "[(2¦try)] %object%.<" + LITE_DESCRIPTOR + ">[\\((1¦[%-objects%])\\)]", - "[(2¦try)] [a] new %javatype%\\([%-objects%]\\)"); - } - - private enum CallType { - FIELD, METHOD, CONSTRUCTOR; - - @Override - public String toString() { - return name().toLowerCase(); - } - } - - static Throwable lastError; - - private final LRUCache> callSiteCache = new LRUCache<>(8); - - private Script script; - private boolean suppressErrors; - private CallType type; - - private Descriptor staticDescriptor; - private Expression dynamicDescriptor; - - private Expression rawTarget; - private Expression rawArgs; - - private final ExprJavaCall source; - private final Class[] types; - private final Class superType; - - @SuppressWarnings({"unchecked", "unused"}) - public ExprJavaCall() { - this(null, (Class) Object.class); - } - - @SuppressWarnings("unchecked") - @SafeVarargs - private ExprJavaCall(ExprJavaCall source, Class... types) { - this.source = source; - - if (source != null) { - this.script = source.script; - this.suppressErrors = source.suppressErrors; - this.type = source.type; - this.staticDescriptor = source.staticDescriptor; - this.dynamicDescriptor = source.dynamicDescriptor; - this.rawTarget = source.rawTarget; - this.rawArgs = source.rawArgs; - } - - this.types = types; - this.superType = (Class) Utils.getSuperType(types); - } - - @SuppressWarnings("unchecked") - @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, - SkriptParser.ParseResult parseResult) { - - script = SkriptUtil.getCurrentScript(); - suppressErrors = (parseResult.mark & 2) == 2; - - rawTarget = SkriptUtil.defendExpression(exprs[0]); - rawArgs = SkriptUtil.defendExpression(exprs[matchedPattern == 0 ? 2 : 1]); - - if (!SkriptUtil.canInitSafely(rawTarget, rawArgs)) - return false; - - switch (matchedPattern) { - case 0: - type = (parseResult.mark & 1) == 1 ? CallType.METHOD : CallType.FIELD; - dynamicDescriptor = (Expression) exprs[1]; - break; - case 1: - type = (parseResult.mark & 1) == 1 ? CallType.METHOD : CallType.FIELD; - String desc = parseResult.regexes.get(0).group(); - - try { - staticDescriptor = Descriptor.parse(desc, script); - } catch (ImportNotFoundException e) { - Skript.error("The class " + e.getUserType() + " could not be found."); - return false; - } - - if (staticDescriptor == null) { - Skript.error(desc + " is not a valid descriptor."); - return false; - } - - if (staticDescriptor.getJavaClass() == null - && rawTarget instanceof StructImport.ImportHandler) { - staticDescriptor = staticDescriptor.orDefaultClass( - ((StructImport.ImportHandler) rawTarget).getJavaType().getJavaClass() - ); - } - - if (staticDescriptor.getParameterTypes() != null && type.equals(CallType.FIELD)) { - Skript.error("You can't pass parameter types to a field call."); - return false; - } - - if (staticDescriptor.getJavaClass() != null && getCallSite(staticDescriptor).size() == 0) { - String name = staticDescriptor.getName(); - if (Stream.of(staticDescriptor.getJavaClass().getClasses()) - .map(Class::getSimpleName) - .noneMatch(simpleName -> simpleName.equals(name)) - ) { - Skript.error(desc + " refers to a non-existent " + (type.equals(CallType.METHOD) ? "method" : "field")); - return false; - } - } - - break; - case 2: - type = CallType.CONSTRUCTOR; - staticDescriptor = CONSTRUCTOR_DESCRIPTOR; - break; - } - return true; - } - - @Override - public T getSingle(Event e) { - Object target = ObjectWrapper.unwrapIfNecessary(rawTarget.getSingle(e)); - Object[] arguments; - - if (target == null) { - return null; - } - - if (rawArgs != null) { - if (rawArgs instanceof ExpressionList && rawArgs.getAnd()) { - // In a 'comma/and' separated list, manually unwrap each expression and convert nulls to Null wrappers - // This ensures that expressions that return null do not change the arity of the invoked method - arguments = Arrays.stream(((ExpressionList) rawArgs).getExpressions()) - .map(SkriptUtil.unwrapWithEvent(e)) - .map(SkriptMirrorUtil::reifyIfNull) - .toArray(Object[]::new); - } else if (rawArgs.isSingle()) { - // A special case of the above, since a single argument will not be wrapped in a list - // Directly wrap the argument in an array to ensure the unary method is invoked - arguments = new Object[]{SkriptMirrorUtil.reifyIfNull(rawArgs.getSingle(e))}; - } else { - // If the user is using a non-single non-list expression, assume the number of arguments is correct - arguments = rawArgs.getArray(e); - } - } else { - arguments = NO_ARGS; - } - - return invoke(target, arguments, getDescriptor(e)); - } - - @Override - public T[] getArray(Event e) { - T returnValue = getSingle(e); - - if (returnValue == null) { - return JavaUtil.newArray(superType, 0); - } - - T[] arr = JavaUtil.newArray(superType, 1); - arr[0] = returnValue; - - return arr; - } - - @Override - public T[] getAll(Event e) { - return getArray(e); - } - - @Override - public boolean isSingle() { - return true; - } - - @Override - public boolean check(Event e, Checker c, boolean negated) { - return SimpleExpression.check(getAll(e), c, negated, getAnd()); - } - - @Override - public boolean check(Event e, Checker c) { - return SimpleExpression.check(getAll(e), c, false, getAnd()); - } - - @SafeVarargs - @Override - public final Expression getConvertedExpression(Class... to) { - return new ExprJavaCall<>(this, to); - } - - @Override - public Class getReturnType() { - return superType; - } - - @Override - public boolean getAnd() { - return true; - } - - @Override - public boolean setTime(int time) { - return false; - } - - @Override - public int getTime() { - return 0; - } - - @Override - public boolean isDefault() { - return false; - } - - @Override - public Iterator iterator(Event e) { - return new ArrayIterator<>(getAll(e)); - } - - @Override - public boolean isLoopOf(String s) { - return false; - } - - @Override - public Expression getSource() { - return source == null ? this : source; - } - - @Override - public Expression simplify() { - return this; - } - - @Override - public Class[] acceptChange(Changer.ChangeMode mode) { - if (type == CallType.FIELD && - (mode == Changer.ChangeMode.SET || mode == Changer.ChangeMode.DELETE)) { - return new Class[]{Object.class}; - } - return null; - } - - @Override - public void change(Event e, Object[] delta, Changer.ChangeMode mode) { - Object target = ObjectWrapper.unwrapIfNecessary(rawTarget.getSingle(e)); - - if (target == null) { - return; - } - - Object[] args = new Object[1]; - - switch (mode) { - case SET: - args[0] = delta[0]; - break; - case DELETE: - args[0] = Null.getInstance(); - break; - } - - invoke(target, args, getDescriptor(e)); - } - - private void error(Throwable error, String message) { - lastError = error; - - directError(message); - } - - private void error(String message) { - lastError = new JavaCallException(message); - - directError(message); - } - - private void directError(String message) { - if (!suppressErrors) { - Skript.warning(message); - } - } - - private synchronized Collection getCallSite(Descriptor e) { - return callSiteCache.computeIfAbsent(e, this::createCallSite); - } - - private Collection createCallSite(Descriptor descriptor) { - Class javaClass = descriptor.getJavaClass(); - - switch (type) { - case FIELD: - ArrayList methodHandles = new ArrayList<>(); - - JavaUtil.fields(javaClass) - .filter(f -> f.getName().equals(descriptor.getName())) - .map(ExprJavaCall::getAccess) - .filter(Objects::nonNull) - .forEach(field -> { - try { - methodHandles.add(LOOKUP.unreflectGetter(field)); - } catch (IllegalAccessException ex) { - Skript.warning( - String.format("skript-reflect encountered a %s: %s%n" + - "Run Skript with the verbosity 'very high' for the stack trace.", - ex.getClass().getSimpleName(), ex.getMessage())); - - if (Skript.logVeryHigh()) { - StringWriter errors = new StringWriter(); - ex.printStackTrace(new PrintWriter(errors)); - Skript.warning(errors.toString()); - } - } - - try { - methodHandles.add(LOOKUP.unreflectSetter(field)); - } catch (IllegalAccessException ignored) { } - }); - - return methodHandles.stream() - .filter(Objects::nonNull) - .limit(2) - .collect(Collectors.toList()); - case METHOD: - Stream methodStream = JavaUtil.methods(javaClass) - .filter(m -> m.getName().equals(descriptor.getName())); - - if (descriptor.getParameterTypes() != null) { - methodStream = methodStream.filter(m -> Arrays.equals(m.getParameterTypes(), descriptor.getParameterTypes())); - } - - return methodStream - .map(ExprJavaCall::getAccess) - .filter(Objects::nonNull) - .map(JavaUtil.propagateErrors(LOOKUP::unreflect)) - .filter(Objects::nonNull) - .collect(Collectors.toList()); - case CONSTRUCTOR: - return JavaUtil.constructors(javaClass) - .map(ExprJavaCall::getAccess) - .filter(Objects::nonNull) - .map(JavaUtil.propagateErrors(LOOKUP::unreflectConstructor)) - .filter(Objects::nonNull) - .collect(Collectors.toList()); - default: - throw new IllegalStateException(); - } - } - - @SuppressWarnings("unchecked") - private T invoke(Object target, Object[] arguments, Descriptor baseDescriptor) { - javaCallsMade++; - - if (baseDescriptor == null) { - return null; - } - - T returnedValue = null; - Class targetClass = SkriptMirrorUtil.toClassUnwrapJavaTypes(target); - Descriptor descriptor = baseDescriptor.orDefaultClass(targetClass); - - // If a declaring class is explicitly written, check if the target is a subclass - if (!descriptor.getJavaClass().isAssignableFrom(targetClass)) { - error(String.format("Incompatible %s call: %s on %s", - type, descriptor, SkriptMirrorUtil.getDebugName(targetClass))); - return null; - } - - // Copy arguments so that the original array isn't modified by type conversions - // For instance methods, the target of the call must be added to the start of the arguments array - Object[] argumentsCopy; - boolean isStatic = target instanceof JavaType; - if (isStatic) { - argumentsCopy = createStaticArgumentsCopy(arguments); - } else { - argumentsCopy = createInstanceArgumentsCopy(target, arguments); - } - - if (isStatic && type == CallType.FIELD) { - Class[] classes = targetClass.getClasses(); - for (Class clazz : classes) { - if (descriptor.getName().equals(clazz.getSimpleName())) { - return Converters.convert(new JavaType(clazz), types); - } - } - } - - Optional method = findCompatibleMethod(descriptor, argumentsCopy); - - if (!method.isPresent()) { - error(String.format("No matching %s %s: %s%s", - isStatic ? "static" : "non-static", type, descriptor.toString(isStatic), argumentsMessage(arguments))); - - suggestParameters(descriptor, isStatic); - suggestTypo(descriptor, isStatic); - - return null; - } - - MethodHandle mh = method.get(); - - argumentsCopy = convertTypes(mh, argumentsCopy); - - try { - returnedValue = (T) mh.invokeWithArguments(argumentsCopy); - } catch (Throwable throwable) { - error(throwable, String.format("%s %s%s threw a %s: %s%n", - type, descriptor, argumentsMessage(arguments), - throwable.getClass().getSimpleName(), throwable.getMessage())); - } - - if (returnedValue == null) { - return null; - } - - // Wrap the return value if it isn't recognized by Skript - if (superType == Object.class || superType == ObjectWrapper.class) { - returnedValue = (T) ObjectWrapper.wrapIfNecessary(returnedValue, superType == ObjectWrapper.class); - } - - T converted = Converters.convert(returnedValue, types); - - if (converted == null) { - String toClasses = Arrays.stream(types) - .map(SkriptMirrorUtil::getDebugName) - .collect(Collectors.joining(", ")); - error(String.format("%s %s%s returned %s, which could not be converted to %s", - type, descriptor, argumentsMessage(arguments), argumentsToString(returnedValue), toClasses)); - return null; - } - - lastError = null; - - return converted; - } - - private Descriptor getDescriptor(Event e) { - if (staticDescriptor != null) - return staticDescriptor; - - String desc = dynamicDescriptor.getSingle(e); - - if (desc == null) { - error(String.format("Dynamic descriptor %s returned null", dynamicDescriptor.toString(e, false))); - return null; - } - - Descriptor parsedDescriptor; - try { - parsedDescriptor = Descriptor.parse(desc, script); - } catch (ImportNotFoundException ex) { - error("The class" + ex.getUserType() + " could not be found."); - return null; - } - - if (parsedDescriptor == null) { - error(String.format("Invalid dynamic descriptor %s (%s)", dynamicDescriptor.toString(e, false), desc)); - return null; - } - - return parsedDescriptor; - } - - /** - * Returns an array with the same objects as the given array. - */ - private static Object[] createStaticArgumentsCopy(Object[] args) { - return Arrays.copyOf(args, args.length); - } - - /** - * Returns an array with the target parameter in index 0, and the arguments parameter in the following indices. - */ - private static Object[] createInstanceArgumentsCopy(Object target, Object[] arguments) { - Object[] copy = new Object[arguments.length + 1]; - copy[0] = target; - System.arraycopy(arguments, 0, copy, 1, arguments.length); - return copy; - } - - /** - * Returns an optional {@link MethodHandle} that matches the given {@link Descriptor} with the given arguments. - */ - private Optional findCompatibleMethod(Descriptor descriptor, Object[] args) { - return getCallSite(descriptor).stream() - .filter(mh -> matchesArgs(args, mh)) - .min(ExprJavaCall::prioritizeMethodHandles); - } - - /** - * Checks if the given arguments match the arguments for the given {@link MethodHandle}. - */ - private static boolean matchesArgs(Object[] args, MethodHandle mh) { - MethodType mt = mh.type(); - Class[] params = mt.parameterArray(); - int varargsIndex = params.length - 1; - boolean hasVarargs = mh.isVarargsCollector(); - - // Fail early if there is an arity mismatch - // If the method has varargs, make sure args has the minimum arity (exclude the varargs parameter) - if (args.length != params.length - && !(hasVarargs && args.length >= varargsIndex)) { - return false; - } - - for (int i = 0; i < args.length; i++) { - Class param; - boolean loopAtVarargs = hasVarargs && i >= varargsIndex; - - if (loopAtVarargs) { - param = params[varargsIndex].getComponentType(); - } else { - param = params[i]; - } - - Object arg = ObjectWrapper.unwrapIfNecessary(args[i]); - - if (!JavaUtil.canConvert(arg, param)) { - // allow varargs arrays to be spread - if (loopAtVarargs && args.length == params.length && JavaUtil.canConvert(arg, params[i])) { - continue; - } - - return false; - } - } - - return true; - } - - /** - * Method for prioritizing certain {@link MethodHandle}s over others. - * The lesser method handle has priority. - */ - private static int prioritizeMethodHandles(MethodHandle mh1, MethodHandle mh2) { - boolean isMh1Varargs = mh1.isVarargsCollector(); - boolean isMh2Varargs = mh2.isVarargsCollector(); - - if (isMh1Varargs ^ isMh2Varargs) { - return isMh1Varargs ? 1 : -1; - } - - return 0; - } - - private static Object[] convertTypes(MethodHandle mh, Object[] args) { - Class[] params = mh.type().parameterArray(); - int varargsIndex = params.length - 1; - boolean hasVarargs = mh.isVarargsCollector(); - - for (int i = 0; i < args.length; i++) { - boolean loopAtVarargs = hasVarargs && i >= varargsIndex; - - // varargs parameters are always arrays, but the method handle expects the array to be spread before called - Class param; - if (loopAtVarargs) { - param = params[varargsIndex].getComponentType(); - } else { - param = params[i]; - } - - args[i] = ObjectWrapper.unwrapIfNecessary(args[i]); - - // spread varargs arrays - if (loopAtVarargs && args.length == params.length && params[i].isInstance(args[i])) { - Object varargsArray = args[i]; - int varargsLength = Array.getLength(varargsArray); - - args = Arrays.copyOf(args, args.length - 1 + varargsLength); - - //noinspection SuspiciousSystemArraycopy - System.arraycopy(varargsArray, 0, args, varargsIndex, varargsLength); - } - - args[i] = JavaUtil.convert(args[i], param); - } - - return args; - } - - private void suggestParameters(Descriptor descriptor, boolean isStatic) { - if (!(type == CallType.CONSTRUCTOR || type == CallType.METHOD)) { - return; - } - - String guess = descriptor.getName(); - Class javaClass = descriptor.getJavaClass(); - - Stream members = getExecutables(javaClass); - - List matches = members - .filter(e -> e.getName().equals(guess)) - .filter(e -> isStatic == isStatic(e)) - .map(Executable::getParameters) - .map(params -> - Arrays.stream(params) - .map(Parameter::getType) - .map(Class::getTypeName) - .collect(Collectors.joining(",")) - ) - .collect(Collectors.toList()); - - if (!matches.isEmpty()) { - directError("Did you pass the wrong parameters? Here are the parameter signatures for the " - + (isStatic ? "static" : "non-static") + " " + type + " " + guess + ":"); - matches.forEach(parameterList -> directError(String.format("* %s(%s)", guess, parameterList))); - } - } - - /** - * Sends fields / methods with names similar to the called field / method. - * Uses {@link StringSimilarity#compare(String, String, int)} for string similarity checks. - */ - private void suggestTypo(Descriptor descriptor, boolean isStatic) { - String guess = descriptor.getName(); - Class javaClass = descriptor.getJavaClass(); - - Stream members = getMembers(javaClass); - - List matchingMembers = new ArrayList<>(); - - outer: for (Member member : members.collect(Collectors.toList())) { - String name = member.getName(); - if (name.equals(guess) && isStatic == isStatic(member)) - continue; - // Distinct - for (Member loopMember : matchingMembers) { - if (loopMember.getName().equals(name)) - continue outer; - } - StringSimilarity.Result result = StringSimilarity.compare(guess, name, 3); - if (result == null) - continue; - matchingMembers.add(member); - } - - if (!matchingMembers.isEmpty()) { - directError("Did you misspell the " + type + "? You may have meant to type one of the following:"); - for (Member member : matchingMembers) { - String className = SkriptMirrorUtil.getDebugName(javaClass); - String staticString = isStatic(member) ? className : "%" + className + "%"; - directError("* " + staticString + "." + member.getName()); - } - } - } - - private Stream getExecutables(Class javaClass) { - switch (type) { - case METHOD: - return JavaUtil.methods(javaClass); - case CONSTRUCTOR: - return JavaUtil.constructors(javaClass); - default: - throw new IllegalStateException(); - } - } - - private Stream getMembers(Class javaClass) { - switch (type) { - case FIELD: - return JavaUtil.fields(javaClass); - case METHOD: - return JavaUtil.methods(javaClass); - case CONSTRUCTOR: - return JavaUtil.constructors(javaClass); - default: - throw new IllegalStateException(); - } - } - - private String argumentsMessage(Object... arguments) { - if (type == CallType.FIELD) { - return ""; - } - - if (arguments.length == 0) { - return " called without arguments"; - } - - return " called with (" + argumentsToString(arguments) + ")"; - } - - private static String argumentsToString(Object... arguments) { - return Arrays.stream(arguments) - .map(arg -> String.format("%s (%s)", - Classes.toString(arg), SkriptMirrorUtil.getDebugName(SkriptMirrorUtil.getClass(arg)))) - .collect(Collectors.joining(", ")); - } - - /** - * Tries to invoke {@link AccessibleObject#setAccessible(boolean)} on the given member, - * returning the given member if successful, and null otherwise.
- * This method also attempts to make the super member of the given member accessible, - * if making the given member accessible failed.
- * If the super member was successfully made accessible, the super member is returned. - */ - @SuppressWarnings("unchecked") - @Nullable - private static T getAccess(T member) { - try { - if (!member.isAccessible()) - member.setAccessible(true); - return member; - } catch (RuntimeException e) { - // InaccessibleObjectException exists in Java 9+ only - if (e instanceof SecurityException || e.getClass().getName().equals("java.lang.reflect.InaccessibleObjectException")) { - Member superMember = getSuperMember((Member) member); - return superMember != null ? getAccess((T) superMember) : null; - } - throw e; - } - } - - /** - * Gets the super member of the given member, using {@link #getSuperMember(Method, Class)}.
- * This will always return null if the given member is not a {@link Method}, or if the given member is static. - */ - @Nullable - private static Member getSuperMember(Member member) { - if (!(member instanceof Method)) - return null; - Method method = (Method) member; - if (isStatic(method)) - return null; - - return getSuperMember(method, method.getDeclaringClass()); - } - - /** - * Gets the super method of the given method, checking in the given class.
- * This method checks all declared methods of the given class, and returns a method - * if its name and parameter types match.
- * If no such method can be found, it checks in all of its super classes (interfaces and super class).
- * If no super method can be found here, null is returned. - */ - @Nullable - private static Method getSuperMember(Method method, Class declaringClass) { - if (method.getDeclaringClass() != declaringClass) { - for (Method loopMethod : declaringClass.getDeclaredMethods()) { - if (method.getName().equals(loopMethod.getName()) - && Arrays.equals(method.getParameterTypes(), loopMethod.getParameterTypes())) { - return loopMethod; - } - } - } - - List> superClasses = new ArrayList<>(); - if (declaringClass.getSuperclass() != null) - superClasses.add(declaringClass.getSuperclass()); - superClasses.addAll(Arrays.asList(declaringClass.getInterfaces())); - - for (Class superClass : superClasses) { - Method superMethod = getSuperMember(method, superClass); - if (superMethod != null) - return superMethod; - } - - return null; - } - - private static boolean isStatic(Member member) { - return (member.getModifiers() & Modifier.STATIC) != 0; - } - - @Override - public String toString(Event e, boolean debug) { - switch (type) { - case FIELD: - return "" + rawTarget.toString(e, debug) + "." + staticDescriptor.getName(); - case METHOD: - return "" + rawTarget.toString(e, debug) + "." + staticDescriptor.getName() + "(" + - (rawArgs == null ? "" : rawArgs.toString(e, debug)) + ")"; - case CONSTRUCTOR: - return "new " + rawTarget.toString(e, debug) + "(" + (rawArgs == null ? "" : rawArgs.toString(e, debug)) + ")"; - } - return null; - } - - @Override - public String toString() { - return toString(null, false); - } + public static int javaCallsMade = 0; + + private static final MethodHandles.Lookup LOOKUP = LookupGetter.getLookup(); + private static final Object[] NO_ARGS = new Object[0]; + private static final Descriptor CONSTRUCTOR_DESCRIPTOR = new Descriptor(null, "", null); + + /** + * A regular expression that captures potential descriptors without actually validating the descriptor. This is done + * both for performance reasons and to provide more helpful error messages when using a malformed descriptor. + * See Descriptor's {@code DESCRIPTOR} field for the extended version of this. + */ + private static final String LITE_DESCRIPTOR = "(\\[[\\w.$]*])?" + + "([^0-9. \\[\\]][^. \\[\\]]*\\b)" + + "(\\[[\\w.$, ]*])?"; + + static { + //noinspection unchecked + Skript.registerExpression(ExprJavaCall.class, Object.class, + ExpressionType.PATTERN_MATCHES_EVERYTHING, + "[(2¦try)] %object%..%string%[\\((1¦[%-objects%])\\)]", + "[(2¦try)] %object%.<" + LITE_DESCRIPTOR + ">[\\((1¦[%-objects%])\\)]", + "[(2¦try)] [a] new %javatype%\\([%-objects%]\\)"); + } + + private enum CallType { + FIELD, METHOD, CONSTRUCTOR; + + @Override + public String toString() { + return name().toLowerCase(); + } + } + + static Throwable lastError; + + private final LRUCache> callSiteCache = new LRUCache<>(8); + + private Script script; + private boolean suppressErrors; + private CallType type; + + private Descriptor staticDescriptor; + private Expression dynamicDescriptor; + + private Expression rawTarget; + private Expression rawArgs; + + private final ExprJavaCall source; + private final Class[] types; + private final Class superType; + + @SuppressWarnings({"unchecked", "unused"}) + public ExprJavaCall() { + this(null, (Class) Object.class); + } + + @SuppressWarnings("unchecked") + @SafeVarargs + private ExprJavaCall(ExprJavaCall source, Class... types) { + this.source = source; + + if (source != null) { + this.script = source.script; + this.suppressErrors = source.suppressErrors; + this.type = source.type; + this.staticDescriptor = source.staticDescriptor; + this.dynamicDescriptor = source.dynamicDescriptor; + this.rawTarget = source.rawTarget; + this.rawArgs = source.rawArgs; + } + + this.types = types; + this.superType = (Class) Utils.getSuperType(types); + } + + @SuppressWarnings("unchecked") + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, + SkriptParser.ParseResult parseResult) { + + script = SkriptUtil.getCurrentScript(); + suppressErrors = (parseResult.mark & 2) == 2; + + rawTarget = SkriptUtil.defendExpression(exprs[0]); + rawArgs = SkriptUtil.defendExpression(exprs[matchedPattern == 0 ? 2 : 1]); + + if (!SkriptUtil.canInitSafely(rawTarget, rawArgs)) + return false; + + switch (matchedPattern) { + case 0: + type = (parseResult.mark & 1) == 1 ? CallType.METHOD : CallType.FIELD; + dynamicDescriptor = (Expression) exprs[1]; + break; + case 1: + type = (parseResult.mark & 1) == 1 ? CallType.METHOD : CallType.FIELD; + String desc = parseResult.regexes.get(0).group(); + + try { + staticDescriptor = Descriptor.parse(desc, script); + } catch (ImportNotFoundException e) { + Skript.error("The class " + e.getUserType() + " could not be found."); + return false; + } + + if (staticDescriptor == null) { + Skript.error(desc + " is not a valid descriptor."); + return false; + } + + if (staticDescriptor.getJavaClass() == null + && rawTarget instanceof StructImport.ImportHandler) { + staticDescriptor = staticDescriptor.orDefaultClass( + ((StructImport.ImportHandler) rawTarget).getJavaType().getJavaClass() + ); + } + + if (staticDescriptor.getParameterTypes() != null && type.equals(CallType.FIELD)) { + Skript.error("You can't pass parameter types to a field call."); + return false; + } + + if (staticDescriptor.getJavaClass() != null && getCallSite(staticDescriptor).size() == 0) { + String name = staticDescriptor.getName(); + if (Stream.of(staticDescriptor.getJavaClass().getClasses()) + .map(Class::getSimpleName) + .noneMatch(simpleName -> simpleName.equals(name)) + ) { + Skript.error(desc + " refers to a non-existent " + (type.equals(CallType.METHOD) ? "method" : "field")); + return false; + } + } + + break; + case 2: + type = CallType.CONSTRUCTOR; + staticDescriptor = CONSTRUCTOR_DESCRIPTOR; + break; + } + return true; + } + + @Override + public T getSingle(Event e) { + Object target = ObjectWrapper.unwrapIfNecessary(rawTarget.getSingle(e)); + Object[] arguments; + + if (target == null) { + return null; + } + + if (rawArgs != null) { + if (rawArgs instanceof ExpressionList && rawArgs.getAnd()) { + // In a 'comma/and' separated list, manually unwrap each expression and convert nulls to Null wrappers + // This ensures that expressions that return null do not change the arity of the invoked method + arguments = Arrays.stream(((ExpressionList) rawArgs).getExpressions()) + .map(SkriptUtil.unwrapWithEvent(e)) + .map(SkriptMirrorUtil::reifyIfNull) + .toArray(Object[]::new); + } else if (rawArgs.isSingle()) { + // A special case of the above, since a single argument will not be wrapped in a list + // Directly wrap the argument in an array to ensure the unary method is invoked + arguments = new Object[]{SkriptMirrorUtil.reifyIfNull(rawArgs.getSingle(e))}; + } else { + // If the user is using a non-single non-list expression, assume the number of arguments is correct + arguments = rawArgs.getArray(e); + } + } else { + arguments = NO_ARGS; + } + + return invoke(target, arguments, getDescriptor(e)); + } + + @Override + public T[] getArray(Event e) { + T returnValue = getSingle(e); + + if (returnValue == null) { + return JavaUtil.newArray(superType, 0); + } + + T[] arr = JavaUtil.newArray(superType, 1); + arr[0] = returnValue; + + return arr; + } + + @Override + public T[] getAll(Event e) { + return getArray(e); + } + + @Override + public boolean isSingle() { + return true; + } + + @Override + public boolean check(Event e, Checker c, boolean negated) { + return SimpleExpression.check(getAll(e), c, negated, getAnd()); + } + + @Override + public boolean check(Event e, Checker c) { + return SimpleExpression.check(getAll(e), c, false, getAnd()); + } + + @SafeVarargs + @Override + public final Expression getConvertedExpression(Class... to) { + return new ExprJavaCall<>(this, to); + } + + @Override + public Class getReturnType() { + return superType; + } + + @Override + public boolean getAnd() { + return true; + } + + @Override + public boolean setTime(int time) { + return false; + } + + @Override + public int getTime() { + return 0; + } + + @Override + public boolean isDefault() { + return false; + } + + @Override + public Iterator iterator(Event e) { + return new ArrayIterator<>(getAll(e)); + } + + @Override + public boolean isLoopOf(String s) { + return false; + } + + @Override + public Expression getSource() { + return source == null ? this : source; + } + + @Override + public Expression simplify() { + return this; + } + + @Override + public Class[] acceptChange(Changer.ChangeMode mode) { + if (type == CallType.FIELD && + (mode == Changer.ChangeMode.SET || mode == Changer.ChangeMode.DELETE)) { + return new Class[]{Object.class}; + } + return null; + } + + @Override + public void change(Event e, Object[] delta, Changer.ChangeMode mode) { + Object target = ObjectWrapper.unwrapIfNecessary(rawTarget.getSingle(e)); + + if (target == null) { + return; + } + + Object[] args = new Object[1]; + + switch (mode) { + case SET: + args[0] = delta[0]; + break; + case DELETE: + args[0] = Null.getInstance(); + break; + } + + invoke(target, args, getDescriptor(e)); + } + + private void error(Throwable error, String message) { + lastError = error; + + directError(message); + } + + private void error(String message) { + lastError = new JavaCallException(message); + + directError(message); + } + + private void directError(String message) { + if (!suppressErrors) { + Skript.warning(message); + } + } + + private synchronized Collection getCallSite(Descriptor e) { + return callSiteCache.computeIfAbsent(e, this::createCallSite); + } + + private Collection createCallSite(Descriptor descriptor) { + Class javaClass = descriptor.getJavaClass(); + + switch (type) { + case FIELD: + ArrayList methodHandles = new ArrayList<>(); + + JavaUtil.fields(javaClass) + .filter(f -> f.getName().equals(descriptor.getName())) + .map(ExprJavaCall::getAccess) + .filter(Objects::nonNull) + .forEach(field -> { + try { + methodHandles.add(LOOKUP.unreflectGetter(field)); + } catch (IllegalAccessException ex) { + Skript.warning( + String.format("skript-reflect encountered a %s: %s%n" + + "Run Skript with the verbosity 'very high' for the stack trace.", + ex.getClass().getSimpleName(), ex.getMessage())); + + if (Skript.logVeryHigh()) { + StringWriter errors = new StringWriter(); + ex.printStackTrace(new PrintWriter(errors)); + Skript.warning(errors.toString()); + } + } + + try { + methodHandles.add(LOOKUP.unreflectSetter(field)); + } catch (IllegalAccessException ignored) { } + }); + + return methodHandles.stream() + .filter(Objects::nonNull) + .limit(2) + .collect(Collectors.toList()); + case METHOD: + Stream methodStream = JavaUtil.methods(javaClass) + .filter(m -> m.getName().equals(descriptor.getName())); + + if (descriptor.getParameterTypes() != null) { + methodStream = methodStream.filter(m -> Arrays.equals(m.getParameterTypes(), descriptor.getParameterTypes())); + } + + return methodStream + .map(ExprJavaCall::getAccess) + .filter(Objects::nonNull) + .map(JavaUtil.propagateErrors(LOOKUP::unreflect)) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + case CONSTRUCTOR: + return JavaUtil.constructors(javaClass) + .map(ExprJavaCall::getAccess) + .filter(Objects::nonNull) + .map(JavaUtil.propagateErrors(LOOKUP::unreflectConstructor)) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + default: + throw new IllegalStateException(); + } + } + + @SuppressWarnings("unchecked") + private T invoke(Object target, Object[] arguments, Descriptor baseDescriptor) { + javaCallsMade++; + + if (baseDescriptor == null) { + return null; + } + + T returnedValue = null; + Class targetClass = SkriptMirrorUtil.toClassUnwrapJavaTypes(target); + Descriptor descriptor = baseDescriptor.orDefaultClass(targetClass); + + // If a declaring class is explicitly written, check if the target is a subclass + if (!descriptor.getJavaClass().isAssignableFrom(targetClass)) { + error(String.format("Incompatible %s call: %s on %s", + type, descriptor, SkriptMirrorUtil.getDebugName(targetClass))); + return null; + } + + // Copy arguments so that the original array isn't modified by type conversions + // For instance methods, the target of the call must be added to the start of the arguments array + Object[] argumentsCopy; + boolean isStatic = target instanceof JavaType; + if (isStatic) { + argumentsCopy = createStaticArgumentsCopy(arguments); + } else { + argumentsCopy = createInstanceArgumentsCopy(target, arguments); + } + + if (isStatic && type == CallType.FIELD) { + Class[] classes = targetClass.getClasses(); + for (Class clazz : classes) { + if (descriptor.getName().equals(clazz.getSimpleName())) { + return Converters.convert(new JavaType(clazz), types); + } + } + } + + Optional method = findCompatibleMethod(descriptor, argumentsCopy); + + if (!method.isPresent()) { + error(String.format("No matching %s %s: %s%s", + isStatic ? "static" : "non-static", type, descriptor.toString(isStatic), argumentsMessage(arguments))); + + suggestParameters(descriptor, isStatic); + suggestTypo(descriptor, isStatic); + + return null; + } + + MethodHandle mh = method.get(); + + argumentsCopy = convertTypes(mh, argumentsCopy); + + try { + returnedValue = (T) mh.invokeWithArguments(argumentsCopy); + } catch (Throwable throwable) { + error(throwable, String.format("%s %s%s threw a %s: %s%n", + type, descriptor, argumentsMessage(arguments), + throwable.getClass().getSimpleName(), throwable.getMessage())); + } + + if (returnedValue == null) { + return null; + } + + // Wrap the return value if it isn't recognized by Skript + if (superType == Object.class || superType == ObjectWrapper.class) { + returnedValue = (T) ObjectWrapper.wrapIfNecessary(returnedValue, superType == ObjectWrapper.class); + } + + T converted = Converters.convert(returnedValue, types); + + if (converted == null) { + String toClasses = Arrays.stream(types) + .map(SkriptMirrorUtil::getDebugName) + .collect(Collectors.joining(", ")); + error(String.format("%s %s%s returned %s, which could not be converted to %s", + type, descriptor, argumentsMessage(arguments), argumentsToString(returnedValue), toClasses)); + return null; + } + + lastError = null; + + return converted; + } + + private Descriptor getDescriptor(Event e) { + if (staticDescriptor != null) + return staticDescriptor; + + String desc = dynamicDescriptor.getSingle(e); + + if (desc == null) { + error(String.format("Dynamic descriptor %s returned null", dynamicDescriptor.toString(e, false))); + return null; + } + + Descriptor parsedDescriptor; + try { + parsedDescriptor = Descriptor.parse(desc, script); + } catch (ImportNotFoundException ex) { + error("The class" + ex.getUserType() + " could not be found."); + return null; + } + + if (parsedDescriptor == null) { + error(String.format("Invalid dynamic descriptor %s (%s)", dynamicDescriptor.toString(e, false), desc)); + return null; + } + + return parsedDescriptor; + } + + /** + * Returns an array with the same objects as the given array. + */ + private static Object[] createStaticArgumentsCopy(Object[] args) { + return Arrays.copyOf(args, args.length); + } + + /** + * Returns an array with the target parameter in index 0, and the arguments parameter in the following indices. + */ + private static Object[] createInstanceArgumentsCopy(Object target, Object[] arguments) { + Object[] copy = new Object[arguments.length + 1]; + copy[0] = target; + System.arraycopy(arguments, 0, copy, 1, arguments.length); + return copy; + } + + /** + * Returns an optional {@link MethodHandle} that matches the given {@link Descriptor} with the given arguments. + */ + private Optional findCompatibleMethod(Descriptor descriptor, Object[] args) { + return getCallSite(descriptor).stream() + .filter(mh -> matchesArgs(args, mh)) + .min(ExprJavaCall::prioritizeMethodHandles); + } + + /** + * Checks if the given arguments match the arguments for the given {@link MethodHandle}. + */ + private static boolean matchesArgs(Object[] args, MethodHandle mh) { + MethodType mt = mh.type(); + Class[] params = mt.parameterArray(); + int varargsIndex = params.length - 1; + boolean hasVarargs = mh.isVarargsCollector(); + + // Fail early if there is an arity mismatch + // If the method has varargs, make sure args has the minimum arity (exclude the varargs parameter) + if (args.length != params.length + && !(hasVarargs && args.length >= varargsIndex)) { + return false; + } + + for (int i = 0; i < args.length; i++) { + Class param; + boolean loopAtVarargs = hasVarargs && i >= varargsIndex; + + if (loopAtVarargs) { + param = params[varargsIndex].getComponentType(); + } else { + param = params[i]; + } + + Object arg = ObjectWrapper.unwrapIfNecessary(args[i]); + + if (!JavaUtil.canConvert(arg, param)) { + // allow varargs arrays to be spread + if (loopAtVarargs && args.length == params.length && JavaUtil.canConvert(arg, params[i])) { + continue; + } + + return false; + } + } + + return true; + } + + /** + * Method for prioritizing certain {@link MethodHandle}s over others. + * The lesser method handle has priority. + */ + private static int prioritizeMethodHandles(MethodHandle mh1, MethodHandle mh2) { + boolean isMh1Varargs = mh1.isVarargsCollector(); + boolean isMh2Varargs = mh2.isVarargsCollector(); + + if (isMh1Varargs ^ isMh2Varargs) { + return isMh1Varargs ? 1 : -1; + } + + return 0; + } + + private static Object[] convertTypes(MethodHandle mh, Object[] args) { + Class[] params = mh.type().parameterArray(); + int varargsIndex = params.length - 1; + boolean hasVarargs = mh.isVarargsCollector(); + + for (int i = 0; i < args.length; i++) { + boolean loopAtVarargs = hasVarargs && i >= varargsIndex; + + // varargs parameters are always arrays, but the method handle expects the array to be spread before called + Class param; + if (loopAtVarargs) { + param = params[varargsIndex].getComponentType(); + } else { + param = params[i]; + } + + args[i] = ObjectWrapper.unwrapIfNecessary(args[i]); + + // spread varargs arrays + if (loopAtVarargs && args.length == params.length && params[i].isInstance(args[i])) { + Object varargsArray = args[i]; + int varargsLength = Array.getLength(varargsArray); + + args = Arrays.copyOf(args, args.length - 1 + varargsLength); + + //noinspection SuspiciousSystemArraycopy + System.arraycopy(varargsArray, 0, args, varargsIndex, varargsLength); + } + + args[i] = JavaUtil.convert(args[i], param); + } + + return args; + } + + private void suggestParameters(Descriptor descriptor, boolean isStatic) { + if (!(type == CallType.CONSTRUCTOR || type == CallType.METHOD)) { + return; + } + + String guess = descriptor.getName(); + Class javaClass = descriptor.getJavaClass(); + + Stream members = getExecutables(javaClass); + + List matches = members + .filter(e -> e.getName().equals(guess)) + .filter(e -> isStatic == isStatic(e)) + .map(Executable::getParameters) + .map(params -> + Arrays.stream(params) + .map(Parameter::getType) + .map(Class::getTypeName) + .collect(Collectors.joining(",")) + ) + .collect(Collectors.toList()); + + if (!matches.isEmpty()) { + directError("Did you pass the wrong parameters? Here are the parameter signatures for the " + + (isStatic ? "static" : "non-static") + " " + type + " " + guess + ":"); + matches.forEach(parameterList -> directError(String.format("* %s(%s)", guess, parameterList))); + } + } + + /** + * Sends fields / methods with names similar to the called field / method. + * Uses {@link StringSimilarity#compare(String, String, int)} for string similarity checks. + */ + private void suggestTypo(Descriptor descriptor, boolean isStatic) { + String guess = descriptor.getName(); + Class javaClass = descriptor.getJavaClass(); + + Stream members = getMembers(javaClass); + + List matchingMembers = new ArrayList<>(); + + outer: for (Member member : members.collect(Collectors.toList())) { + String name = member.getName(); + if (name.equals(guess) && isStatic == isStatic(member)) + continue; + // Distinct + for (Member loopMember : matchingMembers) { + if (loopMember.getName().equals(name)) + continue outer; + } + StringSimilarity.Result result = StringSimilarity.compare(guess, name, 3); + if (result == null) + continue; + matchingMembers.add(member); + } + + if (!matchingMembers.isEmpty()) { + directError("Did you misspell the " + type + "? You may have meant to type one of the following:"); + for (Member member : matchingMembers) { + String className = SkriptMirrorUtil.getDebugName(javaClass); + String staticString = isStatic(member) ? className : "%" + className + "%"; + directError("* " + staticString + "." + member.getName()); + } + } + } + + private Stream getExecutables(Class javaClass) { + switch (type) { + case METHOD: + return JavaUtil.methods(javaClass); + case CONSTRUCTOR: + return JavaUtil.constructors(javaClass); + default: + throw new IllegalStateException(); + } + } + + private Stream getMembers(Class javaClass) { + switch (type) { + case FIELD: + return JavaUtil.fields(javaClass); + case METHOD: + return JavaUtil.methods(javaClass); + case CONSTRUCTOR: + return JavaUtil.constructors(javaClass); + default: + throw new IllegalStateException(); + } + } + + private String argumentsMessage(Object... arguments) { + if (type == CallType.FIELD) { + return ""; + } + + if (arguments.length == 0) { + return " called without arguments"; + } + + return " called with (" + argumentsToString(arguments) + ")"; + } + + private static String argumentsToString(Object... arguments) { + return Arrays.stream(arguments) + .map(arg -> String.format("%s (%s)", + Classes.toString(arg), SkriptMirrorUtil.getDebugName(SkriptMirrorUtil.getClass(arg)))) + .collect(Collectors.joining(", ")); + } + + /** + * Tries to invoke {@link AccessibleObject#setAccessible(boolean)} on the given member, + * returning the given member if successful, and null otherwise.
+ * This method also attempts to make the super member of the given member accessible, + * if making the given member accessible failed.
+ * If the super member was successfully made accessible, the super member is returned. + */ + @SuppressWarnings("unchecked") + @Nullable + private static T getAccess(T member) { + try { + if (!member.isAccessible()) + member.setAccessible(true); + return member; + } catch (RuntimeException e) { + // InaccessibleObjectException exists in Java 9+ only + if (e instanceof SecurityException || e.getClass().getName().equals("java.lang.reflect.InaccessibleObjectException")) { + Member superMember = getSuperMember((Member) member); + return superMember != null ? getAccess((T) superMember) : null; + } + throw e; + } + } + + /** + * Gets the super member of the given member, using {@link #getSuperMember(Method, Class)}.
+ * This will always return null if the given member is not a {@link Method}, or if the given member is static. + */ + @Nullable + private static Member getSuperMember(Member member) { + if (!(member instanceof Method)) + return null; + Method method = (Method) member; + if (isStatic(method)) + return null; + + return getSuperMember(method, method.getDeclaringClass()); + } + + /** + * Gets the super method of the given method, checking in the given class.
+ * This method checks all declared methods of the given class, and returns a method + * if its name and parameter types match.
+ * If no such method can be found, it checks in all of its super classes (interfaces and super class).
+ * If no super method can be found here, null is returned. + */ + @Nullable + private static Method getSuperMember(Method method, Class declaringClass) { + if (method.getDeclaringClass() != declaringClass) { + for (Method loopMethod : declaringClass.getDeclaredMethods()) { + if (method.getName().equals(loopMethod.getName()) + && Arrays.equals(method.getParameterTypes(), loopMethod.getParameterTypes())) { + return loopMethod; + } + } + } + + List> superClasses = new ArrayList<>(); + if (declaringClass.getSuperclass() != null) + superClasses.add(declaringClass.getSuperclass()); + superClasses.addAll(Arrays.asList(declaringClass.getInterfaces())); + + for (Class superClass : superClasses) { + Method superMethod = getSuperMember(method, superClass); + if (superMethod != null) + return superMethod; + } + + return null; + } + + private static boolean isStatic(Member member) { + return (member.getModifiers() & Modifier.STATIC) != 0; + } + + @Override + public String toString(Event e, boolean debug) { + switch (type) { + case FIELD: + return "" + rawTarget.toString(e, debug) + "." + staticDescriptor.getName(); + case METHOD: + return "" + rawTarget.toString(e, debug) + "." + staticDescriptor.getName() + "(" + + (rawArgs == null ? "" : rawArgs.toString(e, debug)) + ")"; + case CONSTRUCTOR: + return "new " + rawTarget.toString(e, debug) + "(" + (rawArgs == null ? "" : rawArgs.toString(e, debug)) + ")"; + } + return null; + } + + @Override + public String toString() { + return toString(null, false); + } } diff --git a/src/main/java/com/btk5h/skriptmirror/skript/reflect/ExprJavaError.java b/src/main/java/com/btk5h/skriptmirror/skript/reflect/ExprJavaError.java index a7d53b16..1f064570 100644 --- a/src/main/java/com/btk5h/skriptmirror/skript/reflect/ExprJavaError.java +++ b/src/main/java/com/btk5h/skriptmirror/skript/reflect/ExprJavaError.java @@ -9,34 +9,34 @@ import org.bukkit.event.Event; public class ExprJavaError extends SimpleExpression { - static { - Skript.registerExpression(ExprJavaError.class, Throwable.class, ExpressionType.SIMPLE, - "[the] [last] [java] (throwable|exception|error)"); - } + static { + Skript.registerExpression(ExprJavaError.class, Throwable.class, ExpressionType.SIMPLE, + "[the] [last] [java] (throwable|exception|error)"); + } - @Override - protected Throwable[] get(Event e) { - return new Throwable[]{ExprJavaCall.lastError}; - } + @Override + protected Throwable[] get(Event e) { + return new Throwable[]{ExprJavaCall.lastError}; + } - @Override - public boolean isSingle() { - return true; - } + @Override + public boolean isSingle() { + return true; + } - @Override - public Class getReturnType() { - return Throwable.class; - } + @Override + public Class getReturnType() { + return Throwable.class; + } - @Override - public String toString(Event e, boolean debug) { - return "last java error"; - } + @Override + public String toString(Event e, boolean debug) { + return "last java error"; + } - @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, - SkriptParser.ParseResult parseResult) { - return true; - } + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, + SkriptParser.ParseResult parseResult) { + return true; + } } diff --git a/src/main/java/com/btk5h/skriptmirror/skript/reflect/ExprJavaType.java b/src/main/java/com/btk5h/skriptmirror/skript/reflect/ExprJavaType.java index afc81209..164d0d69 100644 --- a/src/main/java/com/btk5h/skriptmirror/skript/reflect/ExprJavaType.java +++ b/src/main/java/com/btk5h/skriptmirror/skript/reflect/ExprJavaType.java @@ -11,48 +11,48 @@ import org.bukkit.event.Event; public class ExprJavaType extends SimpleExpression { - static { - Skript.registerExpression(ExprJavaType.class, JavaType.class, ExpressionType.COMBINED, - "[the] [java] class %string%"); - } - - private Expression className; - - @Override - protected JavaType[] get(Event e) { - String cls = className.getSingle(e); - - if (cls == null) { - return null; - } - - try { - return new JavaType[]{new JavaType(LibraryLoader.getClassLoader().loadClass(cls))}; - } catch (ClassNotFoundException ex) { - return null; - } - } - - @Override - public boolean isSingle() { - return true; - } - - @Override - public Class getReturnType() { - return JavaType.class; - } - - @Override - public String toString(Event e, boolean debug) { - return "class " + className.toString(e, debug); - } - - @SuppressWarnings("unchecked") - @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, - SkriptParser.ParseResult parseResult) { - className = (Expression) exprs[0]; - return true; - } + static { + Skript.registerExpression(ExprJavaType.class, JavaType.class, ExpressionType.COMBINED, + "[the] [java] class %string%"); + } + + private Expression className; + + @Override + protected JavaType[] get(Event e) { + String cls = className.getSingle(e); + + if (cls == null) { + return null; + } + + try { + return new JavaType[]{new JavaType(LibraryLoader.getClassLoader().loadClass(cls))}; + } catch (ClassNotFoundException ex) { + return null; + } + } + + @Override + public boolean isSingle() { + return true; + } + + @Override + public Class getReturnType() { + return JavaType.class; + } + + @Override + public String toString(Event e, boolean debug) { + return "class " + className.toString(e, debug); + } + + @SuppressWarnings("unchecked") + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, + SkriptParser.ParseResult parseResult) { + className = (Expression) exprs[0]; + return true; + } } diff --git a/src/main/java/com/btk5h/skriptmirror/skript/reflect/ExprJavaTypeOf.java b/src/main/java/com/btk5h/skriptmirror/skript/reflect/ExprJavaTypeOf.java index 855de993..593224ba 100644 --- a/src/main/java/com/btk5h/skriptmirror/skript/reflect/ExprJavaTypeOf.java +++ b/src/main/java/com/btk5h/skriptmirror/skript/reflect/ExprJavaTypeOf.java @@ -13,40 +13,40 @@ import java.util.Arrays; public class ExprJavaTypeOf extends SimpleExpression { - static { - PropertyExpression.register(ExprJavaTypeOf.class, JavaType.class, "[java] class[es]", "objects"); - } - - private Expression target; - - @Override - protected JavaType[] get(Event e) { - return Arrays.stream(target.getArray(e)) - .map(SkriptMirrorUtil::getClass) - .map(JavaType::new) - .toArray(JavaType[]::new); - } - - @Override - public boolean isSingle() { - return target.isSingle(); - } - - @Override - public Class getReturnType() { - return JavaType.class; - } - - @Override - public String toString(Event e, boolean debug) { - return "class of " + target.toString(e, debug); - } - - @SuppressWarnings("unchecked") - @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, - SkriptParser.ParseResult parseResult) { - target = SkriptUtil.defendExpression(exprs[0]); - return SkriptUtil.canInitSafely(target); - } + static { + PropertyExpression.register(ExprJavaTypeOf.class, JavaType.class, "[java] class[es]", "objects"); + } + + private Expression target; + + @Override + protected JavaType[] get(Event e) { + return Arrays.stream(target.getArray(e)) + .map(SkriptMirrorUtil::getClass) + .map(JavaType::new) + .toArray(JavaType[]::new); + } + + @Override + public boolean isSingle() { + return target.isSingle(); + } + + @Override + public Class getReturnType() { + return JavaType.class; + } + + @Override + public String toString(Event e, boolean debug) { + return "class of " + target.toString(e, debug); + } + + @SuppressWarnings("unchecked") + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, + SkriptParser.ParseResult parseResult) { + target = SkriptUtil.defendExpression(exprs[0]); + return SkriptUtil.canInitSafely(target); + } } diff --git a/src/main/java/com/btk5h/skriptmirror/skript/reflect/ExprMemberNames.java b/src/main/java/com/btk5h/skriptmirror/skript/reflect/ExprMemberNames.java index 9bccb141..8d5d2ae6 100644 --- a/src/main/java/com/btk5h/skriptmirror/skript/reflect/ExprMemberNames.java +++ b/src/main/java/com/btk5h/skriptmirror/skript/reflect/ExprMemberNames.java @@ -16,53 +16,53 @@ import java.util.stream.Stream; public class ExprMemberNames extends SimpleExpression { - static { - PropertyExpression.register(ExprMemberNames.class, String.class, "(0¦field|1¦method) names", "objects"); - } + static { + PropertyExpression.register(ExprMemberNames.class, String.class, "(0¦field|1¦method) names", "objects"); + } - private Expression target; - private Function, Stream> mapper; + private Expression target; + private Function, Stream> mapper; - @Override - protected String[] get(Event e) { - return Arrays.stream(target.getArray(e)) - .map(SkriptMirrorUtil::toClassUnwrapJavaTypes) - .flatMap(mapper) - .map(Member::getName) - .distinct() - .toArray(String[]::new); - } + @Override + protected String[] get(Event e) { + return Arrays.stream(target.getArray(e)) + .map(SkriptMirrorUtil::toClassUnwrapJavaTypes) + .flatMap(mapper) + .map(Member::getName) + .distinct() + .toArray(String[]::new); + } - @Override - public boolean isSingle() { - return false; - } + @Override + public boolean isSingle() { + return false; + } - @Override - public Class getReturnType() { - return String.class; - } + @Override + public Class getReturnType() { + return String.class; + } - @Override - public String toString(Event e, boolean debug) { - return "member names of " + target.toString(); - } + @Override + public String toString(Event e, boolean debug) { + return "member names of " + target.toString(); + } - @SuppressWarnings("unchecked") - @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, - SkriptParser.ParseResult parseResult) { - target = SkriptUtil.defendExpression(exprs[0]); + @SuppressWarnings("unchecked") + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, + SkriptParser.ParseResult parseResult) { + target = SkriptUtil.defendExpression(exprs[0]); - switch (parseResult.mark) { - case 0: - mapper = JavaUtil::fields; - break; - case 1: - mapper = JavaUtil::methods; - break; - } + switch (parseResult.mark) { + case 0: + mapper = JavaUtil::fields; + break; + case 1: + mapper = JavaUtil::methods; + break; + } - return SkriptUtil.canInitSafely(target); - } + return SkriptUtil.canInitSafely(target); + } } diff --git a/src/main/java/com/btk5h/skriptmirror/skript/reflect/ExprMembers.java b/src/main/java/com/btk5h/skriptmirror/skript/reflect/ExprMembers.java index b1d02a75..80dd5201 100644 --- a/src/main/java/com/btk5h/skriptmirror/skript/reflect/ExprMembers.java +++ b/src/main/java/com/btk5h/skriptmirror/skript/reflect/ExprMembers.java @@ -16,57 +16,57 @@ import java.util.stream.Stream; public class ExprMembers extends SimpleExpression { - static { - PropertyExpression.register(ExprMembers.class, String.class, "(0¦fields|1¦methods|2¦constructors)", "objects"); - } + static { + PropertyExpression.register(ExprMembers.class, String.class, "(0¦fields|1¦methods|2¦constructors)", "objects"); + } - private Expression target; - private Function, Stream> mapper; + private Expression target; + private Function, Stream> mapper; - @Override - protected String[] get(Event e) { - return Arrays.stream(target.getArray(e)) - .map(SkriptMirrorUtil::toClassUnwrapJavaTypes) - .flatMap(mapper) - .map(JavaUtil::toGenericString) - .distinct() - .toArray(String[]::new); - } + @Override + protected String[] get(Event e) { + return Arrays.stream(target.getArray(e)) + .map(SkriptMirrorUtil::toClassUnwrapJavaTypes) + .flatMap(mapper) + .map(JavaUtil::toGenericString) + .distinct() + .toArray(String[]::new); + } - @Override - public boolean isSingle() { - return false; - } + @Override + public boolean isSingle() { + return false; + } - @Override - public Class getReturnType() { - return String.class; - } + @Override + public Class getReturnType() { + return String.class; + } - @Override - public String toString(Event e, boolean debug) { - return "members of " + target.toString(e, debug); - } + @Override + public String toString(Event e, boolean debug) { + return "members of " + target.toString(e, debug); + } - @SuppressWarnings("unchecked") - @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, - SkriptParser.ParseResult parseResult) { - target = SkriptUtil.defendExpression(exprs[0]); + @SuppressWarnings("unchecked") + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, + SkriptParser.ParseResult parseResult) { + target = SkriptUtil.defendExpression(exprs[0]); - switch (parseResult.mark) { - case 0: - mapper = JavaUtil::fields; - break; - case 1: - mapper = JavaUtil::methods; - break; - case 2: - mapper = JavaUtil::constructors; - break; - } + switch (parseResult.mark) { + case 0: + mapper = JavaUtil::fields; + break; + case 1: + mapper = JavaUtil::methods; + break; + case 2: + mapper = JavaUtil::constructors; + break; + } - return SkriptUtil.canInitSafely(target); - } + return SkriptUtil.canInitSafely(target); + } } diff --git a/src/main/java/com/btk5h/skriptmirror/skript/reflect/ExprNewArray.java b/src/main/java/com/btk5h/skriptmirror/skript/reflect/ExprNewArray.java index d365b40e..47b40cc8 100644 --- a/src/main/java/com/btk5h/skriptmirror/skript/reflect/ExprNewArray.java +++ b/src/main/java/com/btk5h/skriptmirror/skript/reflect/ExprNewArray.java @@ -16,51 +16,51 @@ public class ExprNewArray extends SimpleExpression { - static { - Skript.registerExpression(ExprNewArray.class, ObjectWrapper.class, ExpressionType.COMBINED, - "new (<(" + JavaTypeWrapper.PRIMITIVE_PATTERNS + ")>|%-javatype%)\\[%number%\\]"); - } + static { + Skript.registerExpression(ExprNewArray.class, ObjectWrapper.class, ExpressionType.COMBINED, + "new (<(" + JavaTypeWrapper.PRIMITIVE_PATTERNS + ")>|%-javatype%)\\[%number%\\]"); + } - private JavaTypeWrapper javaTypeWrapper; - private Expression sizeExpression; + private JavaTypeWrapper javaTypeWrapper; + private Expression sizeExpression; - @SuppressWarnings("unchecked") - @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { - javaTypeWrapper = JavaTypeWrapper.of(exprs[0], parseResult.regexes); - sizeExpression = (Expression) exprs[1]; - return true; - } + @SuppressWarnings("unchecked") + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + javaTypeWrapper = JavaTypeWrapper.of(exprs[0], parseResult.regexes); + sizeExpression = (Expression) exprs[1]; + return true; + } - @Override - @Nullable - protected ObjectWrapper[] get(Event e) { - JavaType javaType = javaTypeWrapper.get(e); - Number length = sizeExpression.getSingle(e); + @Override + @Nullable + protected ObjectWrapper[] get(Event e) { + JavaType javaType = javaTypeWrapper.get(e); + Number length = sizeExpression.getSingle(e); - if (javaType == null || length == null) - return null; + if (javaType == null || length == null) + return null; - int size = length.intValue(); - Class clazz = javaType.getJavaClass(); + int size = length.intValue(); + Class clazz = javaType.getJavaClass(); - Object array = Array.newInstance(clazz, size); - return new ObjectWrapper[] {ObjectWrapper.create(array)}; - } + Object array = Array.newInstance(clazz, size); + return new ObjectWrapper[] {ObjectWrapper.create(array)}; + } - @Override - public boolean isSingle() { - return true; - } + @Override + public boolean isSingle() { + return true; + } - @Override - public Class getReturnType() { - return ObjectWrapper.class; - } + @Override + public Class getReturnType() { + return ObjectWrapper.class; + } - @Override - public String toString(@Nullable Event e, boolean debug) { - return "new " + javaTypeWrapper.toString(e, debug) + "[" + sizeExpression.toString(e, debug) + "]"; - } + @Override + public String toString(@Nullable Event e, boolean debug) { + return "new " + javaTypeWrapper.toString(e, debug) + "[" + sizeExpression.toString(e, debug) + "]"; + } } diff --git a/src/main/java/com/btk5h/skriptmirror/skript/reflect/ExprProxy.java b/src/main/java/com/btk5h/skriptmirror/skript/reflect/ExprProxy.java index 67a01ae2..6bceca8c 100644 --- a/src/main/java/com/btk5h/skriptmirror/skript/reflect/ExprProxy.java +++ b/src/main/java/com/btk5h/skriptmirror/skript/reflect/ExprProxy.java @@ -33,180 +33,180 @@ public class ExprProxy extends SimpleExpression { - public static boolean proxiesUsed = false; - - static { - Skript.registerExpression(ExprProxy.class, Object.class, ExpressionType.COMBINED, - "[a] [new] proxy [instance] of %javatypes% (using|from) %objects%"); - } - - private Expression interfaces; - private Variable handler; - - @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, - SkriptParser.ParseResult parseResult) { - proxiesUsed = true; - - interfaces = SkriptUtil.defendExpression(exprs[0]); - if (interfaces instanceof Literal) { - JavaType[] javaTypes = ((Literal) interfaces).getArray(); - for (JavaType javaType : javaTypes) { - if (!javaType.getJavaClass().isInterface()) { - Skript.warning(javaType + " is not an interface"); - } - } - } - - Expression var = SkriptUtil.defendExpression(exprs[1]); - if (var instanceof Variable && ((Variable) var).isList()) { - handler = (Variable) var; - return true; - } - - Skript.error(var + " is not a list variable."); - return false; - } - - @Override - protected Object[] get(Event e) { - Map handlers = new HashMap<>(); - Map sectionHandlers = new HashMap<>(); - handler.variablesIterator(e) - .forEachRemaining(pair -> { - Object value = pair.getValue(); - if (value instanceof FunctionWrapper) { - handlers.put(pair.getKey(), (FunctionWrapper) value); - } else if (value instanceof Section) { - sectionHandlers.put(pair.getKey(), (Section) value); - } - }); - - return new Object[]{ - Proxy.newProxyInstance( - LibraryLoader.getClassLoader(), - Arrays.stream(interfaces.getArray(e)) - .map(JavaType::getJavaClass) - .filter(Class::isInterface) - .toArray(Class[]::new), - new VariableInvocationHandler(handlers, sectionHandlers) - ) - }; - } - - @Override - public boolean isSingle() { - return true; - } - - @Override - public Class getReturnType() { - return Object.class; - } - - @Override - public String toString(Event e, boolean debug) { - return String.format("proxy of %s from %s", - interfaces.toString(e, debug), - handler.toString(e, debug)); - } - - private static class VariableInvocationHandler implements InvocationHandler { - @Nullable - private static final Method INVOKE_DEFAULT; - static { - Method method; - try { - //noinspection JavaReflectionMemberAccess - method = InvocationHandler.class.getDeclaredMethod("invokeDefault", Object.class, Method.class, Object[].class); - } catch (NoSuchMethodException e) { - method = null; - } - INVOKE_DEFAULT = method; - } - - private final Map handlers; - private final Map sectionHandlers; - - public VariableInvocationHandler(Map handlers, Map sectionHandlers) { - this.handlers = handlers; - this.sectionHandlers = sectionHandlers; - } - - @Override - public Object invoke(Object proxy, Method method, Object[] methodArgs) { - FunctionWrapper functionWrapper = handlers.get(method.getName().toLowerCase()); - Section section = sectionHandlers.get(method.getName().toLowerCase()); - - if (functionWrapper == null && section == null) { - if (INVOKE_DEFAULT != null) { - if (method.isDefault()) { - try { - return INVOKE_DEFAULT.invoke(this, proxy, method, methodArgs); - } catch (IllegalAccessException | InvocationTargetException e) { - throw new RuntimeException(e); - } - } else if (method.getName().equals("toString") && method.getParameterCount() == 0) { - // Default impl of toString - return proxy.getClass().getName() + "@" + Integer.toHexString(proxy.hashCode()); - } else if (method.getName().equals("hashCode") && method.getParameterCount() == 0) { - // Default impl of hashCode - return System.identityHashCode(proxy); - } else if (method.getName().equals("equals") - && method.getParameterCount() == 1 - && method.getParameterTypes()[0] == Object.class) { - // Default impl of equals - return proxy == methodArgs[0]; - } - } - - return null; - } - - Function function = functionWrapper == null ? null : functionWrapper.getFunction(); - Object[] functionArgs = functionWrapper == null ? new Object[0] : functionWrapper.getArguments(); - - if (functionWrapper != null && function == null) { - return null; - } - - if (methodArgs == null) { - methodArgs = new Object[0]; - } - - List params = new ArrayList<>(functionArgs.length + methodArgs.length + 1); - Arrays.stream(functionArgs) - .map(arg -> new Object[]{arg}) - .forEach(params::add); - params.add(new Object[]{proxy}); - Arrays.stream(methodArgs) - .map(arg -> new Object[]{arg}) - .forEach(params::add); - - Object[] returnValueArray; - if (function != null) { - FunctionEvent functionEvent = new FunctionEvent<>(function); - - Object[][] args = params.stream() - .limit(function.getParameters().length) - .toArray(Object[][]::new); - - returnValueArray = function.execute(functionEvent, args); - } else { - SectionEvent sectionEvent = section.run(params.toArray(new Object[0][])); - returnValueArray = sectionEvent.getOutput(); - } - - Object returnValue = (returnValueArray == null || returnValueArray.length == 0) ? null : - ObjectWrapper.unwrapIfNecessary(returnValueArray[0]); - - Class returnType = method.getReturnType(); - if (returnType == void.class) { - return null; - } else { - return JavaUtil.convert(returnValue, returnType); - } - } - } + public static boolean proxiesUsed = false; + + static { + Skript.registerExpression(ExprProxy.class, Object.class, ExpressionType.COMBINED, + "[a] [new] proxy [instance] of %javatypes% (using|from) %objects%"); + } + + private Expression interfaces; + private Variable handler; + + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, + SkriptParser.ParseResult parseResult) { + proxiesUsed = true; + + interfaces = SkriptUtil.defendExpression(exprs[0]); + if (interfaces instanceof Literal) { + JavaType[] javaTypes = ((Literal) interfaces).getArray(); + for (JavaType javaType : javaTypes) { + if (!javaType.getJavaClass().isInterface()) { + Skript.warning(javaType + " is not an interface"); + } + } + } + + Expression var = SkriptUtil.defendExpression(exprs[1]); + if (var instanceof Variable && ((Variable) var).isList()) { + handler = (Variable) var; + return true; + } + + Skript.error(var + " is not a list variable."); + return false; + } + + @Override + protected Object[] get(Event e) { + Map handlers = new HashMap<>(); + Map sectionHandlers = new HashMap<>(); + handler.variablesIterator(e) + .forEachRemaining(pair -> { + Object value = pair.getValue(); + if (value instanceof FunctionWrapper) { + handlers.put(pair.getKey(), (FunctionWrapper) value); + } else if (value instanceof Section) { + sectionHandlers.put(pair.getKey(), (Section) value); + } + }); + + return new Object[]{ + Proxy.newProxyInstance( + LibraryLoader.getClassLoader(), + Arrays.stream(interfaces.getArray(e)) + .map(JavaType::getJavaClass) + .filter(Class::isInterface) + .toArray(Class[]::new), + new VariableInvocationHandler(handlers, sectionHandlers) + ) + }; + } + + @Override + public boolean isSingle() { + return true; + } + + @Override + public Class getReturnType() { + return Object.class; + } + + @Override + public String toString(Event e, boolean debug) { + return String.format("proxy of %s from %s", + interfaces.toString(e, debug), + handler.toString(e, debug)); + } + + private static class VariableInvocationHandler implements InvocationHandler { + @Nullable + private static final Method INVOKE_DEFAULT; + static { + Method method; + try { + //noinspection JavaReflectionMemberAccess + method = InvocationHandler.class.getDeclaredMethod("invokeDefault", Object.class, Method.class, Object[].class); + } catch (NoSuchMethodException e) { + method = null; + } + INVOKE_DEFAULT = method; + } + + private final Map handlers; + private final Map sectionHandlers; + + public VariableInvocationHandler(Map handlers, Map sectionHandlers) { + this.handlers = handlers; + this.sectionHandlers = sectionHandlers; + } + + @Override + public Object invoke(Object proxy, Method method, Object[] methodArgs) { + FunctionWrapper functionWrapper = handlers.get(method.getName().toLowerCase()); + Section section = sectionHandlers.get(method.getName().toLowerCase()); + + if (functionWrapper == null && section == null) { + if (INVOKE_DEFAULT != null) { + if (method.isDefault()) { + try { + return INVOKE_DEFAULT.invoke(this, proxy, method, methodArgs); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException(e); + } + } else if (method.getName().equals("toString") && method.getParameterCount() == 0) { + // Default impl of toString + return proxy.getClass().getName() + "@" + Integer.toHexString(proxy.hashCode()); + } else if (method.getName().equals("hashCode") && method.getParameterCount() == 0) { + // Default impl of hashCode + return System.identityHashCode(proxy); + } else if (method.getName().equals("equals") + && method.getParameterCount() == 1 + && method.getParameterTypes()[0] == Object.class) { + // Default impl of equals + return proxy == methodArgs[0]; + } + } + + return null; + } + + Function function = functionWrapper == null ? null : functionWrapper.getFunction(); + Object[] functionArgs = functionWrapper == null ? new Object[0] : functionWrapper.getArguments(); + + if (functionWrapper != null && function == null) { + return null; + } + + if (methodArgs == null) { + methodArgs = new Object[0]; + } + + List params = new ArrayList<>(functionArgs.length + methodArgs.length + 1); + Arrays.stream(functionArgs) + .map(arg -> new Object[]{arg}) + .forEach(params::add); + params.add(new Object[]{proxy}); + Arrays.stream(methodArgs) + .map(arg -> new Object[]{arg}) + .forEach(params::add); + + Object[] returnValueArray; + if (function != null) { + FunctionEvent functionEvent = new FunctionEvent<>(function); + + Object[][] args = params.stream() + .limit(function.getParameters().length) + .toArray(Object[][]::new); + + returnValueArray = function.execute(functionEvent, args); + } else { + SectionEvent sectionEvent = section.run(params.toArray(new Object[0][])); + returnValueArray = sectionEvent.getOutput(); + } + + Object returnValue = (returnValueArray == null || returnValueArray.length == 0) ? null : + ObjectWrapper.unwrapIfNecessary(returnValueArray[0]); + + Class returnType = method.getReturnType(); + if (returnType == void.class) { + return null; + } else { + return JavaUtil.convert(returnValue, returnType); + } + } + } } diff --git a/src/main/java/com/btk5h/skriptmirror/skript/reflect/sections/EffRunSection.java b/src/main/java/com/btk5h/skriptmirror/skript/reflect/sections/EffRunSection.java index 193dfe38..0845ef1d 100644 --- a/src/main/java/com/btk5h/skriptmirror/skript/reflect/sections/EffRunSection.java +++ b/src/main/java/com/btk5h/skriptmirror/skript/reflect/sections/EffRunSection.java @@ -23,129 +23,129 @@ public class EffRunSection extends Effect { - static { - Skript.registerEffect(EffRunSection.class, - "run section %section% [(1¦sync|2¦async)] [with [arguments] %-objects%] [and store [the] result in %-objects%] [(4¦and wait)]"); - } - - private Expression
sectionExpression; - private Kleenean runsAsync; - private List> arguments; - private Expression variableStorage; - private boolean shouldWait; - - @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) { - sectionExpression = SkriptUtil.defendExpression(exprs[0]); - - if ((parseResult.mark & 0b0001) != 0) - runsAsync = Kleenean.FALSE; - else if ((parseResult.mark & 0b0010) != 0) - runsAsync = Kleenean.TRUE; - else - runsAsync = Kleenean.UNKNOWN; - - Expression expr = SkriptUtil.defendExpression(exprs[1]); - arguments = new ArrayList<>(); - if (expr instanceof ExpressionList) { - Collections.addAll(arguments, ((ExpressionList) expr).getExpressions()); - } else if (expr != null) { - arguments.add(expr); - } - - variableStorage = SkriptUtil.defendExpression(exprs[2]); - if (variableStorage != null && !(variableStorage instanceof Variable)) { - Skript.error("The result can only be stored in a variable"); - return false; - } - - shouldWait = (parseResult.mark & 0b0100) != 0; - if (!runsAsync.isUnknown() && !shouldWait && variableStorage != null) - Skript.warning("You need to wait until the section is finished if you want to get a result."); - - if (!runsAsync.isUnknown() && shouldWait) - getParser().setHasDelayBefore(Kleenean.TRUE); - - return SkriptUtil.canInitSafely(variableStorage) && - (arguments.size() == 0 || arguments.stream().allMatch(SkriptUtil::canInitSafely)); - } - - @Override - protected TriggerItem walk(Event e) { - if (runsAsync.isUnknown()) - return super.walk(e); - - Section section = sectionExpression.getSingle(e); - - if (section == null) - return getNext(); - - Object[][] args = getArgs(e); - - // Whether the trigger needs to be continued abnormally - boolean needsContinue = shouldWait && getNext() != null; - - // If the trigger needs abnormal continuation, remove locals and store whether this trigger was running async. - Object localVars = needsContinue ? SkriptReflection.removeLocals(e) : null; - boolean ranAsync = !Bukkit.isPrimaryThread(); - - Runnable runSection = () -> { - SkriptReflection.putLocals(localVars, e); - - SectionEvent sectionEvent = section.run(args); - storeResult(sectionEvent, e); - - if (needsContinue) { - Runnable continuation = () -> { - - TriggerItem.walk(getNext(), e); - SkriptReflection.removeLocals(e); - }; - - runTask(continuation, ranAsync); - } - }; - - if (needsContinue) - Delay.addDelayedEvent(e); - - runTask(runSection, runsAsync.isTrue()); - - return needsContinue ? null : getNext(); - } - - @Override - protected void execute(Event e) { - Section section = sectionExpression.getSingle(e); - if (section != null) { - SectionEvent sectionEvent = section.run(getArgs(e)); - storeResult(sectionEvent, e); - } - } - - @Override - public String toString(@Nullable Event e, boolean debug) { - return "run section " + sectionExpression.toString(e, debug); - } - - private Object[][] getArgs(Event event) { - Object[][] args = new Object[arguments.size()][]; - for (int i = 0; i < arguments.size(); i++) - args[i] = arguments.get(i).getArray(event); - return args; - } - - private void storeResult(SectionEvent sectionEvent, Event event) { - Object[] output = sectionEvent.getOutput(); - if (variableStorage != null && output != null) - variableStorage.change(event, output, Changer.ChangeMode.SET); - } - - private void runTask(Runnable task, boolean async) { - if (async) - Bukkit.getScheduler().runTaskAsynchronously(SkriptMirror.getInstance(), task); - else - Bukkit.getScheduler().runTask(SkriptMirror.getInstance(), task); - } + static { + Skript.registerEffect(EffRunSection.class, + "run section %section% [(1¦sync|2¦async)] [with [arguments] %-objects%] [and store [the] result in %-objects%] [(4¦and wait)]"); + } + + private Expression
sectionExpression; + private Kleenean runsAsync; + private List> arguments; + private Expression variableStorage; + private boolean shouldWait; + + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) { + sectionExpression = SkriptUtil.defendExpression(exprs[0]); + + if ((parseResult.mark & 0b0001) != 0) + runsAsync = Kleenean.FALSE; + else if ((parseResult.mark & 0b0010) != 0) + runsAsync = Kleenean.TRUE; + else + runsAsync = Kleenean.UNKNOWN; + + Expression expr = SkriptUtil.defendExpression(exprs[1]); + arguments = new ArrayList<>(); + if (expr instanceof ExpressionList) { + Collections.addAll(arguments, ((ExpressionList) expr).getExpressions()); + } else if (expr != null) { + arguments.add(expr); + } + + variableStorage = SkriptUtil.defendExpression(exprs[2]); + if (variableStorage != null && !(variableStorage instanceof Variable)) { + Skript.error("The result can only be stored in a variable"); + return false; + } + + shouldWait = (parseResult.mark & 0b0100) != 0; + if (!runsAsync.isUnknown() && !shouldWait && variableStorage != null) + Skript.warning("You need to wait until the section is finished if you want to get a result."); + + if (!runsAsync.isUnknown() && shouldWait) + getParser().setHasDelayBefore(Kleenean.TRUE); + + return SkriptUtil.canInitSafely(variableStorage) && + (arguments.size() == 0 || arguments.stream().allMatch(SkriptUtil::canInitSafely)); + } + + @Override + protected TriggerItem walk(Event e) { + if (runsAsync.isUnknown()) + return super.walk(e); + + Section section = sectionExpression.getSingle(e); + + if (section == null) + return getNext(); + + Object[][] args = getArgs(e); + + // Whether the trigger needs to be continued abnormally + boolean needsContinue = shouldWait && getNext() != null; + + // If the trigger needs abnormal continuation, remove locals and store whether this trigger was running async. + Object localVars = needsContinue ? SkriptReflection.removeLocals(e) : null; + boolean ranAsync = !Bukkit.isPrimaryThread(); + + Runnable runSection = () -> { + SkriptReflection.putLocals(localVars, e); + + SectionEvent sectionEvent = section.run(args); + storeResult(sectionEvent, e); + + if (needsContinue) { + Runnable continuation = () -> { + + TriggerItem.walk(getNext(), e); + SkriptReflection.removeLocals(e); + }; + + runTask(continuation, ranAsync); + } + }; + + if (needsContinue) + Delay.addDelayedEvent(e); + + runTask(runSection, runsAsync.isTrue()); + + return needsContinue ? null : getNext(); + } + + @Override + protected void execute(Event e) { + Section section = sectionExpression.getSingle(e); + if (section != null) { + SectionEvent sectionEvent = section.run(getArgs(e)); + storeResult(sectionEvent, e); + } + } + + @Override + public String toString(@Nullable Event e, boolean debug) { + return "run section " + sectionExpression.toString(e, debug); + } + + private Object[][] getArgs(Event event) { + Object[][] args = new Object[arguments.size()][]; + for (int i = 0; i < arguments.size(); i++) + args[i] = arguments.get(i).getArray(event); + return args; + } + + private void storeResult(SectionEvent sectionEvent, Event event) { + Object[] output = sectionEvent.getOutput(); + if (variableStorage != null && output != null) + variableStorage.change(event, output, Changer.ChangeMode.SET); + } + + private void runTask(Runnable task, boolean async) { + if (async) + Bukkit.getScheduler().runTaskAsynchronously(SkriptMirror.getInstance(), task); + else + Bukkit.getScheduler().runTask(SkriptMirror.getInstance(), task); + } } diff --git a/src/main/java/com/btk5h/skriptmirror/skript/reflect/sections/SecSection.java b/src/main/java/com/btk5h/skriptmirror/skript/reflect/sections/SecSection.java index 2911478a..5d821822 100644 --- a/src/main/java/com/btk5h/skriptmirror/skript/reflect/sections/SecSection.java +++ b/src/main/java/com/btk5h/skriptmirror/skript/reflect/sections/SecSection.java @@ -19,85 +19,85 @@ public class SecSection extends ch.njol.skript.lang.Section { - public static boolean sectionsUsed = false; - - static { - Skript.registerSection(SecSection.class, - "create [new] section [with [arguments variables] %-objects%] (and store it|stored) in %objects%"); - } - - private Trigger trigger; - private ArrayList> variableArguments; - private Expression variableStore; - - @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult, SectionNode sectionNode, List triggerItems) { - sectionsUsed = true; - - Expression varList = SkriptUtil.defendExpression(exprs[0]); - variableStore = SkriptUtil.defendExpression(exprs[1]); - - if (!SkriptUtil.canInitSafely(varList, variableStore)) - return false; - - variableArguments = new ArrayList<>(); - if (varList != null) { - if (varList instanceof ExpressionList) { - ExpressionList expressionList = (ExpressionList) varList; - - for (Expression expr : expressionList.getExpressions()) { - if (!(expr instanceof Variable)) { - Skript.error("The arguments can only contain variables"); - return false; - } - - variableArguments.add((Variable) expr); - } - } else if (varList instanceof Variable) { - variableArguments.add((Variable) varList); - } else { - Skript.error("The arguments can only contain variables"); - return false; - } - } - - if (!(variableStore instanceof Variable)) { - Skript.error("The created section can only be stored in a variable"); - return false; - } - - trigger = loadCode(sectionNode, "section", SectionEvent.class); - - return SkriptUtil.canInitSafely(variableStore); - } - - @Override - protected @Nullable TriggerItem walk(Event e) { - Section section = new Section(trigger, e, variableArguments); - variableStore.change(e, new Section[]{section}, Changer.ChangeMode.SET); - return super.walk(e, false); - } - - @Override - public String toString(@Nullable Event e, boolean debug) { - StringBuilder stringBuilder = new StringBuilder("create section"); - if (!variableArguments.isEmpty()) { - stringBuilder.append(" with argument variables "); - for (int i = 0; i < variableArguments.size(); i++) { - Variable variable = variableArguments.get(i); - stringBuilder.append(variable.toString(e, debug)); - - if (i == variableArguments.size() - 2) { - stringBuilder.append(" and "); - } else if (i != variableArguments.size() - 1) { - stringBuilder.append(", "); - } - } - } - if (variableStore != null) { - stringBuilder.append(" stored in ").append(variableStore.toString(e, debug)); - } - return stringBuilder.toString(); - } + public static boolean sectionsUsed = false; + + static { + Skript.registerSection(SecSection.class, + "create [new] section [with [arguments variables] %-objects%] (and store it|stored) in %objects%"); + } + + private Trigger trigger; + private ArrayList> variableArguments; + private Expression variableStore; + + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult, SectionNode sectionNode, List triggerItems) { + sectionsUsed = true; + + Expression varList = SkriptUtil.defendExpression(exprs[0]); + variableStore = SkriptUtil.defendExpression(exprs[1]); + + if (!SkriptUtil.canInitSafely(varList, variableStore)) + return false; + + variableArguments = new ArrayList<>(); + if (varList != null) { + if (varList instanceof ExpressionList) { + ExpressionList expressionList = (ExpressionList) varList; + + for (Expression expr : expressionList.getExpressions()) { + if (!(expr instanceof Variable)) { + Skript.error("The arguments can only contain variables"); + return false; + } + + variableArguments.add((Variable) expr); + } + } else if (varList instanceof Variable) { + variableArguments.add((Variable) varList); + } else { + Skript.error("The arguments can only contain variables"); + return false; + } + } + + if (!(variableStore instanceof Variable)) { + Skript.error("The created section can only be stored in a variable"); + return false; + } + + trigger = loadCode(sectionNode, "section", SectionEvent.class); + + return SkriptUtil.canInitSafely(variableStore); + } + + @Override + protected @Nullable TriggerItem walk(Event e) { + Section section = new Section(trigger, e, variableArguments); + variableStore.change(e, new Section[]{section}, Changer.ChangeMode.SET); + return super.walk(e, false); + } + + @Override + public String toString(@Nullable Event e, boolean debug) { + StringBuilder stringBuilder = new StringBuilder("create section"); + if (!variableArguments.isEmpty()) { + stringBuilder.append(" with argument variables "); + for (int i = 0; i < variableArguments.size(); i++) { + Variable variable = variableArguments.get(i); + stringBuilder.append(variable.toString(e, debug)); + + if (i == variableArguments.size() - 2) { + stringBuilder.append(" and "); + } else if (i != variableArguments.size() - 1) { + stringBuilder.append(", "); + } + } + } + if (variableStore != null) { + stringBuilder.append(" stored in ").append(variableStore.toString(e, debug)); + } + return stringBuilder.toString(); + } } diff --git a/src/main/java/com/btk5h/skriptmirror/skript/reflect/sections/Section.java b/src/main/java/com/btk5h/skriptmirror/skript/reflect/sections/Section.java index 10b5a6c7..ce4e946e 100644 --- a/src/main/java/com/btk5h/skriptmirror/skript/reflect/sections/Section.java +++ b/src/main/java/com/btk5h/skriptmirror/skript/reflect/sections/Section.java @@ -11,46 +11,46 @@ public class Section { - private final Trigger trigger; - private final Object variablesMap; - private final List> argumentVariables; - private Object[] output; - - public Section(Trigger trigger, Object variablesMap, List> argumentVariables) { - this.trigger = trigger; - this.variablesMap = variablesMap; - this.argumentVariables = argumentVariables; - } - - public Section(Trigger trigger, Event event, List> argumentVariables) { - this(trigger, SkriptReflection.copyLocals(SkriptReflection.getLocals(event)), argumentVariables); - } - - public SectionEvent run(Object[][] arguments) { - output = null; - SectionEvent sectionEvent = new SectionEvent(this); - SkriptReflection.putLocals(SkriptReflection.copyLocals(variablesMap), sectionEvent); - - for (int i = 0; i < arguments.length && i < argumentVariables.size(); i++) { + private final Trigger trigger; + private final Object variablesMap; + private final List> argumentVariables; + private Object[] output; + + public Section(Trigger trigger, Object variablesMap, List> argumentVariables) { + this.trigger = trigger; + this.variablesMap = variablesMap; + this.argumentVariables = argumentVariables; + } + + public Section(Trigger trigger, Event event, List> argumentVariables) { + this(trigger, SkriptReflection.copyLocals(SkriptReflection.getLocals(event)), argumentVariables); + } + + public SectionEvent run(Object[][] arguments) { + output = null; + SectionEvent sectionEvent = new SectionEvent(this); + SkriptReflection.putLocals(SkriptReflection.copyLocals(variablesMap), sectionEvent); + + for (int i = 0; i < arguments.length && i < argumentVariables.size(); i++) { Object[] currentArg = arguments[i]; - if (currentArg.length == 0) { - argumentVariables.get(i).change(sectionEvent, null, Changer.ChangeMode.DELETE); - } else { - argumentVariables.get(i).change(sectionEvent, currentArg, Changer.ChangeMode.SET); - } + if (currentArg.length == 0) { + argumentVariables.get(i).change(sectionEvent, null, Changer.ChangeMode.DELETE); + } else { + argumentVariables.get(i).change(sectionEvent, currentArg, Changer.ChangeMode.SET); + } } - TriggerItem.walk(trigger, sectionEvent); - SkriptReflection.removeLocals(sectionEvent); - return sectionEvent; - } + TriggerItem.walk(trigger, sectionEvent); + SkriptReflection.removeLocals(sectionEvent); + return sectionEvent; + } - public Object[] getOutput() { - return output; - } + public Object[] getOutput() { + return output; + } - public void setOutput(Object[] output) { - this.output = output; - } + public void setOutput(Object[] output) { + this.output = output; + } } diff --git a/src/main/java/com/btk5h/skriptmirror/skript/reflect/sections/SectionEvent.java b/src/main/java/com/btk5h/skriptmirror/skript/reflect/sections/SectionEvent.java index fa2d52e9..1fbc00ac 100644 --- a/src/main/java/com/btk5h/skriptmirror/skript/reflect/sections/SectionEvent.java +++ b/src/main/java/com/btk5h/skriptmirror/skript/reflect/sections/SectionEvent.java @@ -5,28 +5,28 @@ public class SectionEvent extends Event { - private final Section section; - private Object[] output; + private final Section section; + private Object[] output; - public SectionEvent(Section section) { - this.section = section; - } + public SectionEvent(Section section) { + this.section = section; + } - public Section getSection() { - return section; - } + public Section getSection() { + return section; + } - public Object[] getOutput() { - return output; - } + public Object[] getOutput() { + return output; + } - public void setOutput(Object[] output) { - this.output = output; - } + public void setOutput(Object[] output) { + this.output = output; + } - @Override - public HandlerList getHandlers() { - throw new IllegalStateException(); - } + @Override + public HandlerList getHandlers() { + throw new IllegalStateException(); + } } diff --git a/src/main/java/com/btk5h/skriptmirror/util/JavaTypeWrapper.java b/src/main/java/com/btk5h/skriptmirror/util/JavaTypeWrapper.java index 65011937..07fdb1ba 100644 --- a/src/main/java/com/btk5h/skriptmirror/util/JavaTypeWrapper.java +++ b/src/main/java/com/btk5h/skriptmirror/util/JavaTypeWrapper.java @@ -14,60 +14,60 @@ @SuppressWarnings("ConstantConditions") public class JavaTypeWrapper { - /** - * Contains a string of all primitive types (excluding void), separated by {@code |}. - */ - public static final String PRIMITIVE_PATTERNS = String.join("|", JavaUtil.PRIMITIVE_CLASS_NAMES.keySet()); + /** + * Contains a string of all primitive types (excluding void), separated by {@code |}. + */ + public static final String PRIMITIVE_PATTERNS = String.join("|", JavaUtil.PRIMITIVE_CLASS_NAMES.keySet()); - private final Expression javaTypeExpression; - private final Class clazz; + private final Expression javaTypeExpression; + private final Class clazz; - public JavaTypeWrapper(@Nullable Expression javaTypeExpression, @Nullable Class clazz) { - this.javaTypeExpression = javaTypeExpression; - this.clazz = clazz; - } + public JavaTypeWrapper(@Nullable Expression javaTypeExpression, @Nullable Class clazz) { + this.javaTypeExpression = javaTypeExpression; + this.clazz = clazz; + } - public static JavaTypeWrapper ofExpression(Expression javaTypeExpression) { - return new JavaTypeWrapper(javaTypeExpression, null); - } + public static JavaTypeWrapper ofExpression(Expression javaTypeExpression) { + return new JavaTypeWrapper(javaTypeExpression, null); + } - public static JavaTypeWrapper ofClass(Class clazz) { - return new JavaTypeWrapper(null, clazz); - } + public static JavaTypeWrapper ofClass(Class clazz) { + return new JavaTypeWrapper(null, clazz); + } - @SuppressWarnings("unchecked") - public static JavaTypeWrapper of(Expression expression, List matchResults) { - if (expression != null) { - return ofExpression((Expression) expression); - } else { - String primitiveType = matchResults.get(0).group(); - return ofClass(JavaUtil.PRIMITIVE_CLASS_NAMES.get(primitiveType)); - } - } + @SuppressWarnings("unchecked") + public static JavaTypeWrapper of(Expression expression, List matchResults) { + if (expression != null) { + return ofExpression((Expression) expression); + } else { + String primitiveType = matchResults.get(0).group(); + return ofClass(JavaUtil.PRIMITIVE_CLASS_NAMES.get(primitiveType)); + } + } - public JavaType get(Event event) { - if (clazz != null) { - return new JavaType(clazz); - } else { - return javaTypeExpression.getSingle(event); - } - } + public JavaType get(Event event) { + if (clazz != null) { + return new JavaType(clazz); + } else { + return javaTypeExpression.getSingle(event); + } + } - public String toString(@Nullable Event event, boolean debug) { - if (clazz != null) { - return clazz.getName(); - } else { - return javaTypeExpression.toString(event, debug); - } - } + public String toString(@Nullable Event event, boolean debug) { + if (clazz != null) { + return clazz.getName(); + } else { + return javaTypeExpression.toString(event, debug); + } + } - @Override - public String toString() { - if (clazz != null) { - return clazz.getName(); - } else { - return javaTypeExpression.toString(null, false); - } - } + @Override + public String toString() { + if (clazz != null) { + return clazz.getName(); + } else { + return javaTypeExpression.toString(null, false); + } + } } diff --git a/src/main/java/com/btk5h/skriptmirror/util/JavaUtil.java b/src/main/java/com/btk5h/skriptmirror/util/JavaUtil.java index d55ae1de..1e452d91 100644 --- a/src/main/java/com/btk5h/skriptmirror/util/JavaUtil.java +++ b/src/main/java/com/btk5h/skriptmirror/util/JavaUtil.java @@ -23,376 +23,376 @@ import java.util.stream.Stream; public final class JavaUtil { - public static final Map, Class> WRAPPER_CLASSES = new HashMap<>(); - public static final Set> NUMERIC_CLASSES = new HashSet<>(); - public static final Map> PRIMITIVE_CLASS_NAMES = new HashMap<>(); - - static { - WRAPPER_CLASSES.put(boolean.class, Boolean.class); - WRAPPER_CLASSES.put(byte.class, Byte.class); - WRAPPER_CLASSES.put(char.class, Character.class); - WRAPPER_CLASSES.put(double.class, Double.class); - WRAPPER_CLASSES.put(float.class, Float.class); - WRAPPER_CLASSES.put(int.class, Integer.class); - WRAPPER_CLASSES.put(long.class, Long.class); - WRAPPER_CLASSES.put(short.class, Short.class); - - NUMERIC_CLASSES.add(byte.class); - NUMERIC_CLASSES.add(double.class); - NUMERIC_CLASSES.add(float.class); - NUMERIC_CLASSES.add(int.class); - NUMERIC_CLASSES.add(long.class); - NUMERIC_CLASSES.add(short.class); - NUMERIC_CLASSES.add(Byte.class); - NUMERIC_CLASSES.add(Double.class); - NUMERIC_CLASSES.add(Float.class); - NUMERIC_CLASSES.add(Integer.class); - NUMERIC_CLASSES.add(Long.class); - NUMERIC_CLASSES.add(Short.class); - - PRIMITIVE_CLASS_NAMES.put("boolean", boolean.class); - PRIMITIVE_CLASS_NAMES.put("byte", byte.class); - PRIMITIVE_CLASS_NAMES.put("char", char.class); - PRIMITIVE_CLASS_NAMES.put("double", double.class); - PRIMITIVE_CLASS_NAMES.put("float", float.class); - PRIMITIVE_CLASS_NAMES.put("int", int.class); - PRIMITIVE_CLASS_NAMES.put("long", long.class); - PRIMITIVE_CLASS_NAMES.put("short", short.class); - } - - /** - * @return a {@link Stream} of {@link Field}s, with the fields declared in the given class, - * and the public fields of the given class, without duplicates. - */ - public static Stream fields(Class cls) { - return Stream.concat( - Arrays.stream(cls.getFields()), - Arrays.stream(cls.getDeclaredFields()) - ).distinct(); - } - - /** - * @return a {@link Stream} of {@link Method}s, with the methods declared in the given class - * and the public methods of the given class, without duplicates. - */ - public static Stream methods(Class cls) { - return Stream.concat( - Arrays.stream(cls.getMethods()), - Arrays.stream(cls.getDeclaredMethods()) - ).distinct(); - } - - /** - * @return a {@link Stream} of the {@link Constructor}s declared in the given class. - */ - public static Stream constructors(Class cls) { - return Arrays.stream(cls.getDeclaredConstructors()); - } - - /** - * Calls {@code toGenericString} on the given {@link Member}, - * returning {@code null} if the given {@link Member} is not - * a {@link Field}, a {@link Method} or a {@link Constructor}. - */ - public static String toGenericString(Member o) { - if (o instanceof Field) { - return ((Field) o).toGenericString(); - } else if (o instanceof Method) { - return ((Method) o).toGenericString(); - } else if (o instanceof Constructor) { - return ((Constructor) o).toGenericString(); - } - return null; - } - - /** - * @return an array of the wrapper type of the component type of the given array (e.g. {@code int[] -> Integer[]}). - * The contents of the array are copied over. - */ - public static Object boxPrimitiveArray(Object obj) { - Class componentType = obj.getClass().getComponentType(); - if (componentType != null && componentType.isPrimitive()) { - int length = Array.getLength(obj); - Object[] boxedArray = newArray(WRAPPER_CLASSES.get(componentType), length); - - for (int i = 0; i < length; i++) { - boxedArray[i] = Array.get(obj, i); - } - - obj = boxedArray; - } - return obj; - } - - /** - * Converts a numeric array to a different numeric class. Also supports arrays with depths higher than {@code 1}. - */ - public static Object convertNumericArray(Object array, Class to) { - Class componentType = array.getClass().getComponentType(); - int length = Array.getLength(array); - - Object newArray; - - if (componentType.isArray()) { - newArray = Array.newInstance(componentType, length); - - for (int i = 0; i < length; i++) { - Object innerArray = Array.get(array, i); - - if (innerArray == null) { - innerArray = Array.newInstance(componentType.getComponentType(), 0); - Array.set(newArray, i, innerArray); - } else { - Array.set(newArray, i, convertNumericArray(innerArray, to)); - } - } - } else { - newArray = Array.newInstance(to, length); - - for (int i = 0; i < length; i++) { - Object what = Array.get(array, i); - - if (to == byte.class || to == Byte.class) { - what = ((Number) what).byteValue(); - } else if (to == double.class || to == Double.class) { - what = ((Number) what).doubleValue(); - } else if (to == float.class || to == Float.class) { - what = ((Number) what).floatValue(); - } else if (to == int.class || to == Integer.class) { - what = ((Number) what).intValue(); - } else if (to == long.class || to == Long.class) { - what = ((Number) what).longValue(); - } else if (to == short.class || to == Short.class) { - what = ((Number) what).shortValue(); - } - - Array.set(newArray, i , what); - } - } - - return newArray; - } - - /** - * Gets the array depth of a given class, for example:
- * Object[] -> 1
- * Object[][][] -> 3 - */ - public static int getArrayDepth(Class cls) { - int depth = 0; - - while (cls.isArray()) { - cls = cls.getComponentType(); - depth++; - } - - return depth; - } - - /** - * @return the component type of the given array class, independent of the depth of the array. - */ - public static Class getBaseComponent(Class obj) { - Class componentType = obj.getComponentType(); - - while (componentType.isArray()) { - componentType = componentType.getComponentType(); - } - - return componentType; - } - - /** - * An functional interface with an input and output that may throw an {@link Exception}. - * @param the input of the function. - * @param the return value of the function. - */ - @FunctionalInterface - public interface ExceptionalFunction { - R apply(T t) throws Exception; - } - - /** - * Converts a {@link ExceptionalFunction} to a normal {@link Function}, by catching the exception - * and logging a warning with the simple class name and message of the exception. - * If Skript's verbosity is set to 'very high' or above, this will also print the stack trace. - */ - public static Function propagateErrors(ExceptionalFunction function) { - return t -> { - try { - return function.apply(t); - } catch (Exception e) { - Skript.warning("skript-reflect encountered a " + e.getClass().getSimpleName() + ": " + e.getMessage()); - - if (Skript.logVeryHigh()) { - StringWriter errors = new StringWriter(); - e.printStackTrace(new PrintWriter(errors)); - Skript.warning(errors.toString()); - } else { - Skript.warning("Run Skript with the verbosity 'very high' for the stack trace."); - } - - } - return null; - }; - } - - /** - * @return whether the given class is a numeric class, albeit primitive or a wrapper of a primitive numeric class. - */ - public static boolean isNumericClass(Class cls) { - return Number.class.isAssignableFrom(cls) || JavaUtil.NUMERIC_CLASSES.contains(cls); - } - - /** - * {@return} a new array with the given class as base component type, and the given length as the array length. - */ - @SuppressWarnings("unchecked") - public static T[] newArray(Class type, int length) { - return (T[]) Array.newInstance(type, length); - } - - /** - * {@return} the array class of the given class. - */ - public static Class getArrayClass(Class type) { - return Array.newInstance(type, 0).getClass(); - } - - /** - * @return the array class with the given depth of the given type, using {@link #getArrayClass(Class)}. - */ - public static Class getArrayClass(Class type, int layers) { - for (int i = 0; i < layers; i++) { - type = getArrayClass(type); - } - - return type; - } - - /** - * @return the string form of a (possibly primitive) array, in the form [a, b, c, ...], - * converting the values to strings using the given {@link Function}. - */ - public static String arrayToString(Object array, Function function) { - int length = Array.getLength(array); - - StringBuilder stringBuilder = new StringBuilder("["); - for (int i = 0; i < length; i++) { - Object value = Array.get(array, i); - stringBuilder.append(function.apply(value)); - - if (i != length - 1) { - stringBuilder.append(", "); - } - } - return stringBuilder.append("]").toString(); - } - - /** - * Returns whether the given {@link Object} can be converted to the given class. - */ - public static boolean canConvert(Object object, Class to) { - if (to.isInstance(object)) { - return true; - } - - // coerce numeric types - if (object instanceof Number && JavaUtil.NUMERIC_CLASSES.contains(to)) { - return true; - } - - // coerce arrays of numeric types - if (to.isArray() && JavaUtil.getArrayDepth(to) == JavaUtil.getArrayDepth(object.getClass())) { - Class paramComponent = JavaUtil.getBaseComponent(to); - Class argComponent = JavaUtil.getBaseComponent(object.getClass()); - - if (JavaUtil.isNumericClass(paramComponent) && JavaUtil.isNumericClass(argComponent)) { - return true; - } - } - - // allow boxed numbers - if (to.isPrimitive() && JavaUtil.WRAPPER_CLASSES.get(to).isInstance(object)) { - return true; - } - - // coerce single character strings to chars - if (object instanceof String - && (to == char.class || to == Character.class) - && ((String) object).length() == 1) { - return true; - } - - // coerce a Skript ItemType to an ItemStack - if (object instanceof ItemType && to == ItemStack.class) { - return true; - } - - // coerce javaclasses and classinfos into classes - if (to == Class.class && (object instanceof JavaType || object instanceof ClassInfo)) { - return true; - } - - // unwrap null wrapper - return !to.isPrimitive() && object instanceof Null; - } - - /** - * Converts the given {@link Object} to the given class. - * If {@link #canConvert(Object, Class)} returned {@code false}, this - * returns the same {@link Object} as was passed to this method. - */ - public static Object convert(Object object, Class to) { - // coerce numeric types - if (object instanceof Number && JavaUtil.NUMERIC_CLASSES.contains(to)) { - if (to == byte.class || to == Byte.class) { - return ((Number) object).byteValue(); - } else if (to == double.class || to == Double.class) { - return ((Number) object).doubleValue(); - } else if (to == float.class || to == Float.class) { - return ((Number) object).floatValue(); - } else if (to == int.class || to == Integer.class) { - return ((Number) object).intValue(); - } else if (to == long.class || to == Long.class) { - return ((Number) object).longValue(); - } else if (to == short.class || to == Short.class) { - return ((Number) object).shortValue(); - } - } - - // coerce arrays of numeric types - if (to.isArray() - && JavaUtil.getArrayDepth(to) == JavaUtil.getArrayDepth(object.getClass()) - && JavaUtil.isNumericClass(JavaUtil.getBaseComponent(to))) { - return JavaUtil.convertNumericArray(object, JavaUtil.getBaseComponent(to)); - } - - // coerce single character strings to chars - if (object instanceof String && (to == char.class || to == Character.class)) { - return ((String) object).charAt(0); - } - - // coerce a Skript ItemType to an ItemStack - if (object instanceof ItemType && to == ItemStack.class) { - return ((ItemType) object).getRandom(); - } - - // coerce javatypes and classinfos into classes - if (to == Class.class) { - if (object instanceof JavaType) { - return ((JavaType) object).getJavaClass(); - } else if (object instanceof ClassInfo) { - return ((ClassInfo) object).getC(); - } - } - - // unwrap null wrapper - if (object instanceof Null) { - return null; - } - - return object; - } + public static final Map, Class> WRAPPER_CLASSES = new HashMap<>(); + public static final Set> NUMERIC_CLASSES = new HashSet<>(); + public static final Map> PRIMITIVE_CLASS_NAMES = new HashMap<>(); + + static { + WRAPPER_CLASSES.put(boolean.class, Boolean.class); + WRAPPER_CLASSES.put(byte.class, Byte.class); + WRAPPER_CLASSES.put(char.class, Character.class); + WRAPPER_CLASSES.put(double.class, Double.class); + WRAPPER_CLASSES.put(float.class, Float.class); + WRAPPER_CLASSES.put(int.class, Integer.class); + WRAPPER_CLASSES.put(long.class, Long.class); + WRAPPER_CLASSES.put(short.class, Short.class); + + NUMERIC_CLASSES.add(byte.class); + NUMERIC_CLASSES.add(double.class); + NUMERIC_CLASSES.add(float.class); + NUMERIC_CLASSES.add(int.class); + NUMERIC_CLASSES.add(long.class); + NUMERIC_CLASSES.add(short.class); + NUMERIC_CLASSES.add(Byte.class); + NUMERIC_CLASSES.add(Double.class); + NUMERIC_CLASSES.add(Float.class); + NUMERIC_CLASSES.add(Integer.class); + NUMERIC_CLASSES.add(Long.class); + NUMERIC_CLASSES.add(Short.class); + + PRIMITIVE_CLASS_NAMES.put("boolean", boolean.class); + PRIMITIVE_CLASS_NAMES.put("byte", byte.class); + PRIMITIVE_CLASS_NAMES.put("char", char.class); + PRIMITIVE_CLASS_NAMES.put("double", double.class); + PRIMITIVE_CLASS_NAMES.put("float", float.class); + PRIMITIVE_CLASS_NAMES.put("int", int.class); + PRIMITIVE_CLASS_NAMES.put("long", long.class); + PRIMITIVE_CLASS_NAMES.put("short", short.class); + } + + /** + * @return a {@link Stream} of {@link Field}s, with the fields declared in the given class, + * and the public fields of the given class, without duplicates. + */ + public static Stream fields(Class cls) { + return Stream.concat( + Arrays.stream(cls.getFields()), + Arrays.stream(cls.getDeclaredFields()) + ).distinct(); + } + + /** + * @return a {@link Stream} of {@link Method}s, with the methods declared in the given class + * and the public methods of the given class, without duplicates. + */ + public static Stream methods(Class cls) { + return Stream.concat( + Arrays.stream(cls.getMethods()), + Arrays.stream(cls.getDeclaredMethods()) + ).distinct(); + } + + /** + * @return a {@link Stream} of the {@link Constructor}s declared in the given class. + */ + public static Stream constructors(Class cls) { + return Arrays.stream(cls.getDeclaredConstructors()); + } + + /** + * Calls {@code toGenericString} on the given {@link Member}, + * returning {@code null} if the given {@link Member} is not + * a {@link Field}, a {@link Method} or a {@link Constructor}. + */ + public static String toGenericString(Member o) { + if (o instanceof Field) { + return ((Field) o).toGenericString(); + } else if (o instanceof Method) { + return ((Method) o).toGenericString(); + } else if (o instanceof Constructor) { + return ((Constructor) o).toGenericString(); + } + return null; + } + + /** + * @return an array of the wrapper type of the component type of the given array (e.g. {@code int[] -> Integer[]}). + * The contents of the array are copied over. + */ + public static Object boxPrimitiveArray(Object obj) { + Class componentType = obj.getClass().getComponentType(); + if (componentType != null && componentType.isPrimitive()) { + int length = Array.getLength(obj); + Object[] boxedArray = newArray(WRAPPER_CLASSES.get(componentType), length); + + for (int i = 0; i < length; i++) { + boxedArray[i] = Array.get(obj, i); + } + + obj = boxedArray; + } + return obj; + } + + /** + * Converts a numeric array to a different numeric class. Also supports arrays with depths higher than {@code 1}. + */ + public static Object convertNumericArray(Object array, Class to) { + Class componentType = array.getClass().getComponentType(); + int length = Array.getLength(array); + + Object newArray; + + if (componentType.isArray()) { + newArray = Array.newInstance(componentType, length); + + for (int i = 0; i < length; i++) { + Object innerArray = Array.get(array, i); + + if (innerArray == null) { + innerArray = Array.newInstance(componentType.getComponentType(), 0); + Array.set(newArray, i, innerArray); + } else { + Array.set(newArray, i, convertNumericArray(innerArray, to)); + } + } + } else { + newArray = Array.newInstance(to, length); + + for (int i = 0; i < length; i++) { + Object what = Array.get(array, i); + + if (to == byte.class || to == Byte.class) { + what = ((Number) what).byteValue(); + } else if (to == double.class || to == Double.class) { + what = ((Number) what).doubleValue(); + } else if (to == float.class || to == Float.class) { + what = ((Number) what).floatValue(); + } else if (to == int.class || to == Integer.class) { + what = ((Number) what).intValue(); + } else if (to == long.class || to == Long.class) { + what = ((Number) what).longValue(); + } else if (to == short.class || to == Short.class) { + what = ((Number) what).shortValue(); + } + + Array.set(newArray, i , what); + } + } + + return newArray; + } + + /** + * Gets the array depth of a given class, for example:
+ * Object[] -> 1
+ * Object[][][] -> 3 + */ + public static int getArrayDepth(Class cls) { + int depth = 0; + + while (cls.isArray()) { + cls = cls.getComponentType(); + depth++; + } + + return depth; + } + + /** + * @return the component type of the given array class, independent of the depth of the array. + */ + public static Class getBaseComponent(Class obj) { + Class componentType = obj.getComponentType(); + + while (componentType.isArray()) { + componentType = componentType.getComponentType(); + } + + return componentType; + } + + /** + * An functional interface with an input and output that may throw an {@link Exception}. + * @param the input of the function. + * @param the return value of the function. + */ + @FunctionalInterface + public interface ExceptionalFunction { + R apply(T t) throws Exception; + } + + /** + * Converts a {@link ExceptionalFunction} to a normal {@link Function}, by catching the exception + * and logging a warning with the simple class name and message of the exception. + * If Skript's verbosity is set to 'very high' or above, this will also print the stack trace. + */ + public static Function propagateErrors(ExceptionalFunction function) { + return t -> { + try { + return function.apply(t); + } catch (Exception e) { + Skript.warning("skript-reflect encountered a " + e.getClass().getSimpleName() + ": " + e.getMessage()); + + if (Skript.logVeryHigh()) { + StringWriter errors = new StringWriter(); + e.printStackTrace(new PrintWriter(errors)); + Skript.warning(errors.toString()); + } else { + Skript.warning("Run Skript with the verbosity 'very high' for the stack trace."); + } + + } + return null; + }; + } + + /** + * @return whether the given class is a numeric class, albeit primitive or a wrapper of a primitive numeric class. + */ + public static boolean isNumericClass(Class cls) { + return Number.class.isAssignableFrom(cls) || JavaUtil.NUMERIC_CLASSES.contains(cls); + } + + /** + * {@return} a new array with the given class as base component type, and the given length as the array length. + */ + @SuppressWarnings("unchecked") + public static T[] newArray(Class type, int length) { + return (T[]) Array.newInstance(type, length); + } + + /** + * {@return} the array class of the given class. + */ + public static Class getArrayClass(Class type) { + return Array.newInstance(type, 0).getClass(); + } + + /** + * @return the array class with the given depth of the given type, using {@link #getArrayClass(Class)}. + */ + public static Class getArrayClass(Class type, int layers) { + for (int i = 0; i < layers; i++) { + type = getArrayClass(type); + } + + return type; + } + + /** + * @return the string form of a (possibly primitive) array, in the form [a, b, c, ...], + * converting the values to strings using the given {@link Function}. + */ + public static String arrayToString(Object array, Function function) { + int length = Array.getLength(array); + + StringBuilder stringBuilder = new StringBuilder("["); + for (int i = 0; i < length; i++) { + Object value = Array.get(array, i); + stringBuilder.append(function.apply(value)); + + if (i != length - 1) { + stringBuilder.append(", "); + } + } + return stringBuilder.append("]").toString(); + } + + /** + * Returns whether the given {@link Object} can be converted to the given class. + */ + public static boolean canConvert(Object object, Class to) { + if (to.isInstance(object)) { + return true; + } + + // coerce numeric types + if (object instanceof Number && JavaUtil.NUMERIC_CLASSES.contains(to)) { + return true; + } + + // coerce arrays of numeric types + if (to.isArray() && JavaUtil.getArrayDepth(to) == JavaUtil.getArrayDepth(object.getClass())) { + Class paramComponent = JavaUtil.getBaseComponent(to); + Class argComponent = JavaUtil.getBaseComponent(object.getClass()); + + if (JavaUtil.isNumericClass(paramComponent) && JavaUtil.isNumericClass(argComponent)) { + return true; + } + } + + // allow boxed numbers + if (to.isPrimitive() && JavaUtil.WRAPPER_CLASSES.get(to).isInstance(object)) { + return true; + } + + // coerce single character strings to chars + if (object instanceof String + && (to == char.class || to == Character.class) + && ((String) object).length() == 1) { + return true; + } + + // coerce a Skript ItemType to an ItemStack + if (object instanceof ItemType && to == ItemStack.class) { + return true; + } + + // coerce javaclasses and classinfos into classes + if (to == Class.class && (object instanceof JavaType || object instanceof ClassInfo)) { + return true; + } + + // unwrap null wrapper + return !to.isPrimitive() && object instanceof Null; + } + + /** + * Converts the given {@link Object} to the given class. + * If {@link #canConvert(Object, Class)} returned {@code false}, this + * returns the same {@link Object} as was passed to this method. + */ + public static Object convert(Object object, Class to) { + // coerce numeric types + if (object instanceof Number && JavaUtil.NUMERIC_CLASSES.contains(to)) { + if (to == byte.class || to == Byte.class) { + return ((Number) object).byteValue(); + } else if (to == double.class || to == Double.class) { + return ((Number) object).doubleValue(); + } else if (to == float.class || to == Float.class) { + return ((Number) object).floatValue(); + } else if (to == int.class || to == Integer.class) { + return ((Number) object).intValue(); + } else if (to == long.class || to == Long.class) { + return ((Number) object).longValue(); + } else if (to == short.class || to == Short.class) { + return ((Number) object).shortValue(); + } + } + + // coerce arrays of numeric types + if (to.isArray() + && JavaUtil.getArrayDepth(to) == JavaUtil.getArrayDepth(object.getClass()) + && JavaUtil.isNumericClass(JavaUtil.getBaseComponent(to))) { + return JavaUtil.convertNumericArray(object, JavaUtil.getBaseComponent(to)); + } + + // coerce single character strings to chars + if (object instanceof String && (to == char.class || to == Character.class)) { + return ((String) object).charAt(0); + } + + // coerce a Skript ItemType to an ItemStack + if (object instanceof ItemType && to == ItemStack.class) { + return ((ItemType) object).getRandom(); + } + + // coerce javatypes and classinfos into classes + if (to == Class.class) { + if (object instanceof JavaType) { + return ((JavaType) object).getJavaClass(); + } else if (object instanceof ClassInfo) { + return ((ClassInfo) object).getC(); + } + } + + // unwrap null wrapper + if (object instanceof Null) { + return null; + } + + return object; + } } diff --git a/src/main/java/com/btk5h/skriptmirror/util/LRUCache.java b/src/main/java/com/btk5h/skriptmirror/util/LRUCache.java index ac1e88eb..97a10404 100644 --- a/src/main/java/com/btk5h/skriptmirror/util/LRUCache.java +++ b/src/main/java/com/btk5h/skriptmirror/util/LRUCache.java @@ -5,16 +5,16 @@ public class LRUCache extends LinkedHashMap { - private final int cacheSize; + private final int cacheSize; - public LRUCache(int cacheSize) { - super(16, 0.75F, true); - this.cacheSize = cacheSize; - } + public LRUCache(int cacheSize) { + super(16, 0.75F, true); + this.cacheSize = cacheSize; + } - @Override - protected boolean removeEldestEntry(Map.Entry eldest) { - return size() >= cacheSize; - } + @Override + protected boolean removeEldestEntry(Map.Entry eldest) { + return size() >= cacheSize; + } } diff --git a/src/main/java/com/btk5h/skriptmirror/util/SkriptMirrorUtil.java b/src/main/java/com/btk5h/skriptmirror/util/SkriptMirrorUtil.java index 50c9f16b..5fc1a7bc 100644 --- a/src/main/java/com/btk5h/skriptmirror/util/SkriptMirrorUtil.java +++ b/src/main/java/com/btk5h/skriptmirror/util/SkriptMirrorUtil.java @@ -13,113 +13,113 @@ public class SkriptMirrorUtil { - /** - * A word ($ also an allowed char) that doesn't start with a digit. - */ - public static final String IDENTIFIER = "[_a-zA-Z$][\\w$]*"; - /** - * A full classname (e.g. java.lang.String) - */ - public static final String PACKAGE = "(?:" + IDENTIFIER + "\\.)*(?:" + IDENTIFIER + ")"; - - private static final Pattern TYPE_PREFIXES = Pattern.compile("^[-*~]*"); - - /** - * @return the {@link Class} of this {@link JavaType}, if it is a {@link JavaType}, - * otherwise it returns {@link #getClass(Object)} of this object. - */ - public static Class toClassUnwrapJavaTypes(Object o) { - if (o instanceof JavaType) { - return ((JavaType) o).getJavaClass(); - } - - return getClass(o); - } - - public static String getDebugName(Class cls) { - return Skript.logVeryHigh() ? cls.getName() : cls.getSimpleName(); - } - - /** - * The given object is first possibly unwrapped using {@link ObjectWrapper#unwrapIfNecessary(Object)}. - * Then returns the class of the object, or {@code Object.class}, if the object is {@code null}. - */ - public static Class getClass(Object o) { - o = ObjectWrapper.unwrapIfNecessary(o); - - if (o == null) { - return Object.class; - } - - return o.getClass(); - } - - /** - * Returns the given pattern, with all types starting with an underscore - * replaced with {@code javaobject(s)}, as those types are just context indicators. - */ - public static String preprocessPattern(String pattern) { - StringBuilder newPattern = new StringBuilder(pattern.length()); - String[] parts = pattern.split("%"); - - for (int i = 0; i < parts.length; i++) { - String part = parts[i]; - if (i % 2 == 0) { - newPattern.append(part); - } else { - if (part.startsWith("_")) { - part = Utils.getEnglishPlural(part).getSecond() ? "javaobjects" : "javaobject"; - } else { - part = processTypes(part); - } - - newPattern.append('%'); - newPattern.append(part); - newPattern.append('%'); - } - } - - return newPattern.toString(); - } - - /** - * Returns the given type string, using {@link SkriptUtil#replaceUserInputPatterns(String)} - * on each type in the given string. - */ - public static String processTypes(String part) { - if (part.length() > 0) { - // copy all prefixes - String prefixes = ""; - Matcher prefixMatcher = TYPE_PREFIXES.matcher(part); - if (prefixMatcher.find()) { - prefixes = prefixMatcher.group(); - } - part = part.substring(prefixes.length()); - - // copy all suffixes - String suffixes = ""; - int timeIndex = part.indexOf("@"); - if (timeIndex != -1) { - suffixes = part.substring(timeIndex); - part = part.substring(0, timeIndex); - } - - // replace user input patterns - String types = Arrays.stream(part.split("/")) - .map(SkriptUtil::replaceUserInputPatterns) - .collect(Collectors.joining("/")); - - return prefixes + types + suffixes; - } - return part; - } - - /** - * @return {@link Null#getInstance()} if the given object is {@code null}, - * otherwise returns the given object itself. - */ - public static Object reifyIfNull(Object o) { - return o == null ? Null.getInstance() : o; - } + /** + * A word ($ also an allowed char) that doesn't start with a digit. + */ + public static final String IDENTIFIER = "[_a-zA-Z$][\\w$]*"; + /** + * A full classname (e.g. java.lang.String) + */ + public static final String PACKAGE = "(?:" + IDENTIFIER + "\\.)*(?:" + IDENTIFIER + ")"; + + private static final Pattern TYPE_PREFIXES = Pattern.compile("^[-*~]*"); + + /** + * @return the {@link Class} of this {@link JavaType}, if it is a {@link JavaType}, + * otherwise it returns {@link #getClass(Object)} of this object. + */ + public static Class toClassUnwrapJavaTypes(Object o) { + if (o instanceof JavaType) { + return ((JavaType) o).getJavaClass(); + } + + return getClass(o); + } + + public static String getDebugName(Class cls) { + return Skript.logVeryHigh() ? cls.getName() : cls.getSimpleName(); + } + + /** + * The given object is first possibly unwrapped using {@link ObjectWrapper#unwrapIfNecessary(Object)}. + * Then returns the class of the object, or {@code Object.class}, if the object is {@code null}. + */ + public static Class getClass(Object o) { + o = ObjectWrapper.unwrapIfNecessary(o); + + if (o == null) { + return Object.class; + } + + return o.getClass(); + } + + /** + * Returns the given pattern, with all types starting with an underscore + * replaced with {@code javaobject(s)}, as those types are just context indicators. + */ + public static String preprocessPattern(String pattern) { + StringBuilder newPattern = new StringBuilder(pattern.length()); + String[] parts = pattern.split("%"); + + for (int i = 0; i < parts.length; i++) { + String part = parts[i]; + if (i % 2 == 0) { + newPattern.append(part); + } else { + if (part.startsWith("_")) { + part = Utils.getEnglishPlural(part).getSecond() ? "javaobjects" : "javaobject"; + } else { + part = processTypes(part); + } + + newPattern.append('%'); + newPattern.append(part); + newPattern.append('%'); + } + } + + return newPattern.toString(); + } + + /** + * Returns the given type string, using {@link SkriptUtil#replaceUserInputPatterns(String)} + * on each type in the given string. + */ + public static String processTypes(String part) { + if (part.length() > 0) { + // copy all prefixes + String prefixes = ""; + Matcher prefixMatcher = TYPE_PREFIXES.matcher(part); + if (prefixMatcher.find()) { + prefixes = prefixMatcher.group(); + } + part = part.substring(prefixes.length()); + + // copy all suffixes + String suffixes = ""; + int timeIndex = part.indexOf("@"); + if (timeIndex != -1) { + suffixes = part.substring(timeIndex); + part = part.substring(0, timeIndex); + } + + // replace user input patterns + String types = Arrays.stream(part.split("/")) + .map(SkriptUtil::replaceUserInputPatterns) + .collect(Collectors.joining("/")); + + return prefixes + types + suffixes; + } + return part; + } + + /** + * @return {@link Null#getInstance()} if the given object is {@code null}, + * otherwise returns the given object itself. + */ + public static Object reifyIfNull(Object o) { + return o == null ? Null.getInstance() : o; + } } diff --git a/src/main/java/com/btk5h/skriptmirror/util/SkriptReflection.java b/src/main/java/com/btk5h/skriptmirror/util/SkriptReflection.java index 6c6f41d8..38e45853 100644 --- a/src/main/java/com/btk5h/skriptmirror/util/SkriptReflection.java +++ b/src/main/java/com/btk5h/skriptmirror/util/SkriptReflection.java @@ -29,286 +29,286 @@ @SuppressWarnings("unchecked") public class SkriptReflection { - private static Field PATTERNS; - private static Field LOCAL_VARIABLES; - private static Field NODES; - private static Method VARIABLES_MAP_COPY; - private static Field DEFAULT_EXPRESSION; - private static Field PARSED_VALUE; - private static Field EXPRESSIONS; - private static Field OPTIONS; - - static { - Field _FIELD; - Method _METHOD; - - try { - _FIELD = SyntaxElementInfo.class.getDeclaredField("patterns"); - _FIELD.setAccessible(true); - PATTERNS = _FIELD; - } catch (NoSuchFieldException e) { - warning("Skript's pattern info field could not be resolved. " + - "Custom syntax and imports will not work."); - } - - try { - _FIELD = Variables.class.getDeclaredField("localVariables"); - _FIELD.setAccessible(true); - LOCAL_VARIABLES = _FIELD; - } catch (NoSuchFieldException e) { - warning("Skript's local variables field could not be resolved."); - } - - try { - _FIELD = SectionNode.class.getDeclaredField("nodes"); - _FIELD.setAccessible(true); - NODES = _FIELD; - } catch (NoSuchFieldException e) { - warning("Skript's nodes field could not be resolved, therefore custom syntax and sections won't work."); - } - - try { - Class variablesMap = Class.forName("ch.njol.skript.variables.VariablesMap"); - - try { - _METHOD = variablesMap.getDeclaredMethod("copy"); - _METHOD.setAccessible(true); - VARIABLES_MAP_COPY = _METHOD; - } catch (NoSuchMethodException e) { - warning("Skript's variables map 'copy' method could not be resolved."); - } - } catch (ClassNotFoundException e) { - warning("Skript's variables map class could not be resolved."); - } - - try { - _FIELD = ClassInfo.class.getDeclaredField("defaultExpression"); - _FIELD.setAccessible(true); - DEFAULT_EXPRESSION = _FIELD; - } catch (NoSuchFieldException e) { - warning("Skript's default expression field could not be resolved, " + - "therefore event-values won't work in custom events"); - } - - try { - _FIELD = Option.class.getDeclaredField("parsedValue"); - _FIELD.setAccessible(true); - PARSED_VALUE = _FIELD; - } catch (NoSuchFieldException e) { - warning("Skript's parsed value field could not be resolved, " + - "therefore and/or warnings won't be suppressed"); - } - - try { - _FIELD = Skript.class.getDeclaredField("expressions"); - _FIELD.setAccessible(true); - EXPRESSIONS = _FIELD; - } catch (NoSuchFieldException e) { - warning("Skript's expressions field could not be resolved, " + - "therefore you might get syntax conflict problems"); - } - - try { - _FIELD = StructOptions.OptionsData.class.getDeclaredField("options"); - _FIELD.setAccessible(true); - OPTIONS = _FIELD; - } catch (NoSuchFieldException e) { - warning("Skript's options field could not be resolved, computed options won't work"); - } - } - - private static void warning(String message) { - SkriptMirror.getInstance().getLogger().warning(message); - } - - public static void setPatterns(SyntaxElementInfo info, String[] patterns) { - if (PATTERNS == null) - return; - - try { - PATTERNS.set(info, patterns); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } - } - - /** - * Sets the local variables of an {@link Event} to the given local variables. - */ - @SuppressWarnings("unchecked") - public static void putLocals(Object originalVariablesMap, Event to) { - if (originalVariablesMap == null) { - removeLocals(to); - return; - } - - try { - Map localVariables = (Map) LOCAL_VARIABLES.get(null); - - localVariables.put(to, originalVariablesMap); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - } - - /** - * Removes and returns the local variables from the given {@link Event}. - */ - @SuppressWarnings("unchecked") - public static Object removeLocals(Event event) { - try { - Map localVariables = (Map) LOCAL_VARIABLES.get(null); - return localVariables.remove(event); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - } - - /** - * Retrieves the local variables from an {@link Event}. - * @param event The {@link Event} to get the local variables from. - * @return The local variables of the given {@link Event}. - */ - @SuppressWarnings("unchecked") - public static Object getLocals(Event event) { - try { - Map localVariables = (Map) LOCAL_VARIABLES.get(null); - return localVariables.get(event); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - } - - /** - * Copies the VariablesMap contained in the given {@link Object}. - * @param locals The local variables to copy. - * @return The copied local variables. - */ - public static Object copyLocals(Object locals) { - if (locals == null) - return null; - - try { - return VARIABLES_MAP_COPY.invoke(locals); - } catch (IllegalAccessException e) { - throw new IllegalStateException(e); // setAccessible called - } catch (InvocationTargetException e) { - throw new RuntimeException(e); - } - } - - /** - * Retrieves the {@link Node}s of a {@link SectionNode}. - * @param sectionNode The {@link SectionNode} to get the nodes from. - * @return The {@link Node}s of the given {@link SectionNode} - */ - @SuppressWarnings("unchecked") - public static ArrayList getNodes(SectionNode sectionNode) { - if (NODES == null) - return new ArrayList<>(); - - try { - return (ArrayList) NODES.get(sectionNode); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - } - - /** - * Replaces the event-values of a list of {@link ClassInfo}s with - * {@link ExprReplacedEventValue}'s to make them work in custom events. - * - * @param classInfoList A list of {@link ClassInfo}s to replace - */ - public static void replaceEventValues(List> classInfoList) { - if (DEFAULT_EXPRESSION == null) - return; - - try { - List> replaceExtraList = new ArrayList<>(); - for (ClassInfo classInfo : classInfoList) { - DefaultExpression defaultExpression = classInfo.getDefaultExpression(); - if (defaultExpression instanceof EventValueExpression && !(defaultExpression instanceof ExprReplacedEventValue)) { - DEFAULT_EXPRESSION.set(classInfo, - new ExprReplacedEventValue<>((EventValueExpression) defaultExpression)); - - replaceExtraList.add(classInfo); - } - } - - replaceExtraList.forEach(SkriptReflection::replaceExtra); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - } - - /** - * Replaces {@link ClassInfo}s related to the given {@link ClassInfo}. - */ - public static void replaceExtra(ClassInfo classInfo) { - List> classInfoList = Classes.getClassInfos().stream() - .filter(loopedClassInfo -> !(loopedClassInfo.getDefaultExpression() instanceof ExprReplacedEventValue)) - .filter(loopedClassInfo -> classInfo.getC().isAssignableFrom(loopedClassInfo.getC()) - || loopedClassInfo.getC().isAssignableFrom(classInfo.getC())) - .collect(Collectors.toList()); - replaceEventValues(classInfoList); - } - - /** - * Disable Skript's missing and / or warnings. - */ - public static void disableAndOrWarnings() { - if (PARSED_VALUE == null) - return; - - Option option = SkriptConfig.disableMissingAndOrWarnings; - if (!option.value()) { - try { - PARSED_VALUE.set(option, true); - } catch (IllegalAccessException e) { - throw new RuntimeException(); - } - } - } - - /** - * {@return} a list of all of Skript's registered {@link ch.njol.skript.lang.Expression}s. - */ - public static List> getExpressions() { - if (EXPRESSIONS == null) - return new ArrayList<>(); - - try { - return (List>) EXPRESSIONS.get(null); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - } - - /** - * Gets the modifiable options map from an options data object. - * - * @param script the script to get the options from. - * @return the modifiable options map. - * - * @throws NullPointerException if the given options data object is null. - * @throws IllegalStateException if skript-reflect could not find the modifiable options map. - */ - public static Map getOptions(Script script) { - if (script == null) - throw new NullPointerException(); - - if (OPTIONS == null) - throw new IllegalStateException("OPTIONS field not initialized, computed options cannot be used"); - - StructOptions.OptionsData optionsData = script.getData(StructOptions.OptionsData.class, - StructOptions.OptionsData::new); - - try { - return (Map) OPTIONS.get(optionsData); - } catch (IllegalAccessException e) { - throw new IllegalStateException(e); // setAccessible called - } - } + private static Field PATTERNS; + private static Field LOCAL_VARIABLES; + private static Field NODES; + private static Method VARIABLES_MAP_COPY; + private static Field DEFAULT_EXPRESSION; + private static Field PARSED_VALUE; + private static Field EXPRESSIONS; + private static Field OPTIONS; + + static { + Field _FIELD; + Method _METHOD; + + try { + _FIELD = SyntaxElementInfo.class.getDeclaredField("patterns"); + _FIELD.setAccessible(true); + PATTERNS = _FIELD; + } catch (NoSuchFieldException e) { + warning("Skript's pattern info field could not be resolved. " + + "Custom syntax and imports will not work."); + } + + try { + _FIELD = Variables.class.getDeclaredField("localVariables"); + _FIELD.setAccessible(true); + LOCAL_VARIABLES = _FIELD; + } catch (NoSuchFieldException e) { + warning("Skript's local variables field could not be resolved."); + } + + try { + _FIELD = SectionNode.class.getDeclaredField("nodes"); + _FIELD.setAccessible(true); + NODES = _FIELD; + } catch (NoSuchFieldException e) { + warning("Skript's nodes field could not be resolved, therefore custom syntax and sections won't work."); + } + + try { + Class variablesMap = Class.forName("ch.njol.skript.variables.VariablesMap"); + + try { + _METHOD = variablesMap.getDeclaredMethod("copy"); + _METHOD.setAccessible(true); + VARIABLES_MAP_COPY = _METHOD; + } catch (NoSuchMethodException e) { + warning("Skript's variables map 'copy' method could not be resolved."); + } + } catch (ClassNotFoundException e) { + warning("Skript's variables map class could not be resolved."); + } + + try { + _FIELD = ClassInfo.class.getDeclaredField("defaultExpression"); + _FIELD.setAccessible(true); + DEFAULT_EXPRESSION = _FIELD; + } catch (NoSuchFieldException e) { + warning("Skript's default expression field could not be resolved, " + + "therefore event-values won't work in custom events"); + } + + try { + _FIELD = Option.class.getDeclaredField("parsedValue"); + _FIELD.setAccessible(true); + PARSED_VALUE = _FIELD; + } catch (NoSuchFieldException e) { + warning("Skript's parsed value field could not be resolved, " + + "therefore and/or warnings won't be suppressed"); + } + + try { + _FIELD = Skript.class.getDeclaredField("expressions"); + _FIELD.setAccessible(true); + EXPRESSIONS = _FIELD; + } catch (NoSuchFieldException e) { + warning("Skript's expressions field could not be resolved, " + + "therefore you might get syntax conflict problems"); + } + + try { + _FIELD = StructOptions.OptionsData.class.getDeclaredField("options"); + _FIELD.setAccessible(true); + OPTIONS = _FIELD; + } catch (NoSuchFieldException e) { + warning("Skript's options field could not be resolved, computed options won't work"); + } + } + + private static void warning(String message) { + SkriptMirror.getInstance().getLogger().warning(message); + } + + public static void setPatterns(SyntaxElementInfo info, String[] patterns) { + if (PATTERNS == null) + return; + + try { + PATTERNS.set(info, patterns); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } + + /** + * Sets the local variables of an {@link Event} to the given local variables. + */ + @SuppressWarnings("unchecked") + public static void putLocals(Object originalVariablesMap, Event to) { + if (originalVariablesMap == null) { + removeLocals(to); + return; + } + + try { + Map localVariables = (Map) LOCAL_VARIABLES.get(null); + + localVariables.put(to, originalVariablesMap); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + /** + * Removes and returns the local variables from the given {@link Event}. + */ + @SuppressWarnings("unchecked") + public static Object removeLocals(Event event) { + try { + Map localVariables = (Map) LOCAL_VARIABLES.get(null); + return localVariables.remove(event); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + /** + * Retrieves the local variables from an {@link Event}. + * @param event The {@link Event} to get the local variables from. + * @return The local variables of the given {@link Event}. + */ + @SuppressWarnings("unchecked") + public static Object getLocals(Event event) { + try { + Map localVariables = (Map) LOCAL_VARIABLES.get(null); + return localVariables.get(event); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + /** + * Copies the VariablesMap contained in the given {@link Object}. + * @param locals The local variables to copy. + * @return The copied local variables. + */ + public static Object copyLocals(Object locals) { + if (locals == null) + return null; + + try { + return VARIABLES_MAP_COPY.invoke(locals); + } catch (IllegalAccessException e) { + throw new IllegalStateException(e); // setAccessible called + } catch (InvocationTargetException e) { + throw new RuntimeException(e); + } + } + + /** + * Retrieves the {@link Node}s of a {@link SectionNode}. + * @param sectionNode The {@link SectionNode} to get the nodes from. + * @return The {@link Node}s of the given {@link SectionNode} + */ + @SuppressWarnings("unchecked") + public static ArrayList getNodes(SectionNode sectionNode) { + if (NODES == null) + return new ArrayList<>(); + + try { + return (ArrayList) NODES.get(sectionNode); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + /** + * Replaces the event-values of a list of {@link ClassInfo}s with + * {@link ExprReplacedEventValue}'s to make them work in custom events. + * + * @param classInfoList A list of {@link ClassInfo}s to replace + */ + public static void replaceEventValues(List> classInfoList) { + if (DEFAULT_EXPRESSION == null) + return; + + try { + List> replaceExtraList = new ArrayList<>(); + for (ClassInfo classInfo : classInfoList) { + DefaultExpression defaultExpression = classInfo.getDefaultExpression(); + if (defaultExpression instanceof EventValueExpression && !(defaultExpression instanceof ExprReplacedEventValue)) { + DEFAULT_EXPRESSION.set(classInfo, + new ExprReplacedEventValue<>((EventValueExpression) defaultExpression)); + + replaceExtraList.add(classInfo); + } + } + + replaceExtraList.forEach(SkriptReflection::replaceExtra); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + /** + * Replaces {@link ClassInfo}s related to the given {@link ClassInfo}. + */ + public static void replaceExtra(ClassInfo classInfo) { + List> classInfoList = Classes.getClassInfos().stream() + .filter(loopedClassInfo -> !(loopedClassInfo.getDefaultExpression() instanceof ExprReplacedEventValue)) + .filter(loopedClassInfo -> classInfo.getC().isAssignableFrom(loopedClassInfo.getC()) + || loopedClassInfo.getC().isAssignableFrom(classInfo.getC())) + .collect(Collectors.toList()); + replaceEventValues(classInfoList); + } + + /** + * Disable Skript's missing and / or warnings. + */ + public static void disableAndOrWarnings() { + if (PARSED_VALUE == null) + return; + + Option option = SkriptConfig.disableMissingAndOrWarnings; + if (!option.value()) { + try { + PARSED_VALUE.set(option, true); + } catch (IllegalAccessException e) { + throw new RuntimeException(); + } + } + } + + /** + * {@return} a list of all of Skript's registered {@link ch.njol.skript.lang.Expression}s. + */ + public static List> getExpressions() { + if (EXPRESSIONS == null) + return new ArrayList<>(); + + try { + return (List>) EXPRESSIONS.get(null); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + /** + * Gets the modifiable options map from an options data object. + * + * @param script the script to get the options from. + * @return the modifiable options map. + * + * @throws NullPointerException if the given options data object is null. + * @throws IllegalStateException if skript-reflect could not find the modifiable options map. + */ + public static Map getOptions(Script script) { + if (script == null) + throw new NullPointerException(); + + if (OPTIONS == null) + throw new IllegalStateException("OPTIONS field not initialized, computed options cannot be used"); + + StructOptions.OptionsData optionsData = script.getData(StructOptions.OptionsData.class, + StructOptions.OptionsData::new); + + try { + return (Map) OPTIONS.get(optionsData); + } catch (IllegalAccessException e) { + throw new IllegalStateException(e); // setAccessible called + } + } } diff --git a/src/main/java/com/btk5h/skriptmirror/util/SkriptUtil.java b/src/main/java/com/btk5h/skriptmirror/util/SkriptUtil.java index 17df4f7d..e4055665 100644 --- a/src/main/java/com/btk5h/skriptmirror/util/SkriptUtil.java +++ b/src/main/java/com/btk5h/skriptmirror/util/SkriptUtil.java @@ -32,145 +32,145 @@ public class SkriptUtil { - /** - * Returns the given {@link Expression}, unless it is (or has) an {@link UnparsedLiteral}, - * in which case every {@link UnparsedLiteral} will be parsed, and returned if successful. - * - * Can also be used as an alternative to casting to a generic type. - */ - @SuppressWarnings("unchecked") - public static Expression defendExpression(Expression expr) { - if (expr instanceof UnparsedLiteral) { - Literal parsed = ((UnparsedLiteral) expr).getConvertedExpression(Object.class); - return (Expression) (parsed == null ? expr : parsed); - } else if (expr instanceof ExpressionList) { - Expression[] exprs = ((ExpressionList) expr).getExpressions(); - for (int i = 0; i < exprs.length; i++) { - exprs[i] = defendExpression(exprs[i]); - } - } - return (Expression) expr; - } - - /** - * @return whether the given {@link Expression} is / has an {@link UnparsedLiteral}. - */ - public static boolean hasUnparsedLiteral(Expression expr) { - if (expr instanceof UnparsedLiteral) - return true; - - if (expr instanceof ExpressionList) { - Expression[] expressions = ((ExpressionList) expr).getExpressions(); - for (Expression expression : expressions) { - if (expression instanceof UnparsedLiteral) - return true; - } - } - - return false; - } - - /** - * @return whether the given {@link Expression}s contain any {@link UnparsedLiteral}, - * checked using {@link #hasUnparsedLiteral(Expression)}. - */ - public static boolean canInitSafely(Expression... expressions) { - return Arrays.stream(expressions) - .filter(Objects::nonNull) - .noneMatch(SkriptUtil::hasUnparsedLiteral); - } - - /** - * @return the {@link TriggerItem}s in the given {@link SectionNode}, - * using {@link ScriptLoader#loadItems(SectionNode)}. - */ - public static List getItemsFromNode(SectionNode node) { - RetainingLogHandler log = SkriptLogger.startRetainingLog(); - try { - return ScriptLoader.loadItems(node); - } finally { - log.printLog(); - ParserInstance.get().deleteCurrentEvent(); - } - } - - /** - * Deletes all the nodes in the given {@link SectionNode}. - */ - public static void clearSectionNode(SectionNode node) { - List subNodes = new ArrayList<>(); - node.forEach(subNodes::add); - subNodes.forEach(Node::remove); - } - - /** - * {@return} the {@link ParserInstance#getCurrentScript()} as a {@link File}. - */ - public static File getCurrentScriptFile() { - return Optional.ofNullable(getCurrentScript()) - .map(Script::getConfig) - .map(Config::getFile) - .orElse(null); - } - - public static Script getCurrentScript() { - return Optional.of(ParserInstance.get()) - .filter(ParserInstance::isActive) - .map(ParserInstance::getCurrentScript) - .orElse(null); - } - - /** - * Gets the {@link ClassInfo} by first converting the given string to a singular. - * Returns {@code Object.class}'s if no {@link ClassInfo} can be found for the given type. - */ - @NonNull - public static ClassInfo getUserClassInfo(String name) { - NonNullPair wordData = Utils.getEnglishPlural(name); - - ClassInfo ci = Classes.getClassInfoNoError(wordData.getFirst()); - - if (ci == null) { - ci = Classes.getClassInfoFromUserInput(wordData.getFirst()); - } - - if (ci == null) { - Skript.warning(String.format("'%s' is not a valid Skript type. Using 'object' instead.", name)); - return DefaultClasses.OBJECT; - } - - return ci; - } - - /** - * @return the pair of the {@link ClassInfo} in the given string, and whether is is singular. - */ - public static NonNullPair, Boolean> getUserClassInfoAndPlural(String name) { - NonNullPair wordData = Utils.getEnglishPlural(name); - ClassInfo ci = getUserClassInfo(name); - - return new NonNullPair<>(ci, wordData.getSecond()); - } - - /** - * @return the singular form of the given string type, - * converted back to plural if it was plural in the first place. - * This causes the string type to always be the default codename for the {@link ClassInfo}. - */ - public static String replaceUserInputPatterns(String name) { - NonNullPair wordData = Utils.getEnglishPlural(name); - ClassInfo ci = getUserClassInfo(name); - - return Utils.toEnglishPlural(ci.getCodeName(), wordData.getSecond()); - } - - /** - * {@return} a {@link Function} to get a {@link Expression}'s value, - * using {@link Expression#getSingle(Event)} if {@link Expression#getSingle(Event)} - * returns {@code true}, otherwise returning {@link Expression#getArray(Event)}. - */ - public static Function, Object> unwrapWithEvent(Event e) { - return expr -> expr.isSingle() ? expr.getSingle(e) : expr.getArray(e); - } + /** + * Returns the given {@link Expression}, unless it is (or has) an {@link UnparsedLiteral}, + * in which case every {@link UnparsedLiteral} will be parsed, and returned if successful. + * + * Can also be used as an alternative to casting to a generic type. + */ + @SuppressWarnings("unchecked") + public static Expression defendExpression(Expression expr) { + if (expr instanceof UnparsedLiteral) { + Literal parsed = ((UnparsedLiteral) expr).getConvertedExpression(Object.class); + return (Expression) (parsed == null ? expr : parsed); + } else if (expr instanceof ExpressionList) { + Expression[] exprs = ((ExpressionList) expr).getExpressions(); + for (int i = 0; i < exprs.length; i++) { + exprs[i] = defendExpression(exprs[i]); + } + } + return (Expression) expr; + } + + /** + * @return whether the given {@link Expression} is / has an {@link UnparsedLiteral}. + */ + public static boolean hasUnparsedLiteral(Expression expr) { + if (expr instanceof UnparsedLiteral) + return true; + + if (expr instanceof ExpressionList) { + Expression[] expressions = ((ExpressionList) expr).getExpressions(); + for (Expression expression : expressions) { + if (expression instanceof UnparsedLiteral) + return true; + } + } + + return false; + } + + /** + * @return whether the given {@link Expression}s contain any {@link UnparsedLiteral}, + * checked using {@link #hasUnparsedLiteral(Expression)}. + */ + public static boolean canInitSafely(Expression... expressions) { + return Arrays.stream(expressions) + .filter(Objects::nonNull) + .noneMatch(SkriptUtil::hasUnparsedLiteral); + } + + /** + * @return the {@link TriggerItem}s in the given {@link SectionNode}, + * using {@link ScriptLoader#loadItems(SectionNode)}. + */ + public static List getItemsFromNode(SectionNode node) { + RetainingLogHandler log = SkriptLogger.startRetainingLog(); + try { + return ScriptLoader.loadItems(node); + } finally { + log.printLog(); + ParserInstance.get().deleteCurrentEvent(); + } + } + + /** + * Deletes all the nodes in the given {@link SectionNode}. + */ + public static void clearSectionNode(SectionNode node) { + List subNodes = new ArrayList<>(); + node.forEach(subNodes::add); + subNodes.forEach(Node::remove); + } + + /** + * {@return} the {@link ParserInstance#getCurrentScript()} as a {@link File}. + */ + public static File getCurrentScriptFile() { + return Optional.ofNullable(getCurrentScript()) + .map(Script::getConfig) + .map(Config::getFile) + .orElse(null); + } + + public static Script getCurrentScript() { + return Optional.of(ParserInstance.get()) + .filter(ParserInstance::isActive) + .map(ParserInstance::getCurrentScript) + .orElse(null); + } + + /** + * Gets the {@link ClassInfo} by first converting the given string to a singular. + * Returns {@code Object.class}'s if no {@link ClassInfo} can be found for the given type. + */ + @NonNull + public static ClassInfo getUserClassInfo(String name) { + NonNullPair wordData = Utils.getEnglishPlural(name); + + ClassInfo ci = Classes.getClassInfoNoError(wordData.getFirst()); + + if (ci == null) { + ci = Classes.getClassInfoFromUserInput(wordData.getFirst()); + } + + if (ci == null) { + Skript.warning(String.format("'%s' is not a valid Skript type. Using 'object' instead.", name)); + return DefaultClasses.OBJECT; + } + + return ci; + } + + /** + * @return the pair of the {@link ClassInfo} in the given string, and whether is is singular. + */ + public static NonNullPair, Boolean> getUserClassInfoAndPlural(String name) { + NonNullPair wordData = Utils.getEnglishPlural(name); + ClassInfo ci = getUserClassInfo(name); + + return new NonNullPair<>(ci, wordData.getSecond()); + } + + /** + * @return the singular form of the given string type, + * converted back to plural if it was plural in the first place. + * This causes the string type to always be the default codename for the {@link ClassInfo}. + */ + public static String replaceUserInputPatterns(String name) { + NonNullPair wordData = Utils.getEnglishPlural(name); + ClassInfo ci = getUserClassInfo(name); + + return Utils.toEnglishPlural(ci.getCodeName(), wordData.getSecond()); + } + + /** + * {@return} a {@link Function} to get a {@link Expression}'s value, + * using {@link Expression#getSingle(Event)} if {@link Expression#getSingle(Event)} + * returns {@code true}, otherwise returning {@link Expression#getArray(Event)}. + */ + public static Function, Object> unwrapWithEvent(Event e) { + return expr -> expr.isSingle() ? expr.getSingle(e) : expr.getArray(e); + } } diff --git a/src/main/java/com/btk5h/skriptmirror/util/StringSimilarity.java b/src/main/java/com/btk5h/skriptmirror/util/StringSimilarity.java index eef88c41..c98f854a 100644 --- a/src/main/java/com/btk5h/skriptmirror/util/StringSimilarity.java +++ b/src/main/java/com/btk5h/skriptmirror/util/StringSimilarity.java @@ -4,132 +4,132 @@ public class StringSimilarity { - public static class Result implements Comparable { - private final String left; - private final String right; - private final int editDistance; - - private Result(String left, String right, int editDistance) { - this.left = left; - this.right = right; - this.editDistance = editDistance; - } - - public String getLeft() { - return left; - } - - public String getRight() { - return right; - } - - public int getEditDistance() { - return editDistance; - } - - - @Override - public int compareTo(Result o) { - return getEditDistance() - o.getEditDistance(); - } - } - - /** - * Calculates Levenshtein distance between two strings. - *
- * Source: Apache - *
- * See LICENSE.TXT for the license. - */ - public static Result compare(String left, String right, int threshold) { - String first = left; - String second = right; - if (first == null || second == null) { - throw new IllegalArgumentException("CharSequences must not be null"); - } - if (threshold < 0) { - throw new IllegalArgumentException("Threshold must not be negative"); - } - - int n = first.length(); // length of left - int m = second.length(); // length of right - - // if one string is empty, the edit distance is necessarily the length - // of the other - if (n == 0) { - return m <= threshold ? new Result(left, right, m) : null; - } else if (m == 0) { - return n <= threshold ? new Result(left, right, n) : null; - } - - if (n > m) { - // swap the two strings to consume less memory - final String tmp = first; - first = second; - second = tmp; - n = m; - m = second.length(); - } - - // the edit distance cannot be less than the length difference - if (m - n > threshold) { - return null; - } - - int[] p = new int[n + 1]; // 'previous' cost array, horizontally - int[] d = new int[n + 1]; // cost array, horizontally - int[] tempD; // placeholder to assist in swapping p and d - - // fill in starting table values - final int boundary = Math.min(n, threshold) + 1; - for (int i = 0; i < boundary; i++) { - p[i] = i; - } - // these fills ensure that the value above the rightmost entry of our - // stripe will be ignored in following loop iterations - Arrays.fill(p, boundary, p.length, Integer.MAX_VALUE); - Arrays.fill(d, Integer.MAX_VALUE); - - // iterates through t - for (int j = 1; j <= m; j++) { - final char secondJ = second.charAt(j - 1); // jth character of second - d[0] = j; - - // compute stripe indices, constrain to array size - final int min = Math.max(1, j - threshold); - final int max = j > Integer.MAX_VALUE - threshold ? n : Math.min( - n, j + threshold); - - // ignore entry left of leftmost - if (min > 1) { - d[min - 1] = Integer.MAX_VALUE; - } - - // iterates through [min, max] in s - for (int i = min; i <= max; i++) { - if (first.charAt(i - 1) == secondJ) { - // diagonally left and up - d[i] = p[i - 1]; - } else { - // 1 + minimum of cell to the left, to the top, diagonally - // left and up - d[i] = 1 + Math.min(Math.min(d[i - 1], p[i]), p[i - 1]); - } - } - - // copy current distance counts to 'previous row' distance counts - tempD = p; - p = d; - d = tempD; - } - - // if p[n] is greater than the threshold, there's no guarantee on it - // being the correct - // distance - if (p[n] <= threshold) { - return new Result(left, right, p[n]); - } - return null; - } + public static class Result implements Comparable { + private final String left; + private final String right; + private final int editDistance; + + private Result(String left, String right, int editDistance) { + this.left = left; + this.right = right; + this.editDistance = editDistance; + } + + public String getLeft() { + return left; + } + + public String getRight() { + return right; + } + + public int getEditDistance() { + return editDistance; + } + + + @Override + public int compareTo(Result o) { + return getEditDistance() - o.getEditDistance(); + } + } + + /** + * Calculates Levenshtein distance between two strings. + *
+ * Source: Apache + *
+ * See LICENSE.TXT for the license. + */ + public static Result compare(String left, String right, int threshold) { + String first = left; + String second = right; + if (first == null || second == null) { + throw new IllegalArgumentException("CharSequences must not be null"); + } + if (threshold < 0) { + throw new IllegalArgumentException("Threshold must not be negative"); + } + + int n = first.length(); // length of left + int m = second.length(); // length of right + + // if one string is empty, the edit distance is necessarily the length + // of the other + if (n == 0) { + return m <= threshold ? new Result(left, right, m) : null; + } else if (m == 0) { + return n <= threshold ? new Result(left, right, n) : null; + } + + if (n > m) { + // swap the two strings to consume less memory + final String tmp = first; + first = second; + second = tmp; + n = m; + m = second.length(); + } + + // the edit distance cannot be less than the length difference + if (m - n > threshold) { + return null; + } + + int[] p = new int[n + 1]; // 'previous' cost array, horizontally + int[] d = new int[n + 1]; // cost array, horizontally + int[] tempD; // placeholder to assist in swapping p and d + + // fill in starting table values + final int boundary = Math.min(n, threshold) + 1; + for (int i = 0; i < boundary; i++) { + p[i] = i; + } + // these fills ensure that the value above the rightmost entry of our + // stripe will be ignored in following loop iterations + Arrays.fill(p, boundary, p.length, Integer.MAX_VALUE); + Arrays.fill(d, Integer.MAX_VALUE); + + // iterates through t + for (int j = 1; j <= m; j++) { + final char secondJ = second.charAt(j - 1); // jth character of second + d[0] = j; + + // compute stripe indices, constrain to array size + final int min = Math.max(1, j - threshold); + final int max = j > Integer.MAX_VALUE - threshold ? n : Math.min( + n, j + threshold); + + // ignore entry left of leftmost + if (min > 1) { + d[min - 1] = Integer.MAX_VALUE; + } + + // iterates through [min, max] in s + for (int i = min; i <= max; i++) { + if (first.charAt(i - 1) == secondJ) { + // diagonally left and up + d[i] = p[i - 1]; + } else { + // 1 + minimum of cell to the left, to the top, diagonally + // left and up + d[i] = 1 + Math.min(Math.min(d[i - 1], p[i]), p[i - 1]); + } + } + + // copy current distance counts to 'previous row' distance counts + tempD = p; + p = d; + d = tempD; + } + + // if p[n] is greater than the threshold, there's no guarantee on it + // being the correct + // distance + if (p[n] <= threshold) { + return new Result(left, right, p[n]); + } + return null; + } } diff --git a/src/main/java/com/btk5h/skriptmirror/util/lookup/LookupGetter.java b/src/main/java/com/btk5h/skriptmirror/util/lookup/LookupGetter.java index 8e8ef948..3d3acc78 100644 --- a/src/main/java/com/btk5h/skriptmirror/util/lookup/LookupGetter.java +++ b/src/main/java/com/btk5h/skriptmirror/util/lookup/LookupGetter.java @@ -8,8 +8,8 @@ */ public class LookupGetter { - public static MethodHandles.Lookup getLookup() { - return MethodHandles.lookup(); - } + public static MethodHandles.Lookup getLookup() { + return MethodHandles.lookup(); + } } diff --git a/src/main/java/org/skriptlang/reflect/java/elements/events/EvtByReflection.java b/src/main/java/org/skriptlang/reflect/java/elements/events/EvtByReflection.java index 1b55513f..d4a5934a 100644 --- a/src/main/java/org/skriptlang/reflect/java/elements/events/EvtByReflection.java +++ b/src/main/java/org/skriptlang/reflect/java/elements/events/EvtByReflection.java @@ -21,140 +21,140 @@ public class EvtByReflection extends SkriptEvent { - static { - Skript.registerEvent("*reflection", EvtByReflection.class, BukkitEvent.class, "[1:all] %javatypes%"); - } - - private static class MyEventExecutor implements EventExecutor { - private final Class eventClass; - private final Trigger trigger; - - public MyEventExecutor(Class eventClass, Trigger trigger) { - this.eventClass = eventClass; - this.trigger = trigger; - } - - @Override - public void execute(Listener listener, Event event) throws EventException { - if (eventClass.isInstance(event)) { - Event scriptEvent; - scriptEvent = event instanceof Cancellable - ? new CancellableBukkitEvent((Cancellable) event) : new BukkitEvent(event); - - trigger.execute(scriptEvent); - } - } - } - - private static class BukkitEvent extends WrappedEvent { - public BukkitEvent(Event event) { - super(event, event.isAsynchronous()); - } - - @Override - public HandlerList getHandlers() { - // No HandlerList implementation because this event should never be called - throw new IllegalStateException(); - } - } - - private static class CancellableBukkitEvent extends BukkitEvent implements Cancellable { - public CancellableBukkitEvent(Cancellable event) { - super((Event) event); - } - - @Override - public boolean isCancelled() { - Event event = getDirectEvent(); - return ((Cancellable) event).isCancelled(); - } - - @Override - public void setCancelled(boolean cancel) { - Event event = getDirectEvent(); - ((Cancellable) event).setCancelled(cancel); - } - } - - private Class[] classes; - private boolean ignoreCancelled; - private Listener listener; - - @SuppressWarnings("unchecked") - @Override - public boolean init(Literal[] args, int matchedPattern, SkriptParser.ParseResult parseResult) { - JavaType[] javaTypes = ((Literal) args[0]).getArray(); - - classes = new Class[javaTypes.length]; - - for (int i = 0; i < javaTypes.length; i++) { - JavaType javaType = javaTypes[i]; - Class clazz = javaType.getJavaClass(); - - if (!Event.class.isAssignableFrom(clazz)) { - Skript.error(clazz.getSimpleName() + " is not a Bukkit event"); - return false; - } - - classes[i] = (Class) clazz; - } - - ignoreCancelled = (parseResult.mark & 1) != 1; - - listener = new Listener() {}; - - return true; - } - - @Override - public boolean check(Event event) { - throw new UnsupportedOperationException(); // Should never be called - } - - @Override - public boolean postLoad() { - for (Class eventClass : classes) { - EventExecutor executor = new MyEventExecutor(eventClass, trigger); - - Bukkit.getPluginManager() - .registerEvent(eventClass, listener, getEventPriority(), executor, SkriptMirror.getInstance(), ignoreCancelled); - } - return true; - } - - public void unload() { - HandlerList.unregisterAll(listener); - } - - @SuppressWarnings("unchecked") - @Override - public Class[] getEventClasses() { - boolean hasUncancellable = false; - boolean hasCancellable = false; - - for (Class eventClass : classes) { - if (Cancellable.class.isAssignableFrom(eventClass)) { - hasCancellable = true; - } else { - hasUncancellable = true; - } - } - - if (hasCancellable && hasUncancellable) { - return new Class[] {BukkitEvent.class, CancellableBukkitEvent.class}; - } else if (hasCancellable) { - return new Class[] {CancellableBukkitEvent.class}; - } else { - return new Class[] {BukkitEvent.class}; - } - } - - @Override - public String toString(Event e, boolean debug) { - return (ignoreCancelled ? "all " : "") - + Arrays.stream(classes) - .map(Class::getSimpleName) - .collect(Collectors.joining(", ")); - } + static { + Skript.registerEvent("*reflection", EvtByReflection.class, BukkitEvent.class, "[1:all] %javatypes%"); + } + + private static class MyEventExecutor implements EventExecutor { + private final Class eventClass; + private final Trigger trigger; + + public MyEventExecutor(Class eventClass, Trigger trigger) { + this.eventClass = eventClass; + this.trigger = trigger; + } + + @Override + public void execute(Listener listener, Event event) throws EventException { + if (eventClass.isInstance(event)) { + Event scriptEvent; + scriptEvent = event instanceof Cancellable + ? new CancellableBukkitEvent((Cancellable) event) : new BukkitEvent(event); + + trigger.execute(scriptEvent); + } + } + } + + private static class BukkitEvent extends WrappedEvent { + public BukkitEvent(Event event) { + super(event, event.isAsynchronous()); + } + + @Override + public HandlerList getHandlers() { + // No HandlerList implementation because this event should never be called + throw new IllegalStateException(); + } + } + + private static class CancellableBukkitEvent extends BukkitEvent implements Cancellable { + public CancellableBukkitEvent(Cancellable event) { + super((Event) event); + } + + @Override + public boolean isCancelled() { + Event event = getDirectEvent(); + return ((Cancellable) event).isCancelled(); + } + + @Override + public void setCancelled(boolean cancel) { + Event event = getDirectEvent(); + ((Cancellable) event).setCancelled(cancel); + } + } + + private Class[] classes; + private boolean ignoreCancelled; + private Listener listener; + + @SuppressWarnings("unchecked") + @Override + public boolean init(Literal[] args, int matchedPattern, SkriptParser.ParseResult parseResult) { + JavaType[] javaTypes = ((Literal) args[0]).getArray(); + + classes = new Class[javaTypes.length]; + + for (int i = 0; i < javaTypes.length; i++) { + JavaType javaType = javaTypes[i]; + Class clazz = javaType.getJavaClass(); + + if (!Event.class.isAssignableFrom(clazz)) { + Skript.error(clazz.getSimpleName() + " is not a Bukkit event"); + return false; + } + + classes[i] = (Class) clazz; + } + + ignoreCancelled = (parseResult.mark & 1) != 1; + + listener = new Listener() {}; + + return true; + } + + @Override + public boolean check(Event event) { + throw new UnsupportedOperationException(); // Should never be called + } + + @Override + public boolean postLoad() { + for (Class eventClass : classes) { + EventExecutor executor = new MyEventExecutor(eventClass, trigger); + + Bukkit.getPluginManager() + .registerEvent(eventClass, listener, getEventPriority(), executor, SkriptMirror.getInstance(), ignoreCancelled); + } + return true; + } + + public void unload() { + HandlerList.unregisterAll(listener); + } + + @SuppressWarnings("unchecked") + @Override + public Class[] getEventClasses() { + boolean hasUncancellable = false; + boolean hasCancellable = false; + + for (Class eventClass : classes) { + if (Cancellable.class.isAssignableFrom(eventClass)) { + hasCancellable = true; + } else { + hasUncancellable = true; + } + } + + if (hasCancellable && hasUncancellable) { + return new Class[] {BukkitEvent.class, CancellableBukkitEvent.class}; + } else if (hasCancellable) { + return new Class[] {CancellableBukkitEvent.class}; + } else { + return new Class[] {BukkitEvent.class}; + } + } + + @Override + public String toString(Event e, boolean debug) { + return (ignoreCancelled ? "all " : "") + + Arrays.stream(classes) + .map(Class::getSimpleName) + .collect(Collectors.joining(", ")); + } } diff --git a/src/main/java/org/skriptlang/reflect/java/elements/structures/StructImport.java b/src/main/java/org/skriptlang/reflect/java/elements/structures/StructImport.java index 50cd8c44..43726882 100644 --- a/src/main/java/org/skriptlang/reflect/java/elements/structures/StructImport.java +++ b/src/main/java/org/skriptlang/reflect/java/elements/structures/StructImport.java @@ -33,176 +33,176 @@ public class StructImport extends Structure { - public static final Priority PRIORITY = new Priority(150); - private static final Pattern IMPORT_STATEMENT = - Pattern.compile("(" + SkriptMirrorUtil.PACKAGE + ")(?:\\s+as (" + SkriptMirrorUtil.IDENTIFIER + "))?"); - private static final SyntaxElementInfo thisInfo; - private static final Map> imports = new HashMap<>(); - - static { - Skript.registerStructure(StructImport.class, "import"); - Skript.registerEffect(EffImport.class, "import <" + IMPORT_STATEMENT.pattern() + ">"); - - // TODO try replacing ImportHandler with JavaType's literal parsing - Skript.registerExpression(ImportHandler.class, JavaType.class, ExpressionType.SIMPLE); - thisInfo = StreamSupport.stream(Spliterators.spliteratorUnknownSize(Skript.getExpressions(), Spliterator.ORDERED), false) - .filter(expressionInfo -> ImportHandler.class.equals(expressionInfo.getElementClass())) - .findFirst().orElseThrow(RuntimeException::new); // Should never be null - } - - private Script script; - - @Override - public boolean init(Literal[] args, int matchedPattern, ParseResult parseResult, EntryContainer entryContainer) { - this.script = getParser().getCurrentScript(); - getEntryContainer().getSource().forEach(node -> registerImport(Optional.ofNullable(node.getKey()) - .map(ScriptLoader::replaceOptions) - .orElse(null), script)); - updateImports(); - return true; - } - - @Override - public boolean load() { - return true; - } - - @Override - public void unload() { - imports.remove(script); - updateImports(); - } - - @Override - public Priority getPriority() { - return PRIORITY; - } - - @Override - public String toString(@Nullable Event e, boolean debug) { - return "import"; - } - - private static boolean registerImport(String rawStatement, @Nullable Script script) { - Matcher statement = IMPORT_STATEMENT.matcher(ScriptLoader.replaceOptions(rawStatement)); - if (!statement.matches()) { - Skript.error(rawStatement + " is an invalid import statement."); - return false; - } - - String cls = statement.group(1); - Class javaClass; - - try { - javaClass = LibraryLoader.getClassLoader().loadClass(cls); - } catch (ClassNotFoundException ex) { - Skript.error(cls + " refers to a non-existent class."); - return false; - } - - String importName = statement.group(2); - - if (javaClass.getSimpleName().equals(importName)) { - Skript.warning(cls + " doesn't need the alias " + importName + ", as it will already be imported under that name"); - } - - if (importName == null) { - importName = javaClass.getSimpleName(); - } - - imports.computeIfAbsent(script, s -> new HashMap<>()) - .compute(importName, - (name, oldClass) -> { - if (oldClass != null) { - Skript.error(name + " is already mapped to " + oldClass.getJavaClass() + ". " + - "It will not be remapped to " + javaClass + "."); - return oldClass; - } - return new JavaType(javaClass); - }); - - return true; - } - - private static void updateImports() { - String[] patterns = imports.values().stream() - .flatMap(m -> m.keySet().stream()) - .distinct() - .toArray(String[]::new); - SkriptReflection.setPatterns(thisInfo, patterns); - } - - public static class ImportHandler extends SimpleExpression { - - private JavaType type; - - @Override - protected JavaType[] get(Event e) { - return new JavaType[]{type}; - } - - @Override - public boolean isSingle() { - return true; - } - - @Override - public Class getReturnType() { - return JavaType.class; - } - - @Override - public String toString(Event e, boolean debug) { - return type.getJavaClass().getName(); - } - - @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { - type = lookup(SkriptUtil.getCurrentScript(), parseResult.expr); - return type != null; - } - - public JavaType getJavaType() { - return type; - } - - } - - public static JavaType lookup(Script script, String identifier) { - Map localImports = imports.get(script); - - if (localImports == null) - return null; - - return localImports.get(identifier); - } - - public static class EffImport extends Effect { - - private String className; - - @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { - if (!getParser().isCurrentEvent(EffectCommandEvent.class)) { - Skript.error("The import effect can only be used in effect commands. " + - "To use imports in scripts, use the section."); - return false; - } - - className = parseResult.regexes.get(0).group(); - - return registerImport(className, null); - } - - @Override - protected void execute(Event e) { - updateImports(); - } - - @Override - public String toString(@Nullable Event e, boolean debug) { - return "import " + className; - } - } + public static final Priority PRIORITY = new Priority(150); + private static final Pattern IMPORT_STATEMENT = + Pattern.compile("(" + SkriptMirrorUtil.PACKAGE + ")(?:\\s+as (" + SkriptMirrorUtil.IDENTIFIER + "))?"); + private static final SyntaxElementInfo thisInfo; + private static final Map> imports = new HashMap<>(); + + static { + Skript.registerStructure(StructImport.class, "import"); + Skript.registerEffect(EffImport.class, "import <" + IMPORT_STATEMENT.pattern() + ">"); + + // TODO try replacing ImportHandler with JavaType's literal parsing + Skript.registerExpression(ImportHandler.class, JavaType.class, ExpressionType.SIMPLE); + thisInfo = StreamSupport.stream(Spliterators.spliteratorUnknownSize(Skript.getExpressions(), Spliterator.ORDERED), false) + .filter(expressionInfo -> ImportHandler.class.equals(expressionInfo.getElementClass())) + .findFirst().orElseThrow(RuntimeException::new); // Should never be null + } + + private Script script; + + @Override + public boolean init(Literal[] args, int matchedPattern, ParseResult parseResult, EntryContainer entryContainer) { + this.script = getParser().getCurrentScript(); + getEntryContainer().getSource().forEach(node -> registerImport(Optional.ofNullable(node.getKey()) + .map(ScriptLoader::replaceOptions) + .orElse(null), script)); + updateImports(); + return true; + } + + @Override + public boolean load() { + return true; + } + + @Override + public void unload() { + imports.remove(script); + updateImports(); + } + + @Override + public Priority getPriority() { + return PRIORITY; + } + + @Override + public String toString(@Nullable Event e, boolean debug) { + return "import"; + } + + private static boolean registerImport(String rawStatement, @Nullable Script script) { + Matcher statement = IMPORT_STATEMENT.matcher(ScriptLoader.replaceOptions(rawStatement)); + if (!statement.matches()) { + Skript.error(rawStatement + " is an invalid import statement."); + return false; + } + + String cls = statement.group(1); + Class javaClass; + + try { + javaClass = LibraryLoader.getClassLoader().loadClass(cls); + } catch (ClassNotFoundException ex) { + Skript.error(cls + " refers to a non-existent class."); + return false; + } + + String importName = statement.group(2); + + if (javaClass.getSimpleName().equals(importName)) { + Skript.warning(cls + " doesn't need the alias " + importName + ", as it will already be imported under that name"); + } + + if (importName == null) { + importName = javaClass.getSimpleName(); + } + + imports.computeIfAbsent(script, s -> new HashMap<>()) + .compute(importName, + (name, oldClass) -> { + if (oldClass != null) { + Skript.error(name + " is already mapped to " + oldClass.getJavaClass() + ". " + + "It will not be remapped to " + javaClass + "."); + return oldClass; + } + return new JavaType(javaClass); + }); + + return true; + } + + private static void updateImports() { + String[] patterns = imports.values().stream() + .flatMap(m -> m.keySet().stream()) + .distinct() + .toArray(String[]::new); + SkriptReflection.setPatterns(thisInfo, patterns); + } + + public static class ImportHandler extends SimpleExpression { + + private JavaType type; + + @Override + protected JavaType[] get(Event e) { + return new JavaType[]{type}; + } + + @Override + public boolean isSingle() { + return true; + } + + @Override + public Class getReturnType() { + return JavaType.class; + } + + @Override + public String toString(Event e, boolean debug) { + return type.getJavaClass().getName(); + } + + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + type = lookup(SkriptUtil.getCurrentScript(), parseResult.expr); + return type != null; + } + + public JavaType getJavaType() { + return type; + } + + } + + public static JavaType lookup(Script script, String identifier) { + Map localImports = imports.get(script); + + if (localImports == null) + return null; + + return localImports.get(identifier); + } + + public static class EffImport extends Effect { + + private String className; + + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + if (!getParser().isCurrentEvent(EffectCommandEvent.class)) { + Skript.error("The import effect can only be used in effect commands. " + + "To use imports in scripts, use the section."); + return false; + } + + className = parseResult.regexes.get(0).group(); + + return registerImport(className, null); + } + + @Override + protected void execute(Event e) { + updateImports(); + } + + @Override + public String toString(@Nullable Event e, boolean debug) { + return "import " + className; + } + } } diff --git a/src/main/java/org/skriptlang/reflect/syntax/CustomSyntaxStructure.java b/src/main/java/org/skriptlang/reflect/syntax/CustomSyntaxStructure.java index c2ae3def..3e8b348a 100644 --- a/src/main/java/org/skriptlang/reflect/syntax/CustomSyntaxStructure.java +++ b/src/main/java/org/skriptlang/reflect/syntax/CustomSyntaxStructure.java @@ -30,244 +30,244 @@ public abstract class CustomSyntaxStructure extends Structure { - public static final Priority PRIORITY = new Priority(350); - - public static class CustomSyntaxEvent extends Event { - private CustomSyntaxEvent() {} - - @Override - public HandlerList getHandlers() { - throw new IllegalStateException(); - } - } - - public static class DataTracker { - public DataTracker() { - } - - private List patterns = new ArrayList<>(); - private final Map> primaryData = new HashMap<>(); - private final List> managedData = new ArrayList<>(); - private SyntaxElementInfo info; - - public List getPatterns() { - return patterns; - } - - public Map> getPrimaryData() { - return primaryData; - } - - public List> getManagedData() { - return managedData; - } - - public SyntaxElementInfo getInfo() { - return info; - } - - public void recomputePatterns() { - patterns = primaryData.values().stream() - .map(Map::keySet) - .flatMap(Set::stream) - .distinct() - .collect(Collectors.toList()); - } - - public void addManaged(Map data) { - managedData.add(data); - } - - public void setInfo(SyntaxElementInfo info) { - this.info = info; - } - - public final T lookup(Script script, int matchedPattern) { - String originalSyntax = patterns.get(matchedPattern); - Map localSyntax = primaryData.get(script); - - if (localSyntax != null) { - T privateResult = localSyntax.get(originalSyntax); - if (privateResult != null) { - return privateResult; - } - } - - Map globalSyntax = primaryData.get(null); - - if (globalSyntax == null || !globalSyntax.containsKey(originalSyntax)) { - return null; - } - - return globalSyntax.get(originalSyntax); - } - } - - public abstract static class SyntaxData { - private final Script script; - private final String pattern; - private final int matchedPattern; - - protected SyntaxData(Script script, String pattern, int matchedPattern) { - this.script = script; - this.pattern = pattern; - this.matchedPattern = matchedPattern; - } - - public Script getScript() { - return script; - } - - public String getPattern() { - return pattern; - } - - public int getMatchedPattern() { - return matchedPattern; - } - - @Override - public String toString() { - return pattern; - } - } - - protected List whichInfo = new ArrayList<>(); - private boolean hasPatterns = false; - - protected abstract DataTracker getDataTracker(); - - @Override - public boolean preLoad() { - update(); - return true; - } - - @Override - public boolean load() { - return true; - } - - @Override - public void unload() { - whichInfo.forEach(which -> { - Map> primaryData = getDataTracker().getPrimaryData(); - Script script = which.getScript(); - - Map syntaxes = primaryData.get(script); - syntaxes.remove(which.getPattern()); - if (syntaxes.isEmpty()) { - primaryData.remove(script); - } - - getDataTracker().getManagedData().forEach(data -> data.remove(which)); - }); - - update(); - } - - @Override - public Priority getPriority() { - return PRIORITY; - } - - @Override - public String toString(Event e, boolean debug) { - return null; - } - - private void update() { - getDataTracker().recomputePatterns(); - SkriptReflection.setPatterns(getDataTracker().getInfo(), getDataTracker().getPatterns().toArray(new String[0])); - } - - protected final void register(T data) { - hasPatterns = true; - String pattern = data.getPattern(); - - whichInfo.add(data); - - getDataTracker().getPrimaryData() - .computeIfAbsent(data.getScript(), f -> new HashMap<>()) - .put(pattern, data); - } - - protected boolean checkHasPatterns() { - if (hasPatterns) - return true; - Skript.error("A custom syntax must have at least one pattern"); - return false; - } - - protected SectionNode[] getParseNode() { - SectionNode parseNode = getEntryContainer().getOptional("parse", SectionNode.class, false); - SectionNode safeParseNode = getEntryContainer().getOptional("safe parse", SectionNode.class, false); - if (safeParseNode != null) { - if (parseNode != null) { - Skript.error("A custom syntax element cannot contain both 'parse' and 'safe parse' entries"); - return null; - } - Skript.warning("The 'safe parse' entry is deprecated and will act as a regular 'parse' entry." - + " Please use the 'parse' entry instead"); - return new SectionNode[] {safeParseNode}; - } - return new SectionNode[] {parseNode}; - } - - @SuppressWarnings("unchecked") - protected boolean handleUsableEntry(SectionNode sectionNode, Map>> usableSuppliers) { - Script currentScript = SkriptUtil.getCurrentScript(); - for (Node usableNode : sectionNode) { - String usableKey = usableNode.getKey(); - assert usableKey != null; - - Supplier supplier; - if (usableKey.startsWith("custom event ")) { - String customEventString = usableKey.substring("custom event ".length()); - VariableString variableString = VariableString.newInstance( - customEventString.substring(1, customEventString.length() - 1)); - if (variableString == null || !variableString.isSimple()) { - Skript.error("Custom event identifiers may only be simple strings"); - return false; - } else { - String identifier = variableString.toString(null); - supplier = () -> { - if (!getParser().isCurrentEvent(BukkitCustomEvent.class)) - return false; - - EventSyntaxInfo eventWhich = CustomEvent.lastWhich; - return CustomEventUtils.getName(eventWhich).equalsIgnoreCase(identifier); - }; - } - } else { - JavaType javaType = StructImport.lookup(currentScript, usableKey); - Class javaClass = javaType == null ? null : javaType.getJavaClass(); - if (javaClass == null || !Event.class.isAssignableFrom(javaClass)) { - Skript.error(javaType + " is not a Bukkit event"); - return false; - } - Class eventClass = (Class) javaClass; - - supplier = () -> getParser().isCurrentEvent(eventClass); - } - whichInfo.forEach(which -> - usableSuppliers.computeIfAbsent(which, (whichIndex) -> new ArrayList<>()) - .add(supplier) - ); - } - return true; - } - - public T getFirstWhich() { - return whichInfo.get(0); - } - - public static EntryValidator.EntryValidatorBuilder customSyntaxValidator() { - return EntryValidator.builder() - .addEntryData(new PatternsEntryData("patterns", null, true)) - .addSection("parse", true) - .addSection("safe parse", true) // Deprecated - .addSection("usable in", true); - } + public static final Priority PRIORITY = new Priority(350); + + public static class CustomSyntaxEvent extends Event { + private CustomSyntaxEvent() {} + + @Override + public HandlerList getHandlers() { + throw new IllegalStateException(); + } + } + + public static class DataTracker { + public DataTracker() { + } + + private List patterns = new ArrayList<>(); + private final Map> primaryData = new HashMap<>(); + private final List> managedData = new ArrayList<>(); + private SyntaxElementInfo info; + + public List getPatterns() { + return patterns; + } + + public Map> getPrimaryData() { + return primaryData; + } + + public List> getManagedData() { + return managedData; + } + + public SyntaxElementInfo getInfo() { + return info; + } + + public void recomputePatterns() { + patterns = primaryData.values().stream() + .map(Map::keySet) + .flatMap(Set::stream) + .distinct() + .collect(Collectors.toList()); + } + + public void addManaged(Map data) { + managedData.add(data); + } + + public void setInfo(SyntaxElementInfo info) { + this.info = info; + } + + public final T lookup(Script script, int matchedPattern) { + String originalSyntax = patterns.get(matchedPattern); + Map localSyntax = primaryData.get(script); + + if (localSyntax != null) { + T privateResult = localSyntax.get(originalSyntax); + if (privateResult != null) { + return privateResult; + } + } + + Map globalSyntax = primaryData.get(null); + + if (globalSyntax == null || !globalSyntax.containsKey(originalSyntax)) { + return null; + } + + return globalSyntax.get(originalSyntax); + } + } + + public abstract static class SyntaxData { + private final Script script; + private final String pattern; + private final int matchedPattern; + + protected SyntaxData(Script script, String pattern, int matchedPattern) { + this.script = script; + this.pattern = pattern; + this.matchedPattern = matchedPattern; + } + + public Script getScript() { + return script; + } + + public String getPattern() { + return pattern; + } + + public int getMatchedPattern() { + return matchedPattern; + } + + @Override + public String toString() { + return pattern; + } + } + + protected List whichInfo = new ArrayList<>(); + private boolean hasPatterns = false; + + protected abstract DataTracker getDataTracker(); + + @Override + public boolean preLoad() { + update(); + return true; + } + + @Override + public boolean load() { + return true; + } + + @Override + public void unload() { + whichInfo.forEach(which -> { + Map> primaryData = getDataTracker().getPrimaryData(); + Script script = which.getScript(); + + Map syntaxes = primaryData.get(script); + syntaxes.remove(which.getPattern()); + if (syntaxes.isEmpty()) { + primaryData.remove(script); + } + + getDataTracker().getManagedData().forEach(data -> data.remove(which)); + }); + + update(); + } + + @Override + public Priority getPriority() { + return PRIORITY; + } + + @Override + public String toString(Event e, boolean debug) { + return null; + } + + private void update() { + getDataTracker().recomputePatterns(); + SkriptReflection.setPatterns(getDataTracker().getInfo(), getDataTracker().getPatterns().toArray(new String[0])); + } + + protected final void register(T data) { + hasPatterns = true; + String pattern = data.getPattern(); + + whichInfo.add(data); + + getDataTracker().getPrimaryData() + .computeIfAbsent(data.getScript(), f -> new HashMap<>()) + .put(pattern, data); + } + + protected boolean checkHasPatterns() { + if (hasPatterns) + return true; + Skript.error("A custom syntax must have at least one pattern"); + return false; + } + + protected SectionNode[] getParseNode() { + SectionNode parseNode = getEntryContainer().getOptional("parse", SectionNode.class, false); + SectionNode safeParseNode = getEntryContainer().getOptional("safe parse", SectionNode.class, false); + if (safeParseNode != null) { + if (parseNode != null) { + Skript.error("A custom syntax element cannot contain both 'parse' and 'safe parse' entries"); + return null; + } + Skript.warning("The 'safe parse' entry is deprecated and will act as a regular 'parse' entry." + + " Please use the 'parse' entry instead"); + return new SectionNode[] {safeParseNode}; + } + return new SectionNode[] {parseNode}; + } + + @SuppressWarnings("unchecked") + protected boolean handleUsableEntry(SectionNode sectionNode, Map>> usableSuppliers) { + Script currentScript = SkriptUtil.getCurrentScript(); + for (Node usableNode : sectionNode) { + String usableKey = usableNode.getKey(); + assert usableKey != null; + + Supplier supplier; + if (usableKey.startsWith("custom event ")) { + String customEventString = usableKey.substring("custom event ".length()); + VariableString variableString = VariableString.newInstance( + customEventString.substring(1, customEventString.length() - 1)); + if (variableString == null || !variableString.isSimple()) { + Skript.error("Custom event identifiers may only be simple strings"); + return false; + } else { + String identifier = variableString.toString(null); + supplier = () -> { + if (!getParser().isCurrentEvent(BukkitCustomEvent.class)) + return false; + + EventSyntaxInfo eventWhich = CustomEvent.lastWhich; + return CustomEventUtils.getName(eventWhich).equalsIgnoreCase(identifier); + }; + } + } else { + JavaType javaType = StructImport.lookup(currentScript, usableKey); + Class javaClass = javaType == null ? null : javaType.getJavaClass(); + if (javaClass == null || !Event.class.isAssignableFrom(javaClass)) { + Skript.error(javaType + " is not a Bukkit event"); + return false; + } + Class eventClass = (Class) javaClass; + + supplier = () -> getParser().isCurrentEvent(eventClass); + } + whichInfo.forEach(which -> + usableSuppliers.computeIfAbsent(which, (whichIndex) -> new ArrayList<>()) + .add(supplier) + ); + } + return true; + } + + public T getFirstWhich() { + return whichInfo.get(0); + } + + public static EntryValidator.EntryValidatorBuilder customSyntaxValidator() { + return EntryValidator.builder() + .addEntryData(new PatternsEntryData("patterns", null, true)) + .addSection("parse", true) + .addSection("safe parse", true) // Deprecated + .addSection("usable in", true); + } } diff --git a/src/main/java/org/skriptlang/reflect/syntax/PatternsEntryData.java b/src/main/java/org/skriptlang/reflect/syntax/PatternsEntryData.java index 7b391211..861deecf 100644 --- a/src/main/java/org/skriptlang/reflect/syntax/PatternsEntryData.java +++ b/src/main/java/org/skriptlang/reflect/syntax/PatternsEntryData.java @@ -11,31 +11,31 @@ class PatternsEntryData extends EntryData> { - public PatternsEntryData(String key, @Nullable List defaultValue, boolean optional) { - super(key, defaultValue, optional); - } + public PatternsEntryData(String key, @Nullable List defaultValue, boolean optional) { + super(key, defaultValue, optional); + } - @Override - public List getValue(Node node) { - List patterns = new ArrayList<>(); - for (Node subNode : (SectionNode) node) { - String key = subNode.getKey(); - if (key == null) - continue; - patterns.add(key); - } - return patterns; - } + @Override + public List getValue(Node node) { + List patterns = new ArrayList<>(); + for (Node subNode : (SectionNode) node) { + String key = subNode.getKey(); + if (key == null) + continue; + patterns.add(key); + } + return patterns; + } - @Override - public boolean canCreateWith(Node node) { - if (!(node instanceof SectionNode)) - return false; - String key = node.getKey(); - if (key == null) - return false; - key = ScriptLoader.replaceOptions(key); - return getKey().equalsIgnoreCase(key); - } + @Override + public boolean canCreateWith(Node node) { + if (!(node instanceof SectionNode)) + return false; + String key = node.getKey(); + if (key == null) + return false; + key = ScriptLoader.replaceOptions(key); + return getKey().equalsIgnoreCase(key); + } } diff --git a/src/main/java/org/skriptlang/reflect/syntax/condition/ConditionCheckEvent.java b/src/main/java/org/skriptlang/reflect/syntax/condition/ConditionCheckEvent.java index a336cf89..03aac3da 100644 --- a/src/main/java/org/skriptlang/reflect/syntax/condition/ConditionCheckEvent.java +++ b/src/main/java/org/skriptlang/reflect/syntax/condition/ConditionCheckEvent.java @@ -9,38 +9,38 @@ public class ConditionCheckEvent extends CustomSyntaxEvent implements Continuable { - private final static HandlerList handlers = new HandlerList(); - private boolean markedContinue; - private boolean markedNegated = false; - - public ConditionCheckEvent(Event event, Expression[] expressions, int matchedPattern, - SkriptParser.ParseResult parseResult) { - super(event, expressions, matchedPattern, parseResult); - } - - public static HandlerList getHandlerList() { - return handlers; - } - - public boolean isMarkedContinue() { - return markedContinue; - } - - public boolean isMarkedNegated() { - return markedNegated; - } - - @Override - public void setContinue(boolean b) { - markedContinue = b; - } - - public void markNegated() { - markedNegated = true; - } - - @Override - public HandlerList getHandlers() { - return handlers; - } + private final static HandlerList handlers = new HandlerList(); + private boolean markedContinue; + private boolean markedNegated = false; + + public ConditionCheckEvent(Event event, Expression[] expressions, int matchedPattern, + SkriptParser.ParseResult parseResult) { + super(event, expressions, matchedPattern, parseResult); + } + + public static HandlerList getHandlerList() { + return handlers; + } + + public boolean isMarkedContinue() { + return markedContinue; + } + + public boolean isMarkedNegated() { + return markedNegated; + } + + @Override + public void setContinue(boolean b) { + markedContinue = b; + } + + public void markNegated() { + markedNegated = true; + } + + @Override + public HandlerList getHandlers() { + return handlers; + } } diff --git a/src/main/java/org/skriptlang/reflect/syntax/condition/ConditionSyntaxInfo.java b/src/main/java/org/skriptlang/reflect/syntax/condition/ConditionSyntaxInfo.java index e5824e82..694583e8 100644 --- a/src/main/java/org/skriptlang/reflect/syntax/condition/ConditionSyntaxInfo.java +++ b/src/main/java/org/skriptlang/reflect/syntax/condition/ConditionSyntaxInfo.java @@ -8,48 +8,48 @@ public class ConditionSyntaxInfo extends CustomSyntaxStructure.SyntaxData { - private final boolean inverted; - private final boolean property; - - private ConditionSyntaxInfo(Script script, String pattern, int matchedPattern, boolean inverted, boolean property) { - super(script, pattern, matchedPattern); - this.inverted = inverted; - this.property = property; - } - - public static ConditionSyntaxInfo create(Script script, String pattern, int matchedPattern, - boolean inverted, boolean property) { - return new ConditionSyntaxInfo(script, SkriptMirrorUtil.preprocessPattern(pattern), matchedPattern, - inverted, property); - } - - public boolean isInverted() { - return inverted; - } - - public boolean isProperty() { - return property; - } - - @Override - public String toString() { - return String.format("%s (inverted: %s, property: %s)", getPattern(), inverted, property); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - ConditionSyntaxInfo that = (ConditionSyntaxInfo) o; - return inverted == that.inverted && - property == that.property && - Objects.equals(getScript(), that.getScript()) && - Objects.equals(getPattern(), that.getPattern()); - } - - @Override - public int hashCode() { - return Objects.hash(inverted, property, getScript(), getPattern()); - } + private final boolean inverted; + private final boolean property; + + private ConditionSyntaxInfo(Script script, String pattern, int matchedPattern, boolean inverted, boolean property) { + super(script, pattern, matchedPattern); + this.inverted = inverted; + this.property = property; + } + + public static ConditionSyntaxInfo create(Script script, String pattern, int matchedPattern, + boolean inverted, boolean property) { + return new ConditionSyntaxInfo(script, SkriptMirrorUtil.preprocessPattern(pattern), matchedPattern, + inverted, property); + } + + public boolean isInverted() { + return inverted; + } + + public boolean isProperty() { + return property; + } + + @Override + public String toString() { + return String.format("%s (inverted: %s, property: %s)", getPattern(), inverted, property); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ConditionSyntaxInfo that = (ConditionSyntaxInfo) o; + return inverted == that.inverted && + property == that.property && + Objects.equals(getScript(), that.getScript()) && + Objects.equals(getPattern(), that.getPattern()); + } + + @Override + public int hashCode() { + return Objects.hash(inverted, property, getScript(), getPattern()); + } } diff --git a/src/main/java/org/skriptlang/reflect/syntax/condition/elements/CustomCondition.java b/src/main/java/org/skriptlang/reflect/syntax/condition/elements/CustomCondition.java index 104fe164..2456349b 100644 --- a/src/main/java/org/skriptlang/reflect/syntax/condition/elements/CustomCondition.java +++ b/src/main/java/org/skriptlang/reflect/syntax/condition/elements/CustomCondition.java @@ -23,95 +23,95 @@ public class CustomCondition extends Condition { - private ConditionSyntaxInfo which; - private Expression[] exprs; - private SkriptParser.ParseResult parseResult; - private Object variablesMap; - - @Override - public boolean check(Event e) { - Trigger checker = StructCustomCondition.conditionHandlers.get(which); - - if (checker == null) { - Skript.error( - String.format("The custom condition '%s' no longer has a check handler.", which.getPattern()) - ); - return false; - } - - if (which.isProperty()) { - return checkByProperty(e, checker); - } - - return checkByStandard(e, checker); - } - - private boolean checkByStandard(Event e, Trigger checker) { - ConditionCheckEvent conditionEvent = new ConditionCheckEvent(e, exprs, which.getMatchedPattern(), parseResult); - SkriptReflection.putLocals(variablesMap, conditionEvent); - checker.execute(conditionEvent); - return conditionEvent.isMarkedContinue() ^ conditionEvent.isMarkedNegated() ^ which.isInverted(); - } - - private boolean checkByProperty(Event e, Trigger checker) { - return exprs[0].check(e, o -> { - Expression[] localExprs = Arrays.copyOf(exprs, exprs.length); - localExprs[0] = new SimpleLiteral<>(o, false); - - ConditionCheckEvent conditionEvent = - new ConditionCheckEvent(e, localExprs, which.getMatchedPattern(), parseResult); - SkriptReflection.putLocals(SkriptReflection.copyLocals(variablesMap), conditionEvent); - checker.execute(conditionEvent); - return conditionEvent.isMarkedContinue() ^ conditionEvent.isMarkedNegated(); - }, which.isInverted()); - } - - @Override - public String toString(Event e, boolean debug) { - return which.getPattern(); - } - - @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, - SkriptParser.ParseResult parseResult) { - which = StructCustomCondition.lookup(SkriptUtil.getCurrentScript(), matchedPattern); - - if (which == null) { - return false; - } - - this.exprs = Arrays.stream(exprs) - .map(SkriptUtil::defendExpression) - .toArray(Expression[]::new); - this.parseResult = parseResult; - - if (!SkriptUtil.canInitSafely(this.exprs)) { - return false; - } - - List> suppliers = StructCustomCondition.usableSuppliers.get(which); - if (suppliers != null && suppliers.size() != 0 && suppliers.stream().noneMatch(Supplier::get)) - return false; - - Boolean bool = StructCustomCondition.parseSectionLoaded.get(which); - if (bool != null && !bool) { - Skript.error("You can't use custom conditions with parse sections before they're loaded."); - return false; - } - - Trigger parseHandler = StructCustomCondition.parserHandlers.get(which); - - if (parseHandler != null) { - SyntaxParseEvent event = - new SyntaxParseEvent(this.exprs, matchedPattern, parseResult, getParser().getCurrentEvents()); - - TriggerItem.walk(parseHandler, event); - variablesMap = SkriptReflection.removeLocals(event); - - return event.isMarkedContinue(); - } - - return true; - } + private ConditionSyntaxInfo which; + private Expression[] exprs; + private SkriptParser.ParseResult parseResult; + private Object variablesMap; + + @Override + public boolean check(Event e) { + Trigger checker = StructCustomCondition.conditionHandlers.get(which); + + if (checker == null) { + Skript.error( + String.format("The custom condition '%s' no longer has a check handler.", which.getPattern()) + ); + return false; + } + + if (which.isProperty()) { + return checkByProperty(e, checker); + } + + return checkByStandard(e, checker); + } + + private boolean checkByStandard(Event e, Trigger checker) { + ConditionCheckEvent conditionEvent = new ConditionCheckEvent(e, exprs, which.getMatchedPattern(), parseResult); + SkriptReflection.putLocals(variablesMap, conditionEvent); + checker.execute(conditionEvent); + return conditionEvent.isMarkedContinue() ^ conditionEvent.isMarkedNegated() ^ which.isInverted(); + } + + private boolean checkByProperty(Event e, Trigger checker) { + return exprs[0].check(e, o -> { + Expression[] localExprs = Arrays.copyOf(exprs, exprs.length); + localExprs[0] = new SimpleLiteral<>(o, false); + + ConditionCheckEvent conditionEvent = + new ConditionCheckEvent(e, localExprs, which.getMatchedPattern(), parseResult); + SkriptReflection.putLocals(SkriptReflection.copyLocals(variablesMap), conditionEvent); + checker.execute(conditionEvent); + return conditionEvent.isMarkedContinue() ^ conditionEvent.isMarkedNegated(); + }, which.isInverted()); + } + + @Override + public String toString(Event e, boolean debug) { + return which.getPattern(); + } + + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, + SkriptParser.ParseResult parseResult) { + which = StructCustomCondition.lookup(SkriptUtil.getCurrentScript(), matchedPattern); + + if (which == null) { + return false; + } + + this.exprs = Arrays.stream(exprs) + .map(SkriptUtil::defendExpression) + .toArray(Expression[]::new); + this.parseResult = parseResult; + + if (!SkriptUtil.canInitSafely(this.exprs)) { + return false; + } + + List> suppliers = StructCustomCondition.usableSuppliers.get(which); + if (suppliers != null && suppliers.size() != 0 && suppliers.stream().noneMatch(Supplier::get)) + return false; + + Boolean bool = StructCustomCondition.parseSectionLoaded.get(which); + if (bool != null && !bool) { + Skript.error("You can't use custom conditions with parse sections before they're loaded."); + return false; + } + + Trigger parseHandler = StructCustomCondition.parserHandlers.get(which); + + if (parseHandler != null) { + SyntaxParseEvent event = + new SyntaxParseEvent(this.exprs, matchedPattern, parseResult, getParser().getCurrentEvents()); + + TriggerItem.walk(parseHandler, event); + variablesMap = SkriptReflection.removeLocals(event); + + return event.isMarkedContinue(); + } + + return true; + } } diff --git a/src/main/java/org/skriptlang/reflect/syntax/condition/elements/EffNegateCondition.java b/src/main/java/org/skriptlang/reflect/syntax/condition/elements/EffNegateCondition.java index 8bd53399..b4fb6203 100644 --- a/src/main/java/org/skriptlang/reflect/syntax/condition/elements/EffNegateCondition.java +++ b/src/main/java/org/skriptlang/reflect/syntax/condition/elements/EffNegateCondition.java @@ -10,28 +10,28 @@ import org.skriptlang.reflect.syntax.condition.ConditionCheckEvent; public class EffNegateCondition extends Effect { - static { - Skript.registerEffect(EffNegateCondition.class, "negate [the] [current] condition"); - } + static { + Skript.registerEffect(EffNegateCondition.class, "negate [the] [current] condition"); + } - @Override - protected void execute(Event e) { - ((ConditionCheckEvent) e).markNegated(); - } + @Override + protected void execute(Event e) { + ((ConditionCheckEvent) e).markNegated(); + } - @Override - public String toString(Event e, boolean debug) { - return "negate condition"; - } + @Override + public String toString(Event e, boolean debug) { + return "negate condition"; + } - @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, - SkriptParser.ParseResult parseResult) { - if (!getParser().isCurrentEvent(ConditionCheckEvent.class)) { - Skript.error("The effect 'negate condition' may only be used in a custom condition.", - ErrorQuality.SEMANTIC_ERROR); - return false; - } - return true; - } + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, + SkriptParser.ParseResult parseResult) { + if (!getParser().isCurrentEvent(ConditionCheckEvent.class)) { + Skript.error("The effect 'negate condition' may only be used in a custom condition.", + ErrorQuality.SEMANTIC_ERROR); + return false; + } + return true; + } } diff --git a/src/main/java/org/skriptlang/reflect/syntax/condition/elements/StructCustomCondition.java b/src/main/java/org/skriptlang/reflect/syntax/condition/elements/StructCustomCondition.java index 9caaf677..a2cf507d 100644 --- a/src/main/java/org/skriptlang/reflect/syntax/condition/elements/StructCustomCondition.java +++ b/src/main/java/org/skriptlang/reflect/syntax/condition/elements/StructCustomCondition.java @@ -30,138 +30,138 @@ public class StructCustomCondition extends CustomSyntaxStructure { - public static boolean customConditionsUsed = false; - - static { - String[] syntax = { - "[:local] condition <.+>", - "[:local] condition", - "[:local] %*classinfos% property condition <.+>" - }; - Skript.registerStructure(StructCustomCondition.class, customSyntaxValidator() - .addSection("check", false) - .build(), - syntax - ); - } - - private static final DataTracker dataTracker = new DataTracker<>(); - - static final Map conditionHandlers = new HashMap<>(); - static final Map parserHandlers = new HashMap<>(); - static final Map>> usableSuppliers = new HashMap<>(); - static final Map parseSectionLoaded = new HashMap<>(); - - static { - Skript.registerCondition(CustomCondition.class); - Optional> info = Skript.getConditions().stream() - .filter(i -> i.getElementClass() == CustomCondition.class) - .findFirst(); - info.ifPresent(dataTracker::setInfo); - - dataTracker.addManaged(conditionHandlers); - dataTracker.addManaged(parserHandlers); - dataTracker.addManaged(usableSuppliers); - dataTracker.addManaged(parseSectionLoaded); - } - - private SectionNode parseNode; - - @Override - public DataTracker getDataTracker() { - return dataTracker; - } - - @SuppressWarnings("unchecked") - @Override - public boolean init(Literal[] args, int matchedPattern, SkriptParser.ParseResult parseResult, - EntryContainer entryContainer) { - customConditionsUsed = true; - - List patterns = entryContainer.getOptional("patterns", List.class, false); - Script script = parseResult.hasTag("local") ? SkriptUtil.getCurrentScript() : null; - - if (matchedPattern != 1 && patterns != null) { - Skript.error("A custom condition with an inline pattern cannot have a 'patterns' entry too"); - return false; - } - - switch (matchedPattern) { - case 0: // condition with an inline pattern - String pattern = parseResult.regexes.get(0).group(); - register(ConditionSyntaxInfo.create(script, pattern, 1, false, false)); - break; - case 1: // condition with a 'patterns' entry - if (patterns == null) { - Skript.error("A custom condition without an inline pattern must have a 'patterns' entry"); - return false; - } - - int i = 1; - for (String p : patterns) { - register(ConditionSyntaxInfo.create(script, p, i++, false, false)); - } - break; - case 2: // property condition - String property = parseResult.regexes.get(0).group(); - String type = Arrays.stream(((Literal>) args[0]).getArray()) - .map(ClassInfo::getCodeName) - .map(codeName -> { - boolean isPlural = Utils.getEnglishPlural(codeName).getSecond(); - - if (!isPlural) { - return Utils.toEnglishPlural(codeName); - } - - return codeName; - }) - .collect(Collectors.joining("/")); - register(ConditionSyntaxInfo.create(script, "%" + type + "% (is|are) " + property, 1, false, true)); - register(ConditionSyntaxInfo.create(script, "%" + type + "% (isn't|is not|aren't|are not) " + property, 1, true, true)); - break; - } - - return checkHasPatterns(); - } - - @Override - public boolean preLoad() { - super.preLoad(); - EntryContainer entryContainer = getEntryContainer(); - - SectionNode[] parseNode = getParseNode(); - if (parseNode == null) - return false; - this.parseNode = parseNode[0]; - whichInfo.forEach(which -> parseSectionLoaded.put(which, this.parseNode == null)); - - SectionNode usableInNode = entryContainer.getOptional("usable in", SectionNode.class, false); - return usableInNode == null || handleUsableEntry(usableInNode, usableSuppliers); - } - - @Override - public boolean load() { - if (parseNode != null) { - SkriptLogger.setNode(parseNode); - SyntaxParseEvent.register(parseNode, whichInfo, parserHandlers); - - whichInfo.forEach(which -> parseSectionLoaded.put(which, true)); - } - - SectionNode checkNode = getEntryContainer().get("check", SectionNode.class, false); - SkriptLogger.setNode(checkNode); - getParser().setCurrentEvent("custom condition check", ConditionCheckEvent.class); - List items = SkriptUtil.getItemsFromNode(checkNode); - whichInfo.forEach(which -> conditionHandlers.put(which, - new Trigger(getParser().getCurrentScript(), "condition " + which, new SimpleEvent(), items)) - ); - SkriptLogger.setNode(null); - - return true; - } - - public static ConditionSyntaxInfo lookup(Script script, int matchedPattern) { - return dataTracker.lookup(script, matchedPattern); - } + public static boolean customConditionsUsed = false; + + static { + String[] syntax = { + "[:local] condition <.+>", + "[:local] condition", + "[:local] %*classinfos% property condition <.+>" + }; + Skript.registerStructure(StructCustomCondition.class, customSyntaxValidator() + .addSection("check", false) + .build(), + syntax + ); + } + + private static final DataTracker dataTracker = new DataTracker<>(); + + static final Map conditionHandlers = new HashMap<>(); + static final Map parserHandlers = new HashMap<>(); + static final Map>> usableSuppliers = new HashMap<>(); + static final Map parseSectionLoaded = new HashMap<>(); + + static { + Skript.registerCondition(CustomCondition.class); + Optional> info = Skript.getConditions().stream() + .filter(i -> i.getElementClass() == CustomCondition.class) + .findFirst(); + info.ifPresent(dataTracker::setInfo); + + dataTracker.addManaged(conditionHandlers); + dataTracker.addManaged(parserHandlers); + dataTracker.addManaged(usableSuppliers); + dataTracker.addManaged(parseSectionLoaded); + } + + private SectionNode parseNode; + + @Override + public DataTracker getDataTracker() { + return dataTracker; + } + + @SuppressWarnings("unchecked") + @Override + public boolean init(Literal[] args, int matchedPattern, SkriptParser.ParseResult parseResult, + EntryContainer entryContainer) { + customConditionsUsed = true; + + List patterns = entryContainer.getOptional("patterns", List.class, false); + Script script = parseResult.hasTag("local") ? SkriptUtil.getCurrentScript() : null; + + if (matchedPattern != 1 && patterns != null) { + Skript.error("A custom condition with an inline pattern cannot have a 'patterns' entry too"); + return false; + } + + switch (matchedPattern) { + case 0: // condition with an inline pattern + String pattern = parseResult.regexes.get(0).group(); + register(ConditionSyntaxInfo.create(script, pattern, 1, false, false)); + break; + case 1: // condition with a 'patterns' entry + if (patterns == null) { + Skript.error("A custom condition without an inline pattern must have a 'patterns' entry"); + return false; + } + + int i = 1; + for (String p : patterns) { + register(ConditionSyntaxInfo.create(script, p, i++, false, false)); + } + break; + case 2: // property condition + String property = parseResult.regexes.get(0).group(); + String type = Arrays.stream(((Literal>) args[0]).getArray()) + .map(ClassInfo::getCodeName) + .map(codeName -> { + boolean isPlural = Utils.getEnglishPlural(codeName).getSecond(); + + if (!isPlural) { + return Utils.toEnglishPlural(codeName); + } + + return codeName; + }) + .collect(Collectors.joining("/")); + register(ConditionSyntaxInfo.create(script, "%" + type + "% (is|are) " + property, 1, false, true)); + register(ConditionSyntaxInfo.create(script, "%" + type + "% (isn't|is not|aren't|are not) " + property, 1, true, true)); + break; + } + + return checkHasPatterns(); + } + + @Override + public boolean preLoad() { + super.preLoad(); + EntryContainer entryContainer = getEntryContainer(); + + SectionNode[] parseNode = getParseNode(); + if (parseNode == null) + return false; + this.parseNode = parseNode[0]; + whichInfo.forEach(which -> parseSectionLoaded.put(which, this.parseNode == null)); + + SectionNode usableInNode = entryContainer.getOptional("usable in", SectionNode.class, false); + return usableInNode == null || handleUsableEntry(usableInNode, usableSuppliers); + } + + @Override + public boolean load() { + if (parseNode != null) { + SkriptLogger.setNode(parseNode); + SyntaxParseEvent.register(parseNode, whichInfo, parserHandlers); + + whichInfo.forEach(which -> parseSectionLoaded.put(which, true)); + } + + SectionNode checkNode = getEntryContainer().get("check", SectionNode.class, false); + SkriptLogger.setNode(checkNode); + getParser().setCurrentEvent("custom condition check", ConditionCheckEvent.class); + List items = SkriptUtil.getItemsFromNode(checkNode); + whichInfo.forEach(which -> conditionHandlers.put(which, + new Trigger(getParser().getCurrentScript(), "condition " + which, new SimpleEvent(), items)) + ); + SkriptLogger.setNode(null); + + return true; + } + + public static ConditionSyntaxInfo lookup(Script script, int matchedPattern) { + return dataTracker.lookup(script, matchedPattern); + } } diff --git a/src/main/java/org/skriptlang/reflect/syntax/effect/EffectSyntaxInfo.java b/src/main/java/org/skriptlang/reflect/syntax/effect/EffectSyntaxInfo.java index 5259ba5e..39952876 100644 --- a/src/main/java/org/skriptlang/reflect/syntax/effect/EffectSyntaxInfo.java +++ b/src/main/java/org/skriptlang/reflect/syntax/effect/EffectSyntaxInfo.java @@ -8,26 +8,26 @@ public class EffectSyntaxInfo extends CustomSyntaxStructure.SyntaxData { - private EffectSyntaxInfo(Script script, String pattern, int matchedPattern) { - super(script, pattern, matchedPattern); - } - - public static EffectSyntaxInfo create(Script script, String pattern, int matchedPattern) { - return new EffectSyntaxInfo(script, SkriptMirrorUtil.preprocessPattern(pattern), matchedPattern); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - EffectSyntaxInfo that = (EffectSyntaxInfo) o; - return Objects.equals(getScript(), that.getScript()) && - Objects.equals(getPattern(), that.getPattern()); - } - - @Override - public int hashCode() { - return Objects.hash(getScript(), getPattern()); - } + private EffectSyntaxInfo(Script script, String pattern, int matchedPattern) { + super(script, pattern, matchedPattern); + } + + public static EffectSyntaxInfo create(Script script, String pattern, int matchedPattern) { + return new EffectSyntaxInfo(script, SkriptMirrorUtil.preprocessPattern(pattern), matchedPattern); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + EffectSyntaxInfo that = (EffectSyntaxInfo) o; + return Objects.equals(getScript(), that.getScript()) && + Objects.equals(getPattern(), that.getPattern()); + } + + @Override + public int hashCode() { + return Objects.hash(getScript(), getPattern()); + } } diff --git a/src/main/java/org/skriptlang/reflect/syntax/effect/EffectTriggerEvent.java b/src/main/java/org/skriptlang/reflect/syntax/effect/EffectTriggerEvent.java index 26170825..91502f02 100644 --- a/src/main/java/org/skriptlang/reflect/syntax/effect/EffectTriggerEvent.java +++ b/src/main/java/org/skriptlang/reflect/syntax/effect/EffectTriggerEvent.java @@ -8,49 +8,49 @@ import org.bukkit.event.HandlerList; public class EffectTriggerEvent extends CustomSyntaxEvent { - private final static HandlerList handlers = new HandlerList(); - private final String which; - private final TriggerItem next; - private boolean sync = true; - private boolean hasContinued = false; - - public EffectTriggerEvent(Event event, Expression[] expressions, int matchedPattern, - SkriptParser.ParseResult parseResult, String which, TriggerItem next) { - super(event, expressions, matchedPattern, parseResult); - this.which = which; - this.next = next; - } - - public String getWhich() { - return which; - } - - public TriggerItem getNext() { - return next; - } - - public boolean isSync() { - return sync; - } - - public void setSync(boolean sync) { - this.sync = sync; - } - - public boolean hasContinued() { - return hasContinued; - } - - public void setContinued() { - hasContinued = true; - } - - public static HandlerList getHandlerList() { - return handlers; - } - - @Override - public HandlerList getHandlers() { - return handlers; - } + private final static HandlerList handlers = new HandlerList(); + private final String which; + private final TriggerItem next; + private boolean sync = true; + private boolean hasContinued = false; + + public EffectTriggerEvent(Event event, Expression[] expressions, int matchedPattern, + SkriptParser.ParseResult parseResult, String which, TriggerItem next) { + super(event, expressions, matchedPattern, parseResult); + this.which = which; + this.next = next; + } + + public String getWhich() { + return which; + } + + public TriggerItem getNext() { + return next; + } + + public boolean isSync() { + return sync; + } + + public void setSync(boolean sync) { + this.sync = sync; + } + + public boolean hasContinued() { + return hasContinued; + } + + public void setContinued() { + hasContinued = true; + } + + public static HandlerList getHandlerList() { + return handlers; + } + + @Override + public HandlerList getHandlers() { + return handlers; + } } diff --git a/src/main/java/org/skriptlang/reflect/syntax/effect/elements/CustomEffect.java b/src/main/java/org/skriptlang/reflect/syntax/effect/elements/CustomEffect.java index 7aa8e4b5..98788dae 100644 --- a/src/main/java/org/skriptlang/reflect/syntax/effect/elements/CustomEffect.java +++ b/src/main/java/org/skriptlang/reflect/syntax/effect/elements/CustomEffect.java @@ -21,95 +21,95 @@ public class CustomEffect extends Effect { - private EffectSyntaxInfo which; - private Expression[] exprs; - private SkriptParser.ParseResult parseResult; - private Object variablesMap; - - @Override - protected void execute(Event e) { - // for effect commands - invokeEffect(e); - } - - @Override - protected TriggerItem walk(Event e) { - EffectTriggerEvent effectEvent = invokeEffect(e); - - if (effectEvent.isSync()) { - return getNext(); - } - - Object localVars = SkriptReflection.getLocals(effectEvent.getDirectEvent()); - new Thread(() -> { - try { - Thread.sleep(1); - if (!effectEvent.hasContinued()) - SkriptReflection.putLocals(localVars, effectEvent.getDirectEvent()); - } catch (InterruptedException ignored) { } - }).start(); - return null; - } - - private EffectTriggerEvent invokeEffect(Event e) { - Trigger trigger = StructCustomEffect.effectHandlers.get(which); - EffectTriggerEvent effectEvent = - new EffectTriggerEvent(e, exprs, which.getMatchedPattern(), parseResult, which.getPattern(), getNext()); - if (trigger == null) { - Skript.error(String.format("The custom effect '%s' no longer has a handler.", which)); - } else { - SkriptReflection.putLocals(SkriptReflection.copyLocals(variablesMap), effectEvent); - trigger.execute(effectEvent); - } - return effectEvent; - } - - @Override - public String toString(Event e, boolean debug) { - return which.getPattern(); - } - - @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, - SkriptParser.ParseResult parseResult) { - which = StructCustomEffect.lookup(SkriptUtil.getCurrentScript(), matchedPattern); - - if (which == null) { - return false; - } - - this.exprs = Arrays.stream(exprs) - .map(SkriptUtil::defendExpression) - .toArray(Expression[]::new); - this.parseResult = parseResult; - - if (!SkriptUtil.canInitSafely(this.exprs)) { - return false; - } - - List> suppliers = StructCustomEffect.usableSuppliers.get(which); - if (suppliers != null && suppliers.size() != 0 && suppliers.stream().noneMatch(Supplier::get)) - return false; - - Boolean bool = StructCustomEffect.parseSectionLoaded.get(which); - if (bool != null && !bool) { - Skript.error("You can't use custom effects with parse sections before they're loaded."); - return false; - } - - Trigger parseHandler = StructCustomEffect.parserHandlers.get(which); - - if (parseHandler != null) { - SyntaxParseEvent event = - new SyntaxParseEvent(this.exprs, matchedPattern, parseResult, getParser().getCurrentEvents()); - - TriggerItem.walk(parseHandler, event); - variablesMap = SkriptReflection.removeLocals(event); - - return event.isMarkedContinue(); - } - - return true; - } + private EffectSyntaxInfo which; + private Expression[] exprs; + private SkriptParser.ParseResult parseResult; + private Object variablesMap; + + @Override + protected void execute(Event e) { + // for effect commands + invokeEffect(e); + } + + @Override + protected TriggerItem walk(Event e) { + EffectTriggerEvent effectEvent = invokeEffect(e); + + if (effectEvent.isSync()) { + return getNext(); + } + + Object localVars = SkriptReflection.getLocals(effectEvent.getDirectEvent()); + new Thread(() -> { + try { + Thread.sleep(1); + if (!effectEvent.hasContinued()) + SkriptReflection.putLocals(localVars, effectEvent.getDirectEvent()); + } catch (InterruptedException ignored) { } + }).start(); + return null; + } + + private EffectTriggerEvent invokeEffect(Event e) { + Trigger trigger = StructCustomEffect.effectHandlers.get(which); + EffectTriggerEvent effectEvent = + new EffectTriggerEvent(e, exprs, which.getMatchedPattern(), parseResult, which.getPattern(), getNext()); + if (trigger == null) { + Skript.error(String.format("The custom effect '%s' no longer has a handler.", which)); + } else { + SkriptReflection.putLocals(SkriptReflection.copyLocals(variablesMap), effectEvent); + trigger.execute(effectEvent); + } + return effectEvent; + } + + @Override + public String toString(Event e, boolean debug) { + return which.getPattern(); + } + + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, + SkriptParser.ParseResult parseResult) { + which = StructCustomEffect.lookup(SkriptUtil.getCurrentScript(), matchedPattern); + + if (which == null) { + return false; + } + + this.exprs = Arrays.stream(exprs) + .map(SkriptUtil::defendExpression) + .toArray(Expression[]::new); + this.parseResult = parseResult; + + if (!SkriptUtil.canInitSafely(this.exprs)) { + return false; + } + + List> suppliers = StructCustomEffect.usableSuppliers.get(which); + if (suppliers != null && suppliers.size() != 0 && suppliers.stream().noneMatch(Supplier::get)) + return false; + + Boolean bool = StructCustomEffect.parseSectionLoaded.get(which); + if (bool != null && !bool) { + Skript.error("You can't use custom effects with parse sections before they're loaded."); + return false; + } + + Trigger parseHandler = StructCustomEffect.parserHandlers.get(which); + + if (parseHandler != null) { + SyntaxParseEvent event = + new SyntaxParseEvent(this.exprs, matchedPattern, parseResult, getParser().getCurrentEvents()); + + TriggerItem.walk(parseHandler, event); + variablesMap = SkriptReflection.removeLocals(event); + + return event.isMarkedContinue(); + } + + return true; + } } diff --git a/src/main/java/org/skriptlang/reflect/syntax/effect/elements/EffDelayEffect.java b/src/main/java/org/skriptlang/reflect/syntax/effect/elements/EffDelayEffect.java index 3d5b2e21..31afbcd3 100644 --- a/src/main/java/org/skriptlang/reflect/syntax/effect/elements/EffDelayEffect.java +++ b/src/main/java/org/skriptlang/reflect/syntax/effect/elements/EffDelayEffect.java @@ -10,27 +10,27 @@ import org.skriptlang.reflect.syntax.effect.EffectTriggerEvent; public class EffDelayEffect extends Effect { - static { - Skript.registerEffect(EffDelayEffect.class, "delay [the] [current] effect"); - } + static { + Skript.registerEffect(EffDelayEffect.class, "delay [the] [current] effect"); + } - @Override - protected void execute(Event e) { - ((EffectTriggerEvent) e).setSync(false); - } + @Override + protected void execute(Event e) { + ((EffectTriggerEvent) e).setSync(false); + } - @Override - public String toString(Event e, boolean debug) { - return "delay effect"; - } + @Override + public String toString(Event e, boolean debug) { + return "delay effect"; + } - @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, - SkriptParser.ParseResult parseResult) { - if (!getParser().isCurrentEvent(EffectTriggerEvent.class)) { - Skript.error("The effect 'delay effect' may only be used in a custom effect.", ErrorQuality.SEMANTIC_ERROR); - return false; - } - return true; - } + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, + SkriptParser.ParseResult parseResult) { + if (!getParser().isCurrentEvent(EffectTriggerEvent.class)) { + Skript.error("The effect 'delay effect' may only be used in a custom effect.", ErrorQuality.SEMANTIC_ERROR); + return false; + } + return true; + } } diff --git a/src/main/java/org/skriptlang/reflect/syntax/effect/elements/StructCustomEffect.java b/src/main/java/org/skriptlang/reflect/syntax/effect/elements/StructCustomEffect.java index 78e68466..af8e4308 100644 --- a/src/main/java/org/skriptlang/reflect/syntax/effect/elements/StructCustomEffect.java +++ b/src/main/java/org/skriptlang/reflect/syntax/effect/elements/StructCustomEffect.java @@ -26,118 +26,118 @@ public class StructCustomEffect extends CustomSyntaxStructure { - public static boolean customEffectsUsed = false; - - static { - String[] syntax = { - "[:local] effect <.+>", - "[:local] effect" - }; - Skript.registerStructure(StructCustomEffect.class, customSyntaxValidator() - .addSection("trigger", false) - .build(), - syntax - ); - } - - private static final DataTracker dataTracker = new DataTracker<>(); - - static final Map effectHandlers = new HashMap<>(); - static final Map parserHandlers = new HashMap<>(); - static final Map>> usableSuppliers = new HashMap<>(); - static final Map parseSectionLoaded = new HashMap<>(); - - static { - Skript.registerEffect(CustomEffect.class); - Optional> info = Skript.getEffects().stream() - .filter(i -> i.getElementClass() == CustomEffect.class) - .findFirst(); - info.ifPresent(dataTracker::setInfo); - - dataTracker.addManaged(effectHandlers); - dataTracker.addManaged(parserHandlers); - dataTracker.addManaged(usableSuppliers); - dataTracker.addManaged(parseSectionLoaded); - } - - private SectionNode parseNode; - - @Override - public DataTracker getDataTracker() { - return dataTracker; - } - - @Override - public boolean init(Literal[] args, int matchedPattern, SkriptParser.ParseResult parseResult, - EntryContainer entryContainer) { - customEffectsUsed = true; - - List patterns = entryContainer.getOptional("patterns", List.class, false); - Script script = parseResult.hasTag("local") ? SkriptUtil.getCurrentScript() : null; - - if (matchedPattern != 1 && patterns != null) { - Skript.error("A custom effect with an inline pattern cannot have a 'patterns' entry too"); - return false; - } - - switch (matchedPattern) { - case 0: // effect with an inline pattern - register(EffectSyntaxInfo.create(script, parseResult.regexes.get(0).group(), 1)); - break; - case 1: // effect with a 'patterns' entry - if (patterns == null) { - Skript.error("A custom effect without an inline pattern must have a 'patterns' entry"); - return false; - } - - int i = 1; - for (String pattern : patterns) { - register(EffectSyntaxInfo.create(script, pattern, i++)); - } - break; - } - - return checkHasPatterns(); - } - - @Override - public boolean preLoad() { - super.preLoad(); - EntryContainer entryContainer = getEntryContainer(); - - SectionNode[] parseNode = getParseNode(); - if (parseNode == null) - return false; - this.parseNode = parseNode[0]; - whichInfo.forEach(which -> parseSectionLoaded.put(which, this.parseNode == null)); - - SectionNode usableInNode = entryContainer.getOptional("usable in", SectionNode.class, false); - return usableInNode == null || handleUsableEntry(usableInNode, usableSuppliers); - } - - @Override - public boolean load() { - if (parseNode != null) { - SkriptLogger.setNode(parseNode); - SyntaxParseEvent.register(parseNode, whichInfo, parserHandlers); - - whichInfo.forEach(which -> parseSectionLoaded.put(which, true)); - } - - SectionNode triggerNode = getEntryContainer().get("trigger", SectionNode.class, false); - SkriptLogger.setNode(triggerNode); - getParser().setCurrentEvent("custom effect trigger", EffectTriggerEvent.class); - List items = SkriptUtil.getItemsFromNode(triggerNode); - whichInfo.forEach(which -> effectHandlers.put(which, - new Trigger(getParser().getCurrentScript(), "effect " + which, new SimpleEvent(), items)) - ); - SkriptLogger.setNode(null); - - return true; - } - - public static EffectSyntaxInfo lookup(Script script, int matchedPattern) { - return dataTracker.lookup(script, matchedPattern); - } + public static boolean customEffectsUsed = false; + + static { + String[] syntax = { + "[:local] effect <.+>", + "[:local] effect" + }; + Skript.registerStructure(StructCustomEffect.class, customSyntaxValidator() + .addSection("trigger", false) + .build(), + syntax + ); + } + + private static final DataTracker dataTracker = new DataTracker<>(); + + static final Map effectHandlers = new HashMap<>(); + static final Map parserHandlers = new HashMap<>(); + static final Map>> usableSuppliers = new HashMap<>(); + static final Map parseSectionLoaded = new HashMap<>(); + + static { + Skript.registerEffect(CustomEffect.class); + Optional> info = Skript.getEffects().stream() + .filter(i -> i.getElementClass() == CustomEffect.class) + .findFirst(); + info.ifPresent(dataTracker::setInfo); + + dataTracker.addManaged(effectHandlers); + dataTracker.addManaged(parserHandlers); + dataTracker.addManaged(usableSuppliers); + dataTracker.addManaged(parseSectionLoaded); + } + + private SectionNode parseNode; + + @Override + public DataTracker getDataTracker() { + return dataTracker; + } + + @Override + public boolean init(Literal[] args, int matchedPattern, SkriptParser.ParseResult parseResult, + EntryContainer entryContainer) { + customEffectsUsed = true; + + List patterns = entryContainer.getOptional("patterns", List.class, false); + Script script = parseResult.hasTag("local") ? SkriptUtil.getCurrentScript() : null; + + if (matchedPattern != 1 && patterns != null) { + Skript.error("A custom effect with an inline pattern cannot have a 'patterns' entry too"); + return false; + } + + switch (matchedPattern) { + case 0: // effect with an inline pattern + register(EffectSyntaxInfo.create(script, parseResult.regexes.get(0).group(), 1)); + break; + case 1: // effect with a 'patterns' entry + if (patterns == null) { + Skript.error("A custom effect without an inline pattern must have a 'patterns' entry"); + return false; + } + + int i = 1; + for (String pattern : patterns) { + register(EffectSyntaxInfo.create(script, pattern, i++)); + } + break; + } + + return checkHasPatterns(); + } + + @Override + public boolean preLoad() { + super.preLoad(); + EntryContainer entryContainer = getEntryContainer(); + + SectionNode[] parseNode = getParseNode(); + if (parseNode == null) + return false; + this.parseNode = parseNode[0]; + whichInfo.forEach(which -> parseSectionLoaded.put(which, this.parseNode == null)); + + SectionNode usableInNode = entryContainer.getOptional("usable in", SectionNode.class, false); + return usableInNode == null || handleUsableEntry(usableInNode, usableSuppliers); + } + + @Override + public boolean load() { + if (parseNode != null) { + SkriptLogger.setNode(parseNode); + SyntaxParseEvent.register(parseNode, whichInfo, parserHandlers); + + whichInfo.forEach(which -> parseSectionLoaded.put(which, true)); + } + + SectionNode triggerNode = getEntryContainer().get("trigger", SectionNode.class, false); + SkriptLogger.setNode(triggerNode); + getParser().setCurrentEvent("custom effect trigger", EffectTriggerEvent.class); + List items = SkriptUtil.getItemsFromNode(triggerNode); + whichInfo.forEach(which -> effectHandlers.put(which, + new Trigger(getParser().getCurrentScript(), "effect " + which, new SimpleEvent(), items)) + ); + SkriptLogger.setNode(null); + + return true; + } + + public static EffectSyntaxInfo lookup(Script script, int matchedPattern) { + return dataTracker.lookup(script, matchedPattern); + } } diff --git a/src/main/java/org/skriptlang/reflect/syntax/event/BukkitCustomEvent.java b/src/main/java/org/skriptlang/reflect/syntax/event/BukkitCustomEvent.java index b9d6b868..2599d9fa 100644 --- a/src/main/java/org/skriptlang/reflect/syntax/event/BukkitCustomEvent.java +++ b/src/main/java/org/skriptlang/reflect/syntax/event/BukkitCustomEvent.java @@ -18,81 +18,81 @@ */ public class BukkitCustomEvent extends Event implements Cancellable { - private static final HandlerList HANDLERS = new HandlerList(); - private final String name; - private final Map, Object> eventValueMap; - private final Map dataMap; - private boolean isCancelled = false; - - public BukkitCustomEvent(String name) { - this(name, !Bukkit.isPrimaryThread()); - } - - public BukkitCustomEvent(String name, boolean isAsync) { - super(isAsync); - this.name = name; - this.eventValueMap = new HashMap<>(); - this.dataMap = new HashMap<>(); - } - - public String getName() { - return this.name; - } - - public void setEventValue(ClassInfo classInfo, Object value) { - if (classInfo != null && classInfo.getC().isInstance(value)) - this.eventValueMap.put(classInfo, value); - } - - public void setEventValue(String type, Object value) { - setEventValue(Classes.getClassInfoFromUserInput(type), value); - } - - public Object getEventValue(ClassInfo classInfo) { - Class clazz = classInfo.getC(); - ClassInfo chosenClassInfo = null; - for (ClassInfo classInfoKey : this.eventValueMap.keySet()) { - if (clazz.isAssignableFrom(classInfoKey.getC())) { - chosenClassInfo = classInfoKey; - break; - } - } - return chosenClassInfo == null ? null : getExactEventValue(chosenClassInfo); - } - - public Object getExactEventValue(ClassInfo classInfo) { - return this.eventValueMap.get(classInfo); - } - - public Object getEventValue(String type) { - ClassInfo classInfo = Classes.getClassInfoFromUserInput(type); - return classInfo == null ? null : getEventValue(classInfo); - } - - public void setData(String key, Object value) { - this.dataMap.put(key, value); - } - - public Object getData(String key) { - return this.dataMap.get(key); - } - - public static HandlerList getHandlerList() { - return HANDLERS; - } - - @Override - public HandlerList getHandlers() { - return HANDLERS; - } - - @Override - public boolean isCancelled() { - return isCancelled; - } - - @Override - public void setCancelled(boolean cancel) { - isCancelled = cancel; - } + private static final HandlerList HANDLERS = new HandlerList(); + private final String name; + private final Map, Object> eventValueMap; + private final Map dataMap; + private boolean isCancelled = false; + + public BukkitCustomEvent(String name) { + this(name, !Bukkit.isPrimaryThread()); + } + + public BukkitCustomEvent(String name, boolean isAsync) { + super(isAsync); + this.name = name; + this.eventValueMap = new HashMap<>(); + this.dataMap = new HashMap<>(); + } + + public String getName() { + return this.name; + } + + public void setEventValue(ClassInfo classInfo, Object value) { + if (classInfo != null && classInfo.getC().isInstance(value)) + this.eventValueMap.put(classInfo, value); + } + + public void setEventValue(String type, Object value) { + setEventValue(Classes.getClassInfoFromUserInput(type), value); + } + + public Object getEventValue(ClassInfo classInfo) { + Class clazz = classInfo.getC(); + ClassInfo chosenClassInfo = null; + for (ClassInfo classInfoKey : this.eventValueMap.keySet()) { + if (clazz.isAssignableFrom(classInfoKey.getC())) { + chosenClassInfo = classInfoKey; + break; + } + } + return chosenClassInfo == null ? null : getExactEventValue(chosenClassInfo); + } + + public Object getExactEventValue(ClassInfo classInfo) { + return this.eventValueMap.get(classInfo); + } + + public Object getEventValue(String type) { + ClassInfo classInfo = Classes.getClassInfoFromUserInput(type); + return classInfo == null ? null : getEventValue(classInfo); + } + + public void setData(String key, Object value) { + this.dataMap.put(key, value); + } + + public Object getData(String key) { + return this.dataMap.get(key); + } + + public static HandlerList getHandlerList() { + return HANDLERS; + } + + @Override + public HandlerList getHandlers() { + return HANDLERS; + } + + @Override + public boolean isCancelled() { + return isCancelled; + } + + @Override + public void setCancelled(boolean cancel) { + isCancelled = cancel; + } } diff --git a/src/main/java/org/skriptlang/reflect/syntax/event/EventSyntaxInfo.java b/src/main/java/org/skriptlang/reflect/syntax/event/EventSyntaxInfo.java index 156b9bd7..3801ec35 100644 --- a/src/main/java/org/skriptlang/reflect/syntax/event/EventSyntaxInfo.java +++ b/src/main/java/org/skriptlang/reflect/syntax/event/EventSyntaxInfo.java @@ -10,30 +10,30 @@ public class EventSyntaxInfo extends CustomSyntaxStructure.SyntaxData { - protected EventSyntaxInfo(Script script, String pattern, int matchedPattern) { - super(script, pattern, matchedPattern); - } - - public static EventSyntaxInfo create(Script script, String pattern, int matchedPattern) { - if (Skript.getVersion().isSmallerThan(new Version(2, 8))) - pattern = "[on] " + pattern + " [with priority (lowest|low|normal|high|highest|monitor)]"; - return new EventSyntaxInfo(script, SkriptMirrorUtil.preprocessPattern(pattern), matchedPattern); - } - - @Override - public boolean equals(Object o) { - if (this == o) - return true; - if (o == null || getClass() != o.getClass()) - return false; - EventSyntaxInfo that = (EventSyntaxInfo) o; - return Objects.equals(getScript(), that.getScript()) && - Objects.equals(getPattern(), that.getPattern()); - } - - @Override - public int hashCode() { - return Objects.hash(getScript(), getPattern()); - } + protected EventSyntaxInfo(Script script, String pattern, int matchedPattern) { + super(script, pattern, matchedPattern); + } + + public static EventSyntaxInfo create(Script script, String pattern, int matchedPattern) { + if (Skript.getVersion().isSmallerThan(new Version(2, 8))) + pattern = "[on] " + pattern + " [with priority (lowest|low|normal|high|highest|monitor)]"; + return new EventSyntaxInfo(script, SkriptMirrorUtil.preprocessPattern(pattern), matchedPattern); + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + EventSyntaxInfo that = (EventSyntaxInfo) o; + return Objects.equals(getScript(), that.getScript()) && + Objects.equals(getPattern(), that.getPattern()); + } + + @Override + public int hashCode() { + return Objects.hash(getScript(), getPattern()); + } } diff --git a/src/main/java/org/skriptlang/reflect/syntax/event/EventTriggerEvent.java b/src/main/java/org/skriptlang/reflect/syntax/event/EventTriggerEvent.java index 29f0d10a..6422c297 100644 --- a/src/main/java/org/skriptlang/reflect/syntax/event/EventTriggerEvent.java +++ b/src/main/java/org/skriptlang/reflect/syntax/event/EventTriggerEvent.java @@ -9,36 +9,36 @@ public class EventTriggerEvent extends CustomSyntaxEvent implements Continuable { - private final static HandlerList handlers = new HandlerList(); - private final String which; - private boolean markedContinue = false; - - public EventTriggerEvent(Event event, Expression[] expressions, int matchedPattern, - SkriptParser.ParseResult parseResult, String which) { - super(event, expressions, matchedPattern, parseResult); - this.which = which; - } - - public String getWhich() { - return which; - } - - public boolean isMarkedContinue() { - return markedContinue; - } - - @Override - public void setContinue(boolean b) { - markedContinue = b; - } - - public static HandlerList getHandlerList() { - return handlers; - } - - @Override - public HandlerList getHandlers() { - return handlers; - } + private final static HandlerList handlers = new HandlerList(); + private final String which; + private boolean markedContinue = false; + + public EventTriggerEvent(Event event, Expression[] expressions, int matchedPattern, + SkriptParser.ParseResult parseResult, String which) { + super(event, expressions, matchedPattern, parseResult); + this.which = which; + } + + public String getWhich() { + return which; + } + + public boolean isMarkedContinue() { + return markedContinue; + } + + @Override + public void setContinue(boolean b) { + markedContinue = b; + } + + public static HandlerList getHandlerList() { + return handlers; + } + + @Override + public HandlerList getHandlers() { + return handlers; + } } diff --git a/src/main/java/org/skriptlang/reflect/syntax/event/EventValuesEntryData.java b/src/main/java/org/skriptlang/reflect/syntax/event/EventValuesEntryData.java index 5ae45b4b..4b6441dc 100644 --- a/src/main/java/org/skriptlang/reflect/syntax/event/EventValuesEntryData.java +++ b/src/main/java/org/skriptlang/reflect/syntax/event/EventValuesEntryData.java @@ -14,40 +14,40 @@ public class EventValuesEntryData extends KeyValueEntryData>> { - private static final String listSplitPattern = "\\s*,?\\s+(and|n?or)\\s+|\\s*,\\s*"; // Found in SkriptParser - - public EventValuesEntryData(String key, @Nullable List> defaultValue, boolean optional) { - super(key, defaultValue, optional); - } - - @Override - @Nullable - protected List> getValue(String value) { - String[] stringClasses = value.split(listSplitPattern); - List> classInfos = new ArrayList<>(stringClasses.length); - for (String stringClass : stringClasses) { - ClassInfo classInfo = Classes.getClassInfoFromUserInput(stringClass); - if (classInfo == null) { - Skript.error("The type " + stringClass + " doesn't exist"); - return null; - } - classInfos.add(classInfo); - } - return classInfos; - } - - @Override - public final boolean canCreateWith(Node node) { - if (!(node instanceof SimpleNode)) - return false; - String key = node.getKey(); - if (key == null) - return false; - return canCreateWith(ScriptLoader.replaceOptions(key)); - } - - protected boolean canCreateWith(String node) { - return node.startsWith(getKey() + getSeparator()); - } + private static final String listSplitPattern = "\\s*,?\\s+(and|n?or)\\s+|\\s*,\\s*"; // Found in SkriptParser + + public EventValuesEntryData(String key, @Nullable List> defaultValue, boolean optional) { + super(key, defaultValue, optional); + } + + @Override + @Nullable + protected List> getValue(String value) { + String[] stringClasses = value.split(listSplitPattern); + List> classInfos = new ArrayList<>(stringClasses.length); + for (String stringClass : stringClasses) { + ClassInfo classInfo = Classes.getClassInfoFromUserInput(stringClass); + if (classInfo == null) { + Skript.error("The type " + stringClass + " doesn't exist"); + return null; + } + classInfos.add(classInfo); + } + return classInfos; + } + + @Override + public final boolean canCreateWith(Node node) { + if (!(node instanceof SimpleNode)) + return false; + String key = node.getKey(); + if (key == null) + return false; + return canCreateWith(ScriptLoader.replaceOptions(key)); + } + + protected boolean canCreateWith(String node) { + return node.startsWith(getKey() + getSeparator()); + } } diff --git a/src/main/java/org/skriptlang/reflect/syntax/event/elements/CondEventCancelled.java b/src/main/java/org/skriptlang/reflect/syntax/event/elements/CondEventCancelled.java index 6049b41c..bb2335ac 100644 --- a/src/main/java/org/skriptlang/reflect/syntax/event/elements/CondEventCancelled.java +++ b/src/main/java/org/skriptlang/reflect/syntax/event/elements/CondEventCancelled.java @@ -9,18 +9,18 @@ // backwards compatibility. And for some reason this works, so I'll keep it. public class CondEventCancelled extends PropertyCondition { - static { - register(CondEventCancelled.class, "cancelled", "events"); - } + static { + register(CondEventCancelled.class, "cancelled", "events"); + } - @Override - public boolean check(T event) { - return event instanceof Cancellable && ((Cancellable) event).isCancelled(); - } + @Override + public boolean check(T event) { + return event instanceof Cancellable && ((Cancellable) event).isCancelled(); + } - @Override - protected String getPropertyName() { - return "cancelled"; - } + @Override + protected String getPropertyName() { + return "cancelled"; + } } diff --git a/src/main/java/org/skriptlang/reflect/syntax/event/elements/CustomEvent.java b/src/main/java/org/skriptlang/reflect/syntax/event/elements/CustomEvent.java index dbc515c2..024c76e0 100644 --- a/src/main/java/org/skriptlang/reflect/syntax/event/elements/CustomEvent.java +++ b/src/main/java/org/skriptlang/reflect/syntax/event/elements/CustomEvent.java @@ -25,90 +25,90 @@ */ public class CustomEvent extends SkriptEvent { - public static EventSyntaxInfo lastWhich; + public static EventSyntaxInfo lastWhich; - private EventSyntaxInfo which; - private Expression[] exprs; - private SkriptParser.ParseResult parseResult; - private Object variablesMap; + private EventSyntaxInfo which; + private Expression[] exprs; + private SkriptParser.ParseResult parseResult; + private Object variablesMap; - @Override - public boolean init(Literal[] args, int matchedPattern, SkriptParser.ParseResult parseResult) { - which = StructCustomEvent.lookup(SkriptUtil.getCurrentScript(), matchedPattern); + @Override + public boolean init(Literal[] args, int matchedPattern, SkriptParser.ParseResult parseResult) { + which = StructCustomEvent.lookup(SkriptUtil.getCurrentScript(), matchedPattern); - if (which == null) { - return false; - } + if (which == null) { + return false; + } - this.exprs = Arrays.stream(args) - .map(SkriptUtil::defendExpression) - .toArray(Expression[]::new); - this.parseResult = parseResult; + this.exprs = Arrays.stream(args) + .map(SkriptUtil::defendExpression) + .toArray(Expression[]::new); + this.parseResult = parseResult; - if (!SkriptUtil.canInitSafely(this.exprs)) { - return false; - } + if (!SkriptUtil.canInitSafely(this.exprs)) { + return false; + } - Boolean bool = StructCustomEvent.parseSectionLoaded.get(which); - if (bool != null && !bool) { - Skript.error("You can't use custom events with parse sections before they're loaded."); - return false; - } + Boolean bool = StructCustomEvent.parseSectionLoaded.get(which); + if (bool != null && !bool) { + Skript.error("You can't use custom events with parse sections before they're loaded."); + return false; + } - Trigger parseHandler = StructCustomEvent.parserHandlers.get(which); + Trigger parseHandler = StructCustomEvent.parserHandlers.get(which); - if (parseHandler == null) { - setLastWhich(which); + if (parseHandler == null) { + setLastWhich(which); - return true; - } + return true; + } - SyntaxParseEvent event = - new SyntaxParseEvent(this.exprs, matchedPattern, parseResult, getParser().getCurrentEvents()); + SyntaxParseEvent event = + new SyntaxParseEvent(this.exprs, matchedPattern, parseResult, getParser().getCurrentEvents()); - setLastWhich(which); + setLastWhich(which); - TriggerItem.walk(parseHandler, event); - variablesMap = SkriptReflection.removeLocals(event); + TriggerItem.walk(parseHandler, event); + variablesMap = SkriptReflection.removeLocals(event); - setLastWhich(which); + setLastWhich(which); - return event.isMarkedContinue(); - } + return event.isMarkedContinue(); + } - @Override - public boolean load() { - CustomEvent.setLastWhich(which); - boolean parsed = super.load(); - CustomEvent.setLastWhich(null); - return parsed; - } + @Override + public boolean load() { + CustomEvent.setLastWhich(which); + boolean parsed = super.load(); + CustomEvent.setLastWhich(null); + return parsed; + } - @Override - public boolean check(Event e) { - BukkitCustomEvent bukkitCustomEvent = (BukkitCustomEvent) e; - if (!bukkitCustomEvent.getName().equalsIgnoreCase(StructCustomEvent.nameValues.get(which))) - return false; + @Override + public boolean check(Event e) { + BukkitCustomEvent bukkitCustomEvent = (BukkitCustomEvent) e; + if (!bukkitCustomEvent.getName().equalsIgnoreCase(StructCustomEvent.nameValues.get(which))) + return false; - EventTriggerEvent eventTriggerEvent = new EventTriggerEvent(e, exprs, which.getMatchedPattern(), parseResult, which.getPattern()); - SkriptReflection.putLocals(SkriptReflection.copyLocals(variablesMap), eventTriggerEvent); + EventTriggerEvent eventTriggerEvent = new EventTriggerEvent(e, exprs, which.getMatchedPattern(), parseResult, which.getPattern()); + SkriptReflection.putLocals(SkriptReflection.copyLocals(variablesMap), eventTriggerEvent); - Trigger trigger = StructCustomEvent.eventHandlers.get(which); - if (trigger != null) { - trigger.execute(eventTriggerEvent); - return eventTriggerEvent.isMarkedContinue(); - } + Trigger trigger = StructCustomEvent.eventHandlers.get(which); + if (trigger != null) { + trigger.execute(eventTriggerEvent); + return eventTriggerEvent.isMarkedContinue(); + } - return true; - } + return true; + } - public static void setLastWhich(EventSyntaxInfo which) { - lastWhich = which; - } + public static void setLastWhich(EventSyntaxInfo which) { + lastWhich = which; + } - @Override - public String toString(@Nullable Event e, boolean debug) { - return which.getPattern(); - } + @Override + public String toString(@Nullable Event e, boolean debug) { + return which.getPattern(); + } } diff --git a/src/main/java/org/skriptlang/reflect/syntax/event/elements/CustomEventUtils.java b/src/main/java/org/skriptlang/reflect/syntax/event/elements/CustomEventUtils.java index e1ee6360..31bbfc00 100644 --- a/src/main/java/org/skriptlang/reflect/syntax/event/elements/CustomEventUtils.java +++ b/src/main/java/org/skriptlang/reflect/syntax/event/elements/CustomEventUtils.java @@ -12,42 +12,42 @@ */ public class CustomEventUtils { - /** - * @param which The EventSyntaxInfo that belongs to the used custom event - * @param classInfo The used ClassInfo - * @return whether the given CustomEvent supports the given ClassInfo as an event-value. - */ - public static boolean hasEventValue(EventSyntaxInfo which, ClassInfo classInfo) { - List> eventValueClassInfoList = StructCustomEvent.eventValueTypes.get(which); - if (eventValueClassInfoList == null) - return false; - - Class classInfoClass = classInfo.getC(); - for (ClassInfo loopedClassInfo : eventValueClassInfoList) { - if (classInfoClass.isAssignableFrom(loopedClassInfo.getC())) { - return true; - } - } - return false; - } - - /** - * @param classInfo The ClassInfo which name is returned - * @return Skripts name for the given ClassInfo. - */ - public static String getName(ClassInfo classInfo) { - return Classes.getSuperClassInfo(classInfo.getC()).getName().toString(); - } - - /** - * @param which The EventSyntaxInfo that belongs to the used custom event - * @return The defined name (identifier) of the custom event from the given EventSyntaxInfo - */ - public static String getName(EventSyntaxInfo which) { - if (which == null) - return null; - - return StructCustomEvent.nameValues.get(which); - } + /** + * @param which The EventSyntaxInfo that belongs to the used custom event + * @param classInfo The used ClassInfo + * @return whether the given CustomEvent supports the given ClassInfo as an event-value. + */ + public static boolean hasEventValue(EventSyntaxInfo which, ClassInfo classInfo) { + List> eventValueClassInfoList = StructCustomEvent.eventValueTypes.get(which); + if (eventValueClassInfoList == null) + return false; + + Class classInfoClass = classInfo.getC(); + for (ClassInfo loopedClassInfo : eventValueClassInfoList) { + if (classInfoClass.isAssignableFrom(loopedClassInfo.getC())) { + return true; + } + } + return false; + } + + /** + * @param classInfo The ClassInfo which name is returned + * @return Skripts name for the given ClassInfo. + */ + public static String getName(ClassInfo classInfo) { + return Classes.getSuperClassInfo(classInfo.getC()).getName().toString(); + } + + /** + * @param which The EventSyntaxInfo that belongs to the used custom event + * @return The defined name (identifier) of the custom event from the given EventSyntaxInfo + */ + public static String getName(EventSyntaxInfo which) { + if (which == null) + return null; + + return StructCustomEvent.nameValues.get(which); + } } diff --git a/src/main/java/org/skriptlang/reflect/syntax/event/elements/EffCallEvent.java b/src/main/java/org/skriptlang/reflect/syntax/event/elements/EffCallEvent.java index e4f016c2..e97f15c6 100644 --- a/src/main/java/org/skriptlang/reflect/syntax/event/elements/EffCallEvent.java +++ b/src/main/java/org/skriptlang/reflect/syntax/event/elements/EffCallEvent.java @@ -12,27 +12,27 @@ public class EffCallEvent extends Effect { - static { - Skript.registerEffect(EffCallEvent.class, "call [event] %events%"); - } - - private Expression eventExpr; - - @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) { - eventExpr = SkriptUtil.defendExpression(exprs[0]); - return SkriptUtil.canInitSafely(eventExpr); - } - - @Override - protected void execute(Event e) { - for (Event event : eventExpr.getArray(e)) - Bukkit.getPluginManager().callEvent(event); - } - - @Override - public String toString(@Nullable Event e, boolean debug) { - return "call event " + eventExpr.toString(e, debug); - } + static { + Skript.registerEffect(EffCallEvent.class, "call [event] %events%"); + } + + private Expression eventExpr; + + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) { + eventExpr = SkriptUtil.defendExpression(exprs[0]); + return SkriptUtil.canInitSafely(eventExpr); + } + + @Override + protected void execute(Event e) { + for (Event event : eventExpr.getArray(e)) + Bukkit.getPluginManager().callEvent(event); + } + + @Override + public String toString(@Nullable Event e, boolean debug) { + return "call event " + eventExpr.toString(e, debug); + } } diff --git a/src/main/java/org/skriptlang/reflect/syntax/event/elements/ExprCustomEvent.java b/src/main/java/org/skriptlang/reflect/syntax/event/elements/ExprCustomEvent.java index 71f492cd..a98dd51d 100644 --- a/src/main/java/org/skriptlang/reflect/syntax/event/elements/ExprCustomEvent.java +++ b/src/main/java/org/skriptlang/reflect/syntax/event/elements/ExprCustomEvent.java @@ -16,88 +16,88 @@ public class ExprCustomEvent extends SimpleExpression { - static { - Skript.registerExpression(ExprCustomEvent.class, Event.class, ExpressionType.PATTERN_MATCHES_EVERYTHING, - "[a] [new] custom event %string% [(with|using)] data %-objects%", - "[a] [new] custom event %string% [(with|using) [[event-]values] %-objects%] [[and] [(with|using)] data %-objects%]"); - } - - private Expression customEventName; - private Variable eventValueVarList; - private Variable dataVarList; - - @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) { - if (!SkriptUtil.canInitSafely(exprs)) - return false; - - this.customEventName = SkriptUtil.defendExpression(exprs[0]); - - if (matchedPattern == 1) { - if (exprs[1] != null) { - Expression var = SkriptUtil.defendExpression(exprs[1]); - - if (var instanceof Variable && ((Variable) var).isList()) { - this.eventValueVarList = (Variable) var; - } else { - Skript.error(var.toString(null, false) + " is not a list variable."); - return false; - } - } - } - - Expression expr = exprs[matchedPattern == 0 ? 1 : 2]; - if (expr != null) { - Expression var = SkriptUtil.defendExpression(expr); - - if (var instanceof Variable && ((Variable) var).isList()) { - this.dataVarList = (Variable) var; - } else { - Skript.error(var.toString(null, false) + " is not a list variable."); - return false; - } - } - - return SkriptUtil.canInitSafely(customEventName, eventValueVarList, dataVarList); - } - - @Nullable - @Override - protected Event[] get(Event e) { - String name = this.customEventName.getSingle(e); - if (name == null) - return null; - BukkitCustomEvent bukkitCustomEvent = new BukkitCustomEvent(name); - - if (eventValueVarList != null) - eventValueVarList.variablesIterator(e).forEachRemaining(pair -> { - if (pair.getKey() == null) - return; - ClassInfo classInfo = Classes.getClassInfoFromUserInput(pair.getKey()); - bukkitCustomEvent.setEventValue(classInfo, pair.getValue()); - }); - - if (dataVarList != null) - dataVarList.variablesIterator(e).forEachRemaining(pair -> { - bukkitCustomEvent.setData(pair.getKey(), pair.getValue()); - }); - - return new Event[] {bukkitCustomEvent}; - } - - @Override - public boolean isSingle() { - return true; - } - - @Override - public Class getReturnType() { - return Event.class; - } - - @Override - public String toString(@Nullable Event e, boolean debug) { - return "new custom event " + customEventName.toString(e, debug); - } + static { + Skript.registerExpression(ExprCustomEvent.class, Event.class, ExpressionType.PATTERN_MATCHES_EVERYTHING, + "[a] [new] custom event %string% [(with|using)] data %-objects%", + "[a] [new] custom event %string% [(with|using) [[event-]values] %-objects%] [[and] [(with|using)] data %-objects%]"); + } + + private Expression customEventName; + private Variable eventValueVarList; + private Variable dataVarList; + + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) { + if (!SkriptUtil.canInitSafely(exprs)) + return false; + + this.customEventName = SkriptUtil.defendExpression(exprs[0]); + + if (matchedPattern == 1) { + if (exprs[1] != null) { + Expression var = SkriptUtil.defendExpression(exprs[1]); + + if (var instanceof Variable && ((Variable) var).isList()) { + this.eventValueVarList = (Variable) var; + } else { + Skript.error(var.toString(null, false) + " is not a list variable."); + return false; + } + } + } + + Expression expr = exprs[matchedPattern == 0 ? 1 : 2]; + if (expr != null) { + Expression var = SkriptUtil.defendExpression(expr); + + if (var instanceof Variable && ((Variable) var).isList()) { + this.dataVarList = (Variable) var; + } else { + Skript.error(var.toString(null, false) + " is not a list variable."); + return false; + } + } + + return SkriptUtil.canInitSafely(customEventName, eventValueVarList, dataVarList); + } + + @Nullable + @Override + protected Event[] get(Event e) { + String name = this.customEventName.getSingle(e); + if (name == null) + return null; + BukkitCustomEvent bukkitCustomEvent = new BukkitCustomEvent(name); + + if (eventValueVarList != null) + eventValueVarList.variablesIterator(e).forEachRemaining(pair -> { + if (pair.getKey() == null) + return; + ClassInfo classInfo = Classes.getClassInfoFromUserInput(pair.getKey()); + bukkitCustomEvent.setEventValue(classInfo, pair.getValue()); + }); + + if (dataVarList != null) + dataVarList.variablesIterator(e).forEachRemaining(pair -> { + bukkitCustomEvent.setData(pair.getKey(), pair.getValue()); + }); + + return new Event[] {bukkitCustomEvent}; + } + + @Override + public boolean isSingle() { + return true; + } + + @Override + public Class getReturnType() { + return Event.class; + } + + @Override + public String toString(@Nullable Event e, boolean debug) { + return "new custom event " + customEventName.toString(e, debug); + } } diff --git a/src/main/java/org/skriptlang/reflect/syntax/event/elements/ExprCustomEventValue.java b/src/main/java/org/skriptlang/reflect/syntax/event/elements/ExprCustomEventValue.java index e72fb949..e9262827 100644 --- a/src/main/java/org/skriptlang/reflect/syntax/event/elements/ExprCustomEventValue.java +++ b/src/main/java/org/skriptlang/reflect/syntax/event/elements/ExprCustomEventValue.java @@ -20,82 +20,82 @@ @SuppressWarnings("unused") public class ExprCustomEventValue extends EventValueExpression { - static { - //noinspection unchecked - Skript.registerExpression(ExprCustomEventValue.class, Object.class, ExpressionType.PATTERN_MATCHES_EVERYTHING, "[the] [event-]<.+>"); - } - - private ClassInfo classInfo; - private Changer changer; - - @SuppressWarnings("unchecked") - public ExprCustomEventValue() { - super((Class) Object.class); - } - - @SuppressWarnings("unchecked") - @Override - public boolean init(final Expression[] exprs, final int matchedPattern, final Kleenean isDelayed, final SkriptParser.ParseResult parseResult) { - if (!getParser().isCurrentEvent(BukkitCustomEvent.class, EventTriggerEvent.class)) - return false; - EventSyntaxInfo which = CustomEvent.lastWhich; - if (which == null) - return false; - - String stringClass = parseResult.regexes.get(0).group(); - classInfo = (ClassInfo) Classes.getClassInfoFromUserInput(stringClass); - if (classInfo == null) { - return false; - } - - if (!CustomEventUtils.hasEventValue(which, classInfo)) { - Skript.error("There is no " + CustomEventUtils.getName(classInfo) + " in the custom event " + - CustomEventUtils.getName(which)); - return false; - } - - return true; - } - - @SuppressWarnings("unchecked") - @Override - public T[] get(Event event) { - if (!(event instanceof BukkitCustomEvent || event instanceof EventTriggerEvent)) - return null; - BukkitCustomEvent bukkitCustomEvent; - if (event instanceof BukkitCustomEvent) { - bukkitCustomEvent = (BukkitCustomEvent) event; - } else { - bukkitCustomEvent = (BukkitCustomEvent) ((EventTriggerEvent) event).getDirectEvent(); - } - - T[] tArray = (T[]) Array.newInstance(classInfo.getC(), 1); - tArray[0] = (T) bukkitCustomEvent.getEventValue(classInfo); - return tArray; - } - - @Override - public Class[] acceptChange(Changer.ChangeMode mode) { - changer = classInfo.getChanger(); - return changer == null ? null : changer.acceptChange(mode); - } - - @Override - public void change(Event e, Object[] delta, Changer.ChangeMode mode) { - if (changer == null) - throw new UnsupportedOperationException(); - Changer.ChangerUtils.change(changer, getArray(e), delta, mode); - } - - @Override - public String toString(final @Nullable Event e, final boolean debug) { - return "event-" + classInfo.getCodeName(); - } - - @SuppressWarnings("unchecked") - @Override - public Class getReturnType() { - return (Class) classInfo.getC(); - } + static { + //noinspection unchecked + Skript.registerExpression(ExprCustomEventValue.class, Object.class, ExpressionType.PATTERN_MATCHES_EVERYTHING, "[the] [event-]<.+>"); + } + + private ClassInfo classInfo; + private Changer changer; + + @SuppressWarnings("unchecked") + public ExprCustomEventValue() { + super((Class) Object.class); + } + + @SuppressWarnings("unchecked") + @Override + public boolean init(final Expression[] exprs, final int matchedPattern, final Kleenean isDelayed, final SkriptParser.ParseResult parseResult) { + if (!getParser().isCurrentEvent(BukkitCustomEvent.class, EventTriggerEvent.class)) + return false; + EventSyntaxInfo which = CustomEvent.lastWhich; + if (which == null) + return false; + + String stringClass = parseResult.regexes.get(0).group(); + classInfo = (ClassInfo) Classes.getClassInfoFromUserInput(stringClass); + if (classInfo == null) { + return false; + } + + if (!CustomEventUtils.hasEventValue(which, classInfo)) { + Skript.error("There is no " + CustomEventUtils.getName(classInfo) + " in the custom event " + + CustomEventUtils.getName(which)); + return false; + } + + return true; + } + + @SuppressWarnings("unchecked") + @Override + public T[] get(Event event) { + if (!(event instanceof BukkitCustomEvent || event instanceof EventTriggerEvent)) + return null; + BukkitCustomEvent bukkitCustomEvent; + if (event instanceof BukkitCustomEvent) { + bukkitCustomEvent = (BukkitCustomEvent) event; + } else { + bukkitCustomEvent = (BukkitCustomEvent) ((EventTriggerEvent) event).getDirectEvent(); + } + + T[] tArray = (T[]) Array.newInstance(classInfo.getC(), 1); + tArray[0] = (T) bukkitCustomEvent.getEventValue(classInfo); + return tArray; + } + + @Override + public Class[] acceptChange(Changer.ChangeMode mode) { + changer = classInfo.getChanger(); + return changer == null ? null : changer.acceptChange(mode); + } + + @Override + public void change(Event e, Object[] delta, Changer.ChangeMode mode) { + if (changer == null) + throw new UnsupportedOperationException(); + Changer.ChangerUtils.change(changer, getArray(e), delta, mode); + } + + @Override + public String toString(final @Nullable Event e, final boolean debug) { + return "event-" + classInfo.getCodeName(); + } + + @SuppressWarnings("unchecked") + @Override + public Class getReturnType() { + return (Class) classInfo.getC(); + } } diff --git a/src/main/java/org/skriptlang/reflect/syntax/event/elements/ExprEventData.java b/src/main/java/org/skriptlang/reflect/syntax/event/elements/ExprEventData.java index bc8721ef..f46d5589 100644 --- a/src/main/java/org/skriptlang/reflect/syntax/event/elements/ExprEventData.java +++ b/src/main/java/org/skriptlang/reflect/syntax/event/elements/ExprEventData.java @@ -13,54 +13,54 @@ public class ExprEventData extends SimpleExpression { - static { - Skript.registerExpression(ExprEventData.class, Object.class, ExpressionType.COMBINED, "[extra] [event(-| )]data %string%"); - } + static { + Skript.registerExpression(ExprEventData.class, Object.class, ExpressionType.COMBINED, "[extra] [event(-| )]data %string%"); + } - private Expression dataIndex; + private Expression dataIndex; - @SuppressWarnings("unchecked") - @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) { - if (!getParser().isCurrentEvent(BukkitCustomEvent.class, EventTriggerEvent.class)) { - Skript.error("The event data expression can only be used in a custom event"); - return false; - } - dataIndex = (Expression) exprs[0]; - return true; - } + @SuppressWarnings("unchecked") + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) { + if (!getParser().isCurrentEvent(BukkitCustomEvent.class, EventTriggerEvent.class)) { + Skript.error("The event data expression can only be used in a custom event"); + return false; + } + dataIndex = (Expression) exprs[0]; + return true; + } - @Nullable - @Override - protected Object[] get(Event e) { - String key = dataIndex.getSingle(e); - if (key == null) - return null; + @Nullable + @Override + protected Object[] get(Event e) { + String key = dataIndex.getSingle(e); + if (key == null) + return null; - BukkitCustomEvent bukkitCustomEvent; - if (e instanceof BukkitCustomEvent) { - bukkitCustomEvent = (BukkitCustomEvent) e; - } else { - bukkitCustomEvent = (BukkitCustomEvent) ((EventTriggerEvent) e).getDirectEvent(); - } + BukkitCustomEvent bukkitCustomEvent; + if (e instanceof BukkitCustomEvent) { + bukkitCustomEvent = (BukkitCustomEvent) e; + } else { + bukkitCustomEvent = (BukkitCustomEvent) ((EventTriggerEvent) e).getDirectEvent(); + } - Object data = bukkitCustomEvent.getData(key); - return new Object[] {data}; - } + Object data = bukkitCustomEvent.getData(key); + return new Object[] {data}; + } - @Override - public boolean isSingle() { - return true; - } + @Override + public boolean isSingle() { + return true; + } - @Override - public Class getReturnType() { - return Object.class; - } + @Override + public Class getReturnType() { + return Object.class; + } - @Override - public String toString(@Nullable Event e, boolean debug) { - return "event data"; - } + @Override + public String toString(@Nullable Event e, boolean debug) { + return "event data"; + } } diff --git a/src/main/java/org/skriptlang/reflect/syntax/event/elements/ExprReplacedEventValue.java b/src/main/java/org/skriptlang/reflect/syntax/event/elements/ExprReplacedEventValue.java index d15af15d..f6df7578 100644 --- a/src/main/java/org/skriptlang/reflect/syntax/event/elements/ExprReplacedEventValue.java +++ b/src/main/java/org/skriptlang/reflect/syntax/event/elements/ExprReplacedEventValue.java @@ -19,66 +19,66 @@ */ public class ExprReplacedEventValue extends EventValueExpression { - private final EventValueExpression original; + private final EventValueExpression original; - public ExprReplacedEventValue(EventValueExpression original) { - super(original.getReturnType()); - this.original = original; - } + public ExprReplacedEventValue(EventValueExpression original) { + super(original.getReturnType()); + this.original = original; + } - @SuppressWarnings("unchecked") - @Override - @Nullable - protected T[] get(Event e) { - if (e instanceof BukkitCustomEvent || e instanceof EventTriggerEvent) { - BukkitCustomEvent bukkitCustomEvent; - if (e instanceof BukkitCustomEvent) { - bukkitCustomEvent = (BukkitCustomEvent) e; - } else { - bukkitCustomEvent = (BukkitCustomEvent) ((EventTriggerEvent) e).getDirectEvent(); - } + @SuppressWarnings("unchecked") + @Override + @Nullable + protected T[] get(Event e) { + if (e instanceof BukkitCustomEvent || e instanceof EventTriggerEvent) { + BukkitCustomEvent bukkitCustomEvent; + if (e instanceof BukkitCustomEvent) { + bukkitCustomEvent = (BukkitCustomEvent) e; + } else { + bukkitCustomEvent = (BukkitCustomEvent) ((EventTriggerEvent) e).getDirectEvent(); + } - Class valueClass = original.getReturnType(); + Class valueClass = original.getReturnType(); - T[] tArray = (T[]) Array.newInstance(valueClass, 1); - tArray[0] = (T) bukkitCustomEvent.getEventValue(Classes.getSuperClassInfo(valueClass)); - return tArray; - } else { - return original.getArray(e); - } - } + T[] tArray = (T[]) Array.newInstance(valueClass, 1); + tArray[0] = (T) bukkitCustomEvent.getEventValue(Classes.getSuperClassInfo(valueClass)); + return tArray; + } else { + return original.getArray(e); + } + } - @SuppressWarnings("null") - @Override - public boolean init() { - if (getParser().isCurrentEvent(BukkitCustomEvent.class, EventTriggerEvent.class)) { - EventSyntaxInfo which = CustomEvent.lastWhich; - ClassInfo classInfo = Classes.getSuperClassInfo(getReturnType()); - return CustomEventUtils.hasEventValue(which, classInfo); - } else { - return original.init(); - } - } + @SuppressWarnings("null") + @Override + public boolean init() { + if (getParser().isCurrentEvent(BukkitCustomEvent.class, EventTriggerEvent.class)) { + EventSyntaxInfo which = CustomEvent.lastWhich; + ClassInfo classInfo = Classes.getSuperClassInfo(getReturnType()); + return CustomEventUtils.hasEventValue(which, classInfo); + } else { + return original.init(); + } + } - @Override - public String toString(@Nullable Event e, boolean debug) { - return original.toString(e, debug); - } + @Override + public String toString(@Nullable Event e, boolean debug) { + return original.toString(e, debug); + } - @Override - @Nullable - public Class[] acceptChange(Changer.ChangeMode mode) { - return original.acceptChange(mode); - } + @Override + @Nullable + public Class[] acceptChange(Changer.ChangeMode mode) { + return original.acceptChange(mode); + } - @Override - public void change(Event e, @Nullable Object[] delta, Changer.ChangeMode mode) { - original.change(e, delta, mode); - } + @Override + public void change(Event e, @Nullable Object[] delta, Changer.ChangeMode mode) { + original.change(e, delta, mode); + } - @Override - public boolean setTime(int time) { - return original.setTime(time); - } + @Override + public boolean setTime(int time) { + return original.setTime(time); + } } diff --git a/src/main/java/org/skriptlang/reflect/syntax/event/elements/StructCustomEvent.java b/src/main/java/org/skriptlang/reflect/syntax/event/elements/StructCustomEvent.java index d526ff1c..e6343243 100644 --- a/src/main/java/org/skriptlang/reflect/syntax/event/elements/StructCustomEvent.java +++ b/src/main/java/org/skriptlang/reflect/syntax/event/elements/StructCustomEvent.java @@ -29,138 +29,138 @@ public class StructCustomEvent extends CustomSyntaxStructure { - public static boolean customEventsUsed = false; - - static { - Skript.registerStructure(StructCustomEvent.class, customSyntaxValidator() - .addEntry("pattern", null, true) - .addEntryData(new EventValuesEntryData("event values", null, true) { - @Override - public boolean canCreateWith(String node) { - return super.canCreateWith(node) || node.startsWith(getKey().replace(' ', '-') + getSeparator()); - } - }) - .addSection("check", true) - .build(), - "[:local] [custom] event %string%" - ); - } - - private static final DataTracker dataTracker = new DataTracker<>(); - - static final Map nameValues = new HashMap<>(); - static final Map>> eventValueTypes = new HashMap<>(); - static final Map parserHandlers = new HashMap<>(); - static final Map eventHandlers = new HashMap<>(); - static final Map parseSectionLoaded = new HashMap<>(); - - static { - Skript.registerEvent("custom event", CustomEvent.class, BukkitCustomEvent.class); - Optional> info = Skript.getEvents().stream() - .filter(i -> i.getElementClass() == CustomEvent.class) - .findFirst(); - info.ifPresent(dataTracker::setInfo); - - dataTracker.addManaged(nameValues); - dataTracker.addManaged(eventValueTypes); - dataTracker.addManaged(parserHandlers); - dataTracker.addManaged(eventHandlers); - dataTracker.addManaged(parseSectionLoaded); - } - - private SectionNode parseNode; - - @Override - protected DataTracker getDataTracker() { - return dataTracker; - } - - @Override - public boolean init(Literal[] args, int matchedPattern, SkriptParser.ParseResult parseResult, - EntryContainer entryContainer) { - customEventsUsed = true; - - Script script = parseResult.hasTag("local") ? SkriptUtil.getCurrentScript() : null; - - List patterns = entryContainer.getOptional("patterns", List.class, false); - String patternNode = entryContainer.getOptional("pattern", String.class, false); - if (patterns != null && patternNode != null) { - Skript.error("A custom event may not have both a 'patterns' and 'pattern' entries"); - return false; - } else if (patternNode != null) { - patterns = Collections.singletonList(patternNode); - } - - if (patterns == null || patterns.isEmpty()) { - // Always false. Used for the error - return checkHasPatterns(); - } - - int i = 1; - for (String pattern : patterns) { - register(EventSyntaxInfo.create(script, pattern, i++)); - } - - String name = (String) args[0].getSingle(); - if (nameValues.values().stream().anyMatch(name::equalsIgnoreCase)) { - Skript.error("There is already a custom event with that name"); - return false; - } - - whichInfo.forEach(which -> nameValues.put(which, name)); - - // Register the custom events during #init, rather than #preLoad - super.preLoad(); - return true; - } - - @Override - public boolean preLoad() { - SectionNode[] parseNode = getParseNode(); - if (parseNode == null) - return false; - this.parseNode = parseNode[0]; - whichInfo.forEach(which -> parseSectionLoaded.put(which, this.parseNode == null)); - - return true; - } - - @Override - public boolean load() { - EntryContainer entryContainer = getEntryContainer(); - - List> classInfoList = entryContainer.getOptional("event values", List.class, false); - if (classInfoList != null) { - SkriptReflection.replaceEventValues(classInfoList); - whichInfo.forEach(which -> eventValueTypes.put(which, classInfoList)); - } - - if (parseNode != null) { - SkriptLogger.setNode(parseNode); - SyntaxParseEvent.register(parseNode, whichInfo, parserHandlers); - - whichInfo.forEach(which -> parseSectionLoaded.put(which, true)); - } - - SectionNode checkNode = entryContainer.getOptional("check", SectionNode.class, false); - if (checkNode != null) { - SkriptLogger.setNode(checkNode); - - getParser().setCurrentEvent("custom event trigger", EventTriggerEvent.class); - CustomEvent.setLastWhich(whichInfo.get(0)); - List items = SkriptUtil.getItemsFromNode(checkNode); - CustomEvent.setLastWhich(null); - whichInfo.forEach(which -> eventHandlers.put(which, - new Trigger(getParser().getCurrentScript(), "event " + which, new SimpleEvent(), items)) - ); - } - SkriptLogger.setNode(null); - - return true; - } - - public static EventSyntaxInfo lookup(Script script, int matchedPattern) { - return dataTracker.lookup(script, matchedPattern); - } + public static boolean customEventsUsed = false; + + static { + Skript.registerStructure(StructCustomEvent.class, customSyntaxValidator() + .addEntry("pattern", null, true) + .addEntryData(new EventValuesEntryData("event values", null, true) { + @Override + public boolean canCreateWith(String node) { + return super.canCreateWith(node) || node.startsWith(getKey().replace(' ', '-') + getSeparator()); + } + }) + .addSection("check", true) + .build(), + "[:local] [custom] event %string%" + ); + } + + private static final DataTracker dataTracker = new DataTracker<>(); + + static final Map nameValues = new HashMap<>(); + static final Map>> eventValueTypes = new HashMap<>(); + static final Map parserHandlers = new HashMap<>(); + static final Map eventHandlers = new HashMap<>(); + static final Map parseSectionLoaded = new HashMap<>(); + + static { + Skript.registerEvent("custom event", CustomEvent.class, BukkitCustomEvent.class); + Optional> info = Skript.getEvents().stream() + .filter(i -> i.getElementClass() == CustomEvent.class) + .findFirst(); + info.ifPresent(dataTracker::setInfo); + + dataTracker.addManaged(nameValues); + dataTracker.addManaged(eventValueTypes); + dataTracker.addManaged(parserHandlers); + dataTracker.addManaged(eventHandlers); + dataTracker.addManaged(parseSectionLoaded); + } + + private SectionNode parseNode; + + @Override + protected DataTracker getDataTracker() { + return dataTracker; + } + + @Override + public boolean init(Literal[] args, int matchedPattern, SkriptParser.ParseResult parseResult, + EntryContainer entryContainer) { + customEventsUsed = true; + + Script script = parseResult.hasTag("local") ? SkriptUtil.getCurrentScript() : null; + + List patterns = entryContainer.getOptional("patterns", List.class, false); + String patternNode = entryContainer.getOptional("pattern", String.class, false); + if (patterns != null && patternNode != null) { + Skript.error("A custom event may not have both a 'patterns' and 'pattern' entries"); + return false; + } else if (patternNode != null) { + patterns = Collections.singletonList(patternNode); + } + + if (patterns == null || patterns.isEmpty()) { + // Always false. Used for the error + return checkHasPatterns(); + } + + int i = 1; + for (String pattern : patterns) { + register(EventSyntaxInfo.create(script, pattern, i++)); + } + + String name = (String) args[0].getSingle(); + if (nameValues.values().stream().anyMatch(name::equalsIgnoreCase)) { + Skript.error("There is already a custom event with that name"); + return false; + } + + whichInfo.forEach(which -> nameValues.put(which, name)); + + // Register the custom events during #init, rather than #preLoad + super.preLoad(); + return true; + } + + @Override + public boolean preLoad() { + SectionNode[] parseNode = getParseNode(); + if (parseNode == null) + return false; + this.parseNode = parseNode[0]; + whichInfo.forEach(which -> parseSectionLoaded.put(which, this.parseNode == null)); + + return true; + } + + @Override + public boolean load() { + EntryContainer entryContainer = getEntryContainer(); + + List> classInfoList = entryContainer.getOptional("event values", List.class, false); + if (classInfoList != null) { + SkriptReflection.replaceEventValues(classInfoList); + whichInfo.forEach(which -> eventValueTypes.put(which, classInfoList)); + } + + if (parseNode != null) { + SkriptLogger.setNode(parseNode); + SyntaxParseEvent.register(parseNode, whichInfo, parserHandlers); + + whichInfo.forEach(which -> parseSectionLoaded.put(which, true)); + } + + SectionNode checkNode = entryContainer.getOptional("check", SectionNode.class, false); + if (checkNode != null) { + SkriptLogger.setNode(checkNode); + + getParser().setCurrentEvent("custom event trigger", EventTriggerEvent.class); + CustomEvent.setLastWhich(whichInfo.get(0)); + List items = SkriptUtil.getItemsFromNode(checkNode); + CustomEvent.setLastWhich(null); + whichInfo.forEach(which -> eventHandlers.put(which, + new Trigger(getParser().getCurrentScript(), "event " + which, new SimpleEvent(), items)) + ); + } + SkriptLogger.setNode(null); + + return true; + } + + public static EventSyntaxInfo lookup(Script script, int matchedPattern) { + return dataTracker.lookup(script, matchedPattern); + } } diff --git a/src/main/java/org/skriptlang/reflect/syntax/expression/ChangerEntryData.java b/src/main/java/org/skriptlang/reflect/syntax/expression/ChangerEntryData.java index 350a4324..577ce4a0 100644 --- a/src/main/java/org/skriptlang/reflect/syntax/expression/ChangerEntryData.java +++ b/src/main/java/org/skriptlang/reflect/syntax/expression/ChangerEntryData.java @@ -14,45 +14,45 @@ public class ChangerEntryData extends EntryData[]>> { - public ChangerEntryData(String key, boolean optional) { - super(key, null, optional); - } - - @Override - @Nullable - public NonNullPair[]> getValue(Node node) { - String key = node.getKey(); - assert key != null; - key = ScriptLoader.replaceOptions(node.getKey()); - String rawTypes = key.substring(getKey().length()).trim(); - if (rawTypes.isEmpty()) - return new NonNullPair<>((SectionNode) node, new Class[0]); - Class[] acceptedClasses = Arrays.stream(rawTypes.split(",")) - .map(String::trim) - .map(SkriptUtil::getUserClassInfoAndPlural) - .map(meta -> { - ClassInfo classInfo = meta.getFirst(); - boolean plural = meta.getSecond(); - - if (plural) { - return CollectionUtils.arrayType(classInfo.getC()); - } - - return classInfo.getC(); - }) - .toArray(Class[]::new); - return new NonNullPair<>((SectionNode) node, acceptedClasses); - } - - @Override - public boolean canCreateWith(Node node) { - if (!(node instanceof SectionNode)) - return false; - String key = node.getKey(); - if (key == null) - return false; - key = ScriptLoader.replaceOptions(key); - return key.startsWith(getKey()); - } + public ChangerEntryData(String key, boolean optional) { + super(key, null, optional); + } + + @Override + @Nullable + public NonNullPair[]> getValue(Node node) { + String key = node.getKey(); + assert key != null; + key = ScriptLoader.replaceOptions(node.getKey()); + String rawTypes = key.substring(getKey().length()).trim(); + if (rawTypes.isEmpty()) + return new NonNullPair<>((SectionNode) node, new Class[0]); + Class[] acceptedClasses = Arrays.stream(rawTypes.split(",")) + .map(String::trim) + .map(SkriptUtil::getUserClassInfoAndPlural) + .map(meta -> { + ClassInfo classInfo = meta.getFirst(); + boolean plural = meta.getSecond(); + + if (plural) { + return CollectionUtils.arrayType(classInfo.getC()); + } + + return classInfo.getC(); + }) + .toArray(Class[]::new); + return new NonNullPair<>((SectionNode) node, acceptedClasses); + } + + @Override + public boolean canCreateWith(Node node) { + if (!(node instanceof SectionNode)) + return false; + String key = node.getKey(); + if (key == null) + return false; + key = ScriptLoader.replaceOptions(key); + return key.startsWith(getKey()); + } } diff --git a/src/main/java/org/skriptlang/reflect/syntax/expression/ConstantGetEvent.java b/src/main/java/org/skriptlang/reflect/syntax/expression/ConstantGetEvent.java index 6640d165..c76c60e4 100644 --- a/src/main/java/org/skriptlang/reflect/syntax/expression/ConstantGetEvent.java +++ b/src/main/java/org/skriptlang/reflect/syntax/expression/ConstantGetEvent.java @@ -5,18 +5,18 @@ import org.bukkit.event.HandlerList; public class ConstantGetEvent extends ExpressionGetEvent { - private final static HandlerList handlers = new HandlerList(); + private final static HandlerList handlers = new HandlerList(); - public ConstantGetEvent(int matchedPattern, SkriptParser.ParseResult parseResult) { - super(null, new Expression[0], matchedPattern, parseResult); - } + public ConstantGetEvent(int matchedPattern, SkriptParser.ParseResult parseResult) { + super(null, new Expression[0], matchedPattern, parseResult); + } - public static HandlerList getHandlerList() { - return handlers; - } + public static HandlerList getHandlerList() { + return handlers; + } - @Override - public HandlerList getHandlers() { - return handlers; - } + @Override + public HandlerList getHandlers() { + return handlers; + } } diff --git a/src/main/java/org/skriptlang/reflect/syntax/expression/ConstantSyntaxInfo.java b/src/main/java/org/skriptlang/reflect/syntax/expression/ConstantSyntaxInfo.java index bcbed072..50507fff 100644 --- a/src/main/java/org/skriptlang/reflect/syntax/expression/ConstantSyntaxInfo.java +++ b/src/main/java/org/skriptlang/reflect/syntax/expression/ConstantSyntaxInfo.java @@ -8,27 +8,27 @@ public class ConstantSyntaxInfo extends CustomSyntaxStructure.SyntaxData { - private ConstantSyntaxInfo(Script script, String pattern, int matchedPattern) { - super(script, pattern, matchedPattern); - } - - public static ConstantSyntaxInfo create(Script script, String pattern, int matchedPattern) { - return new ConstantSyntaxInfo(script, SkriptMirrorUtil.preprocessPattern(pattern), matchedPattern); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - ConstantSyntaxInfo that = (ConstantSyntaxInfo) o; - return - Objects.equals(getScript(), that.getScript()) && - Objects.equals(getPattern(), that.getPattern()); - } - - @Override - public int hashCode() { - return Objects.hash(getScript(), getPattern()); - } + private ConstantSyntaxInfo(Script script, String pattern, int matchedPattern) { + super(script, pattern, matchedPattern); + } + + public static ConstantSyntaxInfo create(Script script, String pattern, int matchedPattern) { + return new ConstantSyntaxInfo(script, SkriptMirrorUtil.preprocessPattern(pattern), matchedPattern); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ConstantSyntaxInfo that = (ConstantSyntaxInfo) o; + return + Objects.equals(getScript(), that.getScript()) && + Objects.equals(getPattern(), that.getPattern()); + } + + @Override + public int hashCode() { + return Objects.hash(getScript(), getPattern()); + } } diff --git a/src/main/java/org/skriptlang/reflect/syntax/expression/ExpressionChangeEvent.java b/src/main/java/org/skriptlang/reflect/syntax/expression/ExpressionChangeEvent.java index e355e889..381cca1e 100644 --- a/src/main/java/org/skriptlang/reflect/syntax/expression/ExpressionChangeEvent.java +++ b/src/main/java/org/skriptlang/reflect/syntax/expression/ExpressionChangeEvent.java @@ -7,25 +7,25 @@ import org.bukkit.event.HandlerList; public class ExpressionChangeEvent extends CustomSyntaxEvent { - private final static HandlerList handlers = new HandlerList(); - private final Object[] delta; + private final static HandlerList handlers = new HandlerList(); + private final Object[] delta; - public ExpressionChangeEvent(Event event, Expression[] expressions, int matchedPattern, - SkriptParser.ParseResult parseResult, Object[] delta) { - super(event, expressions, matchedPattern, parseResult); - this.delta = delta; - } + public ExpressionChangeEvent(Event event, Expression[] expressions, int matchedPattern, + SkriptParser.ParseResult parseResult, Object[] delta) { + super(event, expressions, matchedPattern, parseResult); + this.delta = delta; + } - public static HandlerList getHandlerList() { - return handlers; - } + public static HandlerList getHandlerList() { + return handlers; + } - public Object[] getDelta() { - return delta; - } + public Object[] getDelta() { + return delta; + } - @Override - public HandlerList getHandlers() { - return handlers; - } + @Override + public HandlerList getHandlers() { + return handlers; + } } diff --git a/src/main/java/org/skriptlang/reflect/syntax/expression/ExpressionGetEvent.java b/src/main/java/org/skriptlang/reflect/syntax/expression/ExpressionGetEvent.java index 5bbacd38..6606c351 100644 --- a/src/main/java/org/skriptlang/reflect/syntax/expression/ExpressionGetEvent.java +++ b/src/main/java/org/skriptlang/reflect/syntax/expression/ExpressionGetEvent.java @@ -7,28 +7,28 @@ import org.bukkit.event.HandlerList; public class ExpressionGetEvent extends CustomSyntaxEvent { - private final static HandlerList handlers = new HandlerList(); - private Object[] output; + private final static HandlerList handlers = new HandlerList(); + private Object[] output; - public ExpressionGetEvent(Event event, Expression[] expressions, int matchedPattern, - SkriptParser.ParseResult parseResult) { - super(event, expressions, matchedPattern, parseResult); - } + public ExpressionGetEvent(Event event, Expression[] expressions, int matchedPattern, + SkriptParser.ParseResult parseResult) { + super(event, expressions, matchedPattern, parseResult); + } - public static HandlerList getHandlerList() { - return handlers; - } + public static HandlerList getHandlerList() { + return handlers; + } - public Object[] getOutput() { - return output; - } + public Object[] getOutput() { + return output; + } - public void setOutput(Object[] output) { - this.output = output; - } + public void setOutput(Object[] output) { + this.output = output; + } - @Override - public HandlerList getHandlers() { - return handlers; - } + @Override + public HandlerList getHandlers() { + return handlers; + } } diff --git a/src/main/java/org/skriptlang/reflect/syntax/expression/ExpressionSyntaxInfo.java b/src/main/java/org/skriptlang/reflect/syntax/expression/ExpressionSyntaxInfo.java index a3e51cb8..3932339c 100644 --- a/src/main/java/org/skriptlang/reflect/syntax/expression/ExpressionSyntaxInfo.java +++ b/src/main/java/org/skriptlang/reflect/syntax/expression/ExpressionSyntaxInfo.java @@ -11,101 +11,101 @@ public class ExpressionSyntaxInfo extends CustomSyntaxStructure.SyntaxData { - private final int[] inheritedSingles; - private final boolean alwaysPlural; - private final boolean adaptArgument; - private final boolean property; - - - private ExpressionSyntaxInfo(Script script, String pattern, int matchedPattern, int[] inheritedSingles, - boolean alwaysPlural, boolean adaptArgument, boolean property) { - super(script, pattern, matchedPattern); - this.inheritedSingles = inheritedSingles; - this.alwaysPlural = alwaysPlural; - this.adaptArgument = adaptArgument; - this.property = property; - } - - public static ExpressionSyntaxInfo create(Script script, String pattern, int matchedPattern, boolean alwaysPlural, - boolean adaptArgument, boolean property) { - StringBuilder newPattern = new StringBuilder(pattern.length()); - List inheritedSingles = new ArrayList<>(); - String[] parts = pattern.split("%"); - - for (int i = 0; i < parts.length; i++) { - String part = parts[i]; - if (i % 2 == 0) { - newPattern.append(part); - } else { - if (part.startsWith("$")) { - part = part.substring(1); - inheritedSingles.add(i / 2); - } - - if (part.startsWith("_")) { - part = part.endsWith("s") ? "javaobject" : "javaobjects"; - } else { - part = SkriptMirrorUtil.processTypes(part); - } - - newPattern.append('%'); - newPattern.append(part); - newPattern.append('%'); - } - } - - return new ExpressionSyntaxInfo( - script, - newPattern.toString(), - matchedPattern, - inheritedSingles.stream() - .mapToInt(i -> i) - .toArray(), - alwaysPlural, - adaptArgument, - property); - } - - public int[] getInheritedSingles() { - return inheritedSingles; - } - - public boolean isAlwaysPlural() { - return alwaysPlural; - } - - public boolean shouldAdaptArgument() { - return adaptArgument; - } - - public boolean isProperty() { - return property; - } - - @Override - public String toString() { - return String.format("%s (singles: %s, plural: %s, adapt: %s, property: %s)", - getPattern(), Arrays.toString(inheritedSingles), alwaysPlural, adaptArgument, property); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - ExpressionSyntaxInfo that = (ExpressionSyntaxInfo) o; - return alwaysPlural == that.alwaysPlural && - adaptArgument == that.adaptArgument && - property == that.property && - Arrays.equals(inheritedSingles, that.inheritedSingles) && - Objects.equals(getScript(), that.getScript()) && - Objects.equals(getPattern(), that.getPattern()); - } - - @Override - public int hashCode() { - int result = Objects.hash(alwaysPlural, adaptArgument, property, getScript(), getPattern()); - result = 31 * result + Arrays.hashCode(inheritedSingles); - return result; - } + private final int[] inheritedSingles; + private final boolean alwaysPlural; + private final boolean adaptArgument; + private final boolean property; + + + private ExpressionSyntaxInfo(Script script, String pattern, int matchedPattern, int[] inheritedSingles, + boolean alwaysPlural, boolean adaptArgument, boolean property) { + super(script, pattern, matchedPattern); + this.inheritedSingles = inheritedSingles; + this.alwaysPlural = alwaysPlural; + this.adaptArgument = adaptArgument; + this.property = property; + } + + public static ExpressionSyntaxInfo create(Script script, String pattern, int matchedPattern, boolean alwaysPlural, + boolean adaptArgument, boolean property) { + StringBuilder newPattern = new StringBuilder(pattern.length()); + List inheritedSingles = new ArrayList<>(); + String[] parts = pattern.split("%"); + + for (int i = 0; i < parts.length; i++) { + String part = parts[i]; + if (i % 2 == 0) { + newPattern.append(part); + } else { + if (part.startsWith("$")) { + part = part.substring(1); + inheritedSingles.add(i / 2); + } + + if (part.startsWith("_")) { + part = part.endsWith("s") ? "javaobject" : "javaobjects"; + } else { + part = SkriptMirrorUtil.processTypes(part); + } + + newPattern.append('%'); + newPattern.append(part); + newPattern.append('%'); + } + } + + return new ExpressionSyntaxInfo( + script, + newPattern.toString(), + matchedPattern, + inheritedSingles.stream() + .mapToInt(i -> i) + .toArray(), + alwaysPlural, + adaptArgument, + property); + } + + public int[] getInheritedSingles() { + return inheritedSingles; + } + + public boolean isAlwaysPlural() { + return alwaysPlural; + } + + public boolean shouldAdaptArgument() { + return adaptArgument; + } + + public boolean isProperty() { + return property; + } + + @Override + public String toString() { + return String.format("%s (singles: %s, plural: %s, adapt: %s, property: %s)", + getPattern(), Arrays.toString(inheritedSingles), alwaysPlural, adaptArgument, property); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ExpressionSyntaxInfo that = (ExpressionSyntaxInfo) o; + return alwaysPlural == that.alwaysPlural && + adaptArgument == that.adaptArgument && + property == that.property && + Arrays.equals(inheritedSingles, that.inheritedSingles) && + Objects.equals(getScript(), that.getScript()) && + Objects.equals(getPattern(), that.getPattern()); + } + + @Override + public int hashCode() { + int result = Objects.hash(alwaysPlural, adaptArgument, property, getScript(), getPattern()); + result = 31 * result + Arrays.hashCode(inheritedSingles); + return result; + } } diff --git a/src/main/java/org/skriptlang/reflect/syntax/expression/elements/CustomExpression.java b/src/main/java/org/skriptlang/reflect/syntax/expression/elements/CustomExpression.java index 50d60fc4..80b07a84 100644 --- a/src/main/java/org/skriptlang/reflect/syntax/expression/elements/CustomExpression.java +++ b/src/main/java/org/skriptlang/reflect/syntax/expression/elements/CustomExpression.java @@ -34,280 +34,280 @@ public class CustomExpression implements Expression { - private ExpressionSyntaxInfo which; - private Expression[] exprs; - private SkriptParser.ParseResult parseResult; - private Object variablesMap; - - private final CustomExpression source; - private Class[] types; - private Class superType; - - @SuppressWarnings({"unchecked", "unused"}) - public CustomExpression() { - this(null, (Class) Object.class); - } - - @SuppressWarnings("unchecked") - @SafeVarargs - private CustomExpression(CustomExpression source, Class... types) { - this.source = source; - - if (source != null) { - this.which = source.which; - this.exprs = source.exprs; - this.parseResult = source.parseResult; - this.variablesMap = source.variablesMap; - } - - this.types = types; - this.superType = (Class) Utils.getSuperType(types); - } - - @Override - public T getSingle(Event e) { - T[] all = getAll(e); - return all.length == 0 ? null : all[0]; - } - - @Override - public T[] getArray(Event e) { - return getAll(e); - } - - @Override - public T[] getAll(Event e) { - Trigger getter = StructCustomExpression.expressionHandlers.get(which); - - if (getter == null) { - Skript.error( - String.format("The custom expression '%s' no longer has a get handler.", - which.getPattern()) - ); - return JavaUtil.newArray(superType, 0); - } - - if (which.isProperty()) { - return getByProperty(e, getter); - } - - return getByStandard(e, getter); - } - - private T[] getByStandard(Event e, Trigger getter) { - ExpressionGetEvent expressionEvent = new ExpressionGetEvent(e, exprs, which.getMatchedPattern(), parseResult); - SkriptReflection.putLocals(variablesMap, expressionEvent); - getter.execute(expressionEvent); - if (expressionEvent.getOutput() == null) { - Skript.error( - String.format("The get handler for '%s' did not return.", which.getPattern()) - ); - return JavaUtil.newArray(superType, 0); - } - - return Converters.convert(expressionEvent.getOutput(), types, superType); - } - - private T[] getByProperty(Event e, Trigger getter) { - List output = new ArrayList<>(); - for (Object o : exprs[0].getArray(e)) { - Expression[] localExprs = Arrays.copyOf(exprs, exprs.length); - localExprs[0] = new SimpleLiteral<>(o, false); - - ExpressionGetEvent expressionEvent = - new ExpressionGetEvent(e, localExprs, which.getMatchedPattern(), parseResult); - SkriptReflection.putLocals(variablesMap, expressionEvent); - getter.execute(expressionEvent); - - Object[] exprOutput = expressionEvent.getOutput(); - if (exprOutput == null) { - Skript.error( - String.format("The get handler for '%s' did not return for the value %s", - which.getPattern(), Classes.toString(o)) - ); - return JavaUtil.newArray(superType, 0); - } - - if (!which.isAlwaysPlural() && exprOutput.length > 1) { - Skript.error( - String.format("The get handler for '%s' returned more than one value.", which.getPattern()) - ); - return JavaUtil.newArray(superType, 0); - } - - T[] converted = Converters.convert(exprOutput, superType); - output.addAll(Arrays.asList(converted)); - } - - return output.toArray(JavaUtil.newArray(superType, 0)); - } - - @Override - public boolean isSingle() { - return !which.isAlwaysPlural() && - Arrays.stream(which.getInheritedSingles()) - .mapToObj(i -> exprs[i]) - .filter(Objects::nonNull) - .allMatch(Expression::isSingle); - } - - @Override - public boolean check(Event e, Checker c, boolean negated) { - return SimpleExpression.check(getAll(e), c, negated, getAnd()); - } - - @Override - public boolean check(Event e, Checker c) { - return SimpleExpression.check(getAll(e), c, false, getAnd()); - } - - @Override - public Expression getConvertedExpression(Class[] to) { - if (StructCustomExpression.returnTypes.containsKey(which) - && !Converters.converterExists(StructCustomExpression.returnTypes.get(which), to)) { - return null; - } - - return new CustomExpression<>(this, to); - } - - @Override - public Class getReturnType() { - return superType; - } - - @Override - public boolean getAnd() { - return true; - } - - @Override - public boolean setTime(int time) { - return false; - } - - @Override - public int getTime() { - return 0; - } - - @Override - public boolean isDefault() { - return false; - } - - @Override - public Iterator iterator(Event e) { - return new ArrayIterator<>(getAll(e)); - } - - @Override - public boolean isLoopOf(String s) { - return s.equalsIgnoreCase(StructCustomExpression.loopOfs.get(which)); - } - - @Override - public Expression getSource() { - return source == null ? this : source; - } - - @Override - public Expression simplify() { - return this; - } - - @Override - public String toString(Event e, boolean debug) { - return which.getPattern(); - } - - @Override - public String toString() { - return toString(null, false); - } - - @Override - public Class[] acceptChange(Changer.ChangeMode mode) { - if (StructCustomExpression.hasChanger.containsKey(which) - && StructCustomExpression.hasChanger.get(which).contains(mode)) { - return StructCustomExpression.changerTypes - .getOrDefault(which, Collections.emptyMap()) - .getOrDefault(mode, new Class[]{Object[].class}); - } - - return null; - } - - @Override - public void change(Event e, Object[] delta, Changer.ChangeMode mode) { - Trigger changer = StructCustomExpression.changerHandlers.getOrDefault(which, Collections.emptyMap()).get(mode); - - if (changer == null) { - Skript.error( - String.format("The custom expression '%s' no longer has a %s handler.", - which.getPattern(), mode.name()) - ); - } else { - ExpressionChangeEvent changeEvent = - new ExpressionChangeEvent(e, exprs, which.getMatchedPattern(), parseResult, delta); - SkriptReflection.putLocals(SkriptReflection.copyLocals(variablesMap), changeEvent); - changer.execute(changeEvent); - } - } - - @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, - SkriptParser.ParseResult parseResult) { - which = StructCustomExpression.lookup(SkriptUtil.getCurrentScript(), matchedPattern); - - if (which == null) { - return false; - } - - if (which.shouldAdaptArgument()) { - Expression lastExpression = exprs[exprs.length - 1]; - System.arraycopy(exprs, 0, exprs, 1, exprs.length - 1); - exprs[0] = lastExpression; - } - - this.exprs = Arrays.stream(exprs) - .map(SkriptUtil::defendExpression) - .toArray(Expression[]::new); - this.parseResult = parseResult; - - if (!SkriptUtil.canInitSafely(this.exprs)) { - return false; - } - - Class returnType = StructCustomExpression.returnTypes.get(which); - - if (returnType != null) { - this.types = new Class[]{returnType}; - this.superType = (Class) returnType; - } - - List> suppliers = StructCustomExpression.usableSuppliers.get(which); - if (suppliers != null && suppliers.size() != 0 && suppliers.stream().noneMatch(Supplier::get)) - return false; - - Boolean bool = StructCustomExpression.parseSectionLoaded.get(which); - if (bool != null && !bool) { - Skript.error("You can't use custom expressions with parse sections before they're loaded."); - return false; - } - - Trigger parseHandler = StructCustomExpression.parserHandlers.get(which); - - if (parseHandler != null) { - SyntaxParseEvent event = - new SyntaxParseEvent(this.exprs, matchedPattern, parseResult, getParser().getCurrentEvents()); - - TriggerItem.walk(parseHandler, event); - variablesMap = SkriptReflection.removeLocals(event); - - return event.isMarkedContinue(); - } - - return true; - } + private ExpressionSyntaxInfo which; + private Expression[] exprs; + private SkriptParser.ParseResult parseResult; + private Object variablesMap; + + private final CustomExpression source; + private Class[] types; + private Class superType; + + @SuppressWarnings({"unchecked", "unused"}) + public CustomExpression() { + this(null, (Class) Object.class); + } + + @SuppressWarnings("unchecked") + @SafeVarargs + private CustomExpression(CustomExpression source, Class... types) { + this.source = source; + + if (source != null) { + this.which = source.which; + this.exprs = source.exprs; + this.parseResult = source.parseResult; + this.variablesMap = source.variablesMap; + } + + this.types = types; + this.superType = (Class) Utils.getSuperType(types); + } + + @Override + public T getSingle(Event e) { + T[] all = getAll(e); + return all.length == 0 ? null : all[0]; + } + + @Override + public T[] getArray(Event e) { + return getAll(e); + } + + @Override + public T[] getAll(Event e) { + Trigger getter = StructCustomExpression.expressionHandlers.get(which); + + if (getter == null) { + Skript.error( + String.format("The custom expression '%s' no longer has a get handler.", + which.getPattern()) + ); + return JavaUtil.newArray(superType, 0); + } + + if (which.isProperty()) { + return getByProperty(e, getter); + } + + return getByStandard(e, getter); + } + + private T[] getByStandard(Event e, Trigger getter) { + ExpressionGetEvent expressionEvent = new ExpressionGetEvent(e, exprs, which.getMatchedPattern(), parseResult); + SkriptReflection.putLocals(variablesMap, expressionEvent); + getter.execute(expressionEvent); + if (expressionEvent.getOutput() == null) { + Skript.error( + String.format("The get handler for '%s' did not return.", which.getPattern()) + ); + return JavaUtil.newArray(superType, 0); + } + + return Converters.convert(expressionEvent.getOutput(), types, superType); + } + + private T[] getByProperty(Event e, Trigger getter) { + List output = new ArrayList<>(); + for (Object o : exprs[0].getArray(e)) { + Expression[] localExprs = Arrays.copyOf(exprs, exprs.length); + localExprs[0] = new SimpleLiteral<>(o, false); + + ExpressionGetEvent expressionEvent = + new ExpressionGetEvent(e, localExprs, which.getMatchedPattern(), parseResult); + SkriptReflection.putLocals(variablesMap, expressionEvent); + getter.execute(expressionEvent); + + Object[] exprOutput = expressionEvent.getOutput(); + if (exprOutput == null) { + Skript.error( + String.format("The get handler for '%s' did not return for the value %s", + which.getPattern(), Classes.toString(o)) + ); + return JavaUtil.newArray(superType, 0); + } + + if (!which.isAlwaysPlural() && exprOutput.length > 1) { + Skript.error( + String.format("The get handler for '%s' returned more than one value.", which.getPattern()) + ); + return JavaUtil.newArray(superType, 0); + } + + T[] converted = Converters.convert(exprOutput, superType); + output.addAll(Arrays.asList(converted)); + } + + return output.toArray(JavaUtil.newArray(superType, 0)); + } + + @Override + public boolean isSingle() { + return !which.isAlwaysPlural() && + Arrays.stream(which.getInheritedSingles()) + .mapToObj(i -> exprs[i]) + .filter(Objects::nonNull) + .allMatch(Expression::isSingle); + } + + @Override + public boolean check(Event e, Checker c, boolean negated) { + return SimpleExpression.check(getAll(e), c, negated, getAnd()); + } + + @Override + public boolean check(Event e, Checker c) { + return SimpleExpression.check(getAll(e), c, false, getAnd()); + } + + @Override + public Expression getConvertedExpression(Class[] to) { + if (StructCustomExpression.returnTypes.containsKey(which) + && !Converters.converterExists(StructCustomExpression.returnTypes.get(which), to)) { + return null; + } + + return new CustomExpression<>(this, to); + } + + @Override + public Class getReturnType() { + return superType; + } + + @Override + public boolean getAnd() { + return true; + } + + @Override + public boolean setTime(int time) { + return false; + } + + @Override + public int getTime() { + return 0; + } + + @Override + public boolean isDefault() { + return false; + } + + @Override + public Iterator iterator(Event e) { + return new ArrayIterator<>(getAll(e)); + } + + @Override + public boolean isLoopOf(String s) { + return s.equalsIgnoreCase(StructCustomExpression.loopOfs.get(which)); + } + + @Override + public Expression getSource() { + return source == null ? this : source; + } + + @Override + public Expression simplify() { + return this; + } + + @Override + public String toString(Event e, boolean debug) { + return which.getPattern(); + } + + @Override + public String toString() { + return toString(null, false); + } + + @Override + public Class[] acceptChange(Changer.ChangeMode mode) { + if (StructCustomExpression.hasChanger.containsKey(which) + && StructCustomExpression.hasChanger.get(which).contains(mode)) { + return StructCustomExpression.changerTypes + .getOrDefault(which, Collections.emptyMap()) + .getOrDefault(mode, new Class[]{Object[].class}); + } + + return null; + } + + @Override + public void change(Event e, Object[] delta, Changer.ChangeMode mode) { + Trigger changer = StructCustomExpression.changerHandlers.getOrDefault(which, Collections.emptyMap()).get(mode); + + if (changer == null) { + Skript.error( + String.format("The custom expression '%s' no longer has a %s handler.", + which.getPattern(), mode.name()) + ); + } else { + ExpressionChangeEvent changeEvent = + new ExpressionChangeEvent(e, exprs, which.getMatchedPattern(), parseResult, delta); + SkriptReflection.putLocals(SkriptReflection.copyLocals(variablesMap), changeEvent); + changer.execute(changeEvent); + } + } + + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, + SkriptParser.ParseResult parseResult) { + which = StructCustomExpression.lookup(SkriptUtil.getCurrentScript(), matchedPattern); + + if (which == null) { + return false; + } + + if (which.shouldAdaptArgument()) { + Expression lastExpression = exprs[exprs.length - 1]; + System.arraycopy(exprs, 0, exprs, 1, exprs.length - 1); + exprs[0] = lastExpression; + } + + this.exprs = Arrays.stream(exprs) + .map(SkriptUtil::defendExpression) + .toArray(Expression[]::new); + this.parseResult = parseResult; + + if (!SkriptUtil.canInitSafely(this.exprs)) { + return false; + } + + Class returnType = StructCustomExpression.returnTypes.get(which); + + if (returnType != null) { + this.types = new Class[]{returnType}; + this.superType = (Class) returnType; + } + + List> suppliers = StructCustomExpression.usableSuppliers.get(which); + if (suppliers != null && suppliers.size() != 0 && suppliers.stream().noneMatch(Supplier::get)) + return false; + + Boolean bool = StructCustomExpression.parseSectionLoaded.get(which); + if (bool != null && !bool) { + Skript.error("You can't use custom expressions with parse sections before they're loaded."); + return false; + } + + Trigger parseHandler = StructCustomExpression.parserHandlers.get(which); + + if (parseHandler != null) { + SyntaxParseEvent event = + new SyntaxParseEvent(this.exprs, matchedPattern, parseResult, getParser().getCurrentEvents()); + + TriggerItem.walk(parseHandler, event); + variablesMap = SkriptReflection.removeLocals(event); + + return event.isMarkedContinue(); + } + + return true; + } } diff --git a/src/main/java/org/skriptlang/reflect/syntax/expression/elements/EffReturn.java b/src/main/java/org/skriptlang/reflect/syntax/expression/elements/EffReturn.java index a941d689..78b74d85 100644 --- a/src/main/java/org/skriptlang/reflect/syntax/expression/elements/EffReturn.java +++ b/src/main/java/org/skriptlang/reflect/syntax/expression/elements/EffReturn.java @@ -23,99 +23,99 @@ public class EffReturn extends Effect { - static { - Skript.registerEffect(EffReturn.class, "return [%-objects%]"); - } - - private Expression objects; - - @SuppressWarnings("unchecked") - @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { - Expression expr = SkriptUtil.defendExpression(exprs[0]); - if (!SkriptUtil.canInitSafely(expr)) { - Skript.error("Can't understand this expression: " + expr); - return false; - } - - boolean isContinuable = CollectionUtils.containsAnySuperclass(new Class[]{Continuable.class}, getParser().getCurrentEvents()); - - if (!getParser().isCurrentEvent(ExpressionGetEvent.class, ConstantGetEvent.class, SectionEvent.class) - && !isContinuable) { - Skript.error("The return effect can only be used in functions, custom expressions, sections, custom syntax parse sections and custom conditions"); - return false; - } - - if (isContinuable) { - expr = expr.getConvertedExpression(Boolean.class); - if (expr == null || !expr.isSingle()) { - Skript.error(exprs[0] + " is not a single boolean value"); - return false; - } - } - - Structure structure = getParser().getCurrentStructure(); - if (expr != null && structure instanceof StructCustomExpression) { - StructCustomExpression customExpressionSection = (StructCustomExpression) structure; - ExpressionSyntaxInfo which = customExpressionSection.getFirstWhich(); - Class returnType = StructCustomExpression.returnTypes.get(which); - if (returnType != null) { - Expression newExpr = expr.getConvertedExpression(returnType); - if (newExpr == null) { - Skript.error(expr + " is not " + Classes.getSuperClassInfo(returnType).getName().withIndefiniteArticle()); - return false; - } - expr = newExpr; - } - } - - if (!isDelayed.isFalse()) { - Skript.error("Return may not be used if the code before it contains any delays", ErrorQuality.SEMANTIC_ERROR); - return false; - } - - objects = expr; - - return true; - } - - @Override - protected TriggerItem walk(Event e) { - if (e instanceof SectionEvent) { - ((SectionEvent) e).setOutput(objects == null ? new Object[0] : objects.getArray(e)); - } else if (e instanceof ExpressionGetEvent) { - ((ExpressionGetEvent) e).setOutput(objects == null ? new Object[0] : objects.getArray(e)); - } else { - // objects is always a single boolean expression, see init - // Doesn't require casting, and deals with null - boolean b = Boolean.TRUE.equals(objects.getSingle(e)); - ((Continuable) e).setContinue(b); - } - - TriggerSection parent = getParent(); - while (parent != null) { - if (parent instanceof SecLoop) { - ((SecLoop) parent).exit(e); - } else if (parent instanceof SecWhile) { - ((SecWhile) parent).exit(e); - } - parent = parent.getParent(); - } - - return null; - } - - @Override - protected void execute(Event e) { - throw new UnsupportedOperationException(); - } - - @Override - public String toString(Event e, boolean debug) { - if (objects == null) { - return "return"; - } - return "return " + objects.toString(e, debug); - } + static { + Skript.registerEffect(EffReturn.class, "return [%-objects%]"); + } + + private Expression objects; + + @SuppressWarnings("unchecked") + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + Expression expr = SkriptUtil.defendExpression(exprs[0]); + if (!SkriptUtil.canInitSafely(expr)) { + Skript.error("Can't understand this expression: " + expr); + return false; + } + + boolean isContinuable = CollectionUtils.containsAnySuperclass(new Class[]{Continuable.class}, getParser().getCurrentEvents()); + + if (!getParser().isCurrentEvent(ExpressionGetEvent.class, ConstantGetEvent.class, SectionEvent.class) + && !isContinuable) { + Skript.error("The return effect can only be used in functions, custom expressions, sections, custom syntax parse sections and custom conditions"); + return false; + } + + if (isContinuable) { + expr = expr.getConvertedExpression(Boolean.class); + if (expr == null || !expr.isSingle()) { + Skript.error(exprs[0] + " is not a single boolean value"); + return false; + } + } + + Structure structure = getParser().getCurrentStructure(); + if (expr != null && structure instanceof StructCustomExpression) { + StructCustomExpression customExpressionSection = (StructCustomExpression) structure; + ExpressionSyntaxInfo which = customExpressionSection.getFirstWhich(); + Class returnType = StructCustomExpression.returnTypes.get(which); + if (returnType != null) { + Expression newExpr = expr.getConvertedExpression(returnType); + if (newExpr == null) { + Skript.error(expr + " is not " + Classes.getSuperClassInfo(returnType).getName().withIndefiniteArticle()); + return false; + } + expr = newExpr; + } + } + + if (!isDelayed.isFalse()) { + Skript.error("Return may not be used if the code before it contains any delays", ErrorQuality.SEMANTIC_ERROR); + return false; + } + + objects = expr; + + return true; + } + + @Override + protected TriggerItem walk(Event e) { + if (e instanceof SectionEvent) { + ((SectionEvent) e).setOutput(objects == null ? new Object[0] : objects.getArray(e)); + } else if (e instanceof ExpressionGetEvent) { + ((ExpressionGetEvent) e).setOutput(objects == null ? new Object[0] : objects.getArray(e)); + } else { + // objects is always a single boolean expression, see init + // Doesn't require casting, and deals with null + boolean b = Boolean.TRUE.equals(objects.getSingle(e)); + ((Continuable) e).setContinue(b); + } + + TriggerSection parent = getParent(); + while (parent != null) { + if (parent instanceof SecLoop) { + ((SecLoop) parent).exit(e); + } else if (parent instanceof SecWhile) { + ((SecWhile) parent).exit(e); + } + parent = parent.getParent(); + } + + return null; + } + + @Override + protected void execute(Event e) { + throw new UnsupportedOperationException(); + } + + @Override + public String toString(Event e, boolean debug) { + if (objects == null) { + return "return"; + } + return "return " + objects.toString(e, debug); + } } diff --git a/src/main/java/org/skriptlang/reflect/syntax/expression/elements/ExprChangeValue.java b/src/main/java/org/skriptlang/reflect/syntax/expression/elements/ExprChangeValue.java index 7685f7cd..d42fb4e5 100644 --- a/src/main/java/org/skriptlang/reflect/syntax/expression/elements/ExprChangeValue.java +++ b/src/main/java/org/skriptlang/reflect/syntax/expression/elements/ExprChangeValue.java @@ -19,157 +19,157 @@ import java.util.Iterator; public class ExprChangeValue implements Expression { - static { - //noinspection unchecked - Skript.registerExpression(ExprChangeValue.class, Object.class, ExpressionType.SIMPLE, - "[the] change value[1:s]"); - } - - private int index; - private boolean plural; - - private final ExprChangeValue source; - private final Class[] types; - private final Class superType; - - @SuppressWarnings("unchecked") - public ExprChangeValue() { - this(null, ((Class) Object.class)); - } - - @SuppressWarnings("unchecked") - @SafeVarargs - private ExprChangeValue(ExprChangeValue source, Class... types) { - if (source != null) { - index = source.index; - plural = source.plural; - } - - this.source = source; - this.types = types; - this.superType = (Class) Utils.getSuperType(types); - } - - @Override - public T getSingle(Event e) { - T[] all = getAll(e); - if (all.length == 0) { - return null; - } - return all[0]; - } - - @Override - public T[] getArray(Event e) { - return getAll(e); - } - - @Override - public T[] getAll(Event e) { - Object[] delta = ((ExpressionChangeEvent) e).getDelta(); - if (delta == null) { - return JavaUtil.newArray(superType, 0); - } - return Converters.convert(delta, types, superType); - } - - @Override - public boolean isSingle() { - return !plural; - } - - @Override - public boolean check(Event e, Checker c, boolean negated) { - return SimpleExpression.check(getAll(e), c, negated, getAnd()); - } - - @Override - public boolean check(Event e, Checker c) { - return SimpleExpression.check(getAll(e), c, false, getAnd()); - } - - @Override - public Expression getConvertedExpression(Class[] to) { - return new ExprChangeValue<>(this, to); - } - - @Override - public Class getReturnType() { - return superType; - } - - @Override - public boolean getAnd() { - return true; - } - - @Override - public boolean setTime(int time) { - return false; - } - - @Override - public int getTime() { - return 0; - } - - @Override - public boolean isDefault() { - return false; - } - - @Override - public Iterator iterator(Event e) { - return new ArrayIterator<>(getAll(e)); - } - - @Override - public boolean isLoopOf(String s) { - return s.equalsIgnoreCase("expression"); - } - - @Override - public Expression getSource() { - return source == null ? this : source; - } - - @Override - public Expression simplify() { - return this; - } - - @Override - public Class[] acceptChange(Changer.ChangeMode mode) { - return null; - } - - @Override - public void change(Event e, Object[] delta, Changer.ChangeMode mode) { - throw new UnsupportedOperationException(); - } - - - @Override - public String toString(Event e, boolean debug) { - return "expression " + index; - } - - @Override - public String toString() { - return toString(null, false); - } - - @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, - SkriptParser.ParseResult parseResult) { - if (!getParser().isCurrentEvent(ExpressionChangeEvent.class)) { - Skript.error("The change value may only be used in a change handlers.", - ErrorQuality.SEMANTIC_ERROR); - return false; - } - - plural = parseResult.mark == 1; - - return true; - } + static { + //noinspection unchecked + Skript.registerExpression(ExprChangeValue.class, Object.class, ExpressionType.SIMPLE, + "[the] change value[1:s]"); + } + + private int index; + private boolean plural; + + private final ExprChangeValue source; + private final Class[] types; + private final Class superType; + + @SuppressWarnings("unchecked") + public ExprChangeValue() { + this(null, ((Class) Object.class)); + } + + @SuppressWarnings("unchecked") + @SafeVarargs + private ExprChangeValue(ExprChangeValue source, Class... types) { + if (source != null) { + index = source.index; + plural = source.plural; + } + + this.source = source; + this.types = types; + this.superType = (Class) Utils.getSuperType(types); + } + + @Override + public T getSingle(Event e) { + T[] all = getAll(e); + if (all.length == 0) { + return null; + } + return all[0]; + } + + @Override + public T[] getArray(Event e) { + return getAll(e); + } + + @Override + public T[] getAll(Event e) { + Object[] delta = ((ExpressionChangeEvent) e).getDelta(); + if (delta == null) { + return JavaUtil.newArray(superType, 0); + } + return Converters.convert(delta, types, superType); + } + + @Override + public boolean isSingle() { + return !plural; + } + + @Override + public boolean check(Event e, Checker c, boolean negated) { + return SimpleExpression.check(getAll(e), c, negated, getAnd()); + } + + @Override + public boolean check(Event e, Checker c) { + return SimpleExpression.check(getAll(e), c, false, getAnd()); + } + + @Override + public Expression getConvertedExpression(Class[] to) { + return new ExprChangeValue<>(this, to); + } + + @Override + public Class getReturnType() { + return superType; + } + + @Override + public boolean getAnd() { + return true; + } + + @Override + public boolean setTime(int time) { + return false; + } + + @Override + public int getTime() { + return 0; + } + + @Override + public boolean isDefault() { + return false; + } + + @Override + public Iterator iterator(Event e) { + return new ArrayIterator<>(getAll(e)); + } + + @Override + public boolean isLoopOf(String s) { + return s.equalsIgnoreCase("expression"); + } + + @Override + public Expression getSource() { + return source == null ? this : source; + } + + @Override + public Expression simplify() { + return this; + } + + @Override + public Class[] acceptChange(Changer.ChangeMode mode) { + return null; + } + + @Override + public void change(Event e, Object[] delta, Changer.ChangeMode mode) { + throw new UnsupportedOperationException(); + } + + + @Override + public String toString(Event e, boolean debug) { + return "expression " + index; + } + + @Override + public String toString() { + return toString(null, false); + } + + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, + SkriptParser.ParseResult parseResult) { + if (!getParser().isCurrentEvent(ExpressionChangeEvent.class)) { + Skript.error("The change value may only be used in a change handlers.", + ErrorQuality.SEMANTIC_ERROR); + return false; + } + + plural = parseResult.mark == 1; + + return true; + } } diff --git a/src/main/java/org/skriptlang/reflect/syntax/expression/elements/StructCustomConstant.java b/src/main/java/org/skriptlang/reflect/syntax/expression/elements/StructCustomConstant.java index 09ee7783..3aeb2519 100644 --- a/src/main/java/org/skriptlang/reflect/syntax/expression/elements/StructCustomConstant.java +++ b/src/main/java/org/skriptlang/reflect/syntax/expression/elements/StructCustomConstant.java @@ -27,56 +27,56 @@ public class StructCustomConstant extends CustomSyntaxStructure { - static { - Skript.registerStructure(StructCustomConstant.class, EntryValidator.builder() - .addSection("get", false) - // We only have one entry, so we know it's 'get' - .missingRequiredEntryMessage(key -> "Computed options don't work without a get section") - .build(), - "option <.+>" - ); - } + static { + Skript.registerStructure(StructCustomConstant.class, EntryValidator.builder() + .addSection("get", false) + // We only have one entry, so we know it's 'get' + .missingRequiredEntryMessage(key -> "Computed options don't work without a get section") + .build(), + "option <.+>" + ); + } - private static final DataTracker dataTracker = new DataTracker<>(); + private static final DataTracker dataTracker = new DataTracker<>(); - static { - // noinspection unchecked - Skript.registerExpression(CustomExpression.class, Object.class, ExpressionType.SIMPLE); - Optional> info = StreamSupport.stream( - Spliterators.spliteratorUnknownSize(Skript.getExpressions(), Spliterator.ORDERED), false) - .filter(i -> i.getElementClass() == CustomExpression.class) - .findFirst(); - info.ifPresent(dataTracker::setInfo); - } + static { + // noinspection unchecked + Skript.registerExpression(CustomExpression.class, Object.class, ExpressionType.SIMPLE); + Optional> info = StreamSupport.stream( + Spliterators.spliteratorUnknownSize(Skript.getExpressions(), Spliterator.ORDERED), false) + .filter(i -> i.getElementClass() == CustomExpression.class) + .findFirst(); + info.ifPresent(dataTracker::setInfo); + } - @Override - protected DataTracker getDataTracker() { - return dataTracker; - } + @Override + protected DataTracker getDataTracker() { + return dataTracker; + } - @Override - public boolean init(Literal[] args, int matchedPattern, SkriptParser.ParseResult parseResult, EntryContainer entryContainer) { - String option = parseResult.regexes.get(0).group(); + @Override + public boolean init(Literal[] args, int matchedPattern, SkriptParser.ParseResult parseResult, EntryContainer entryContainer) { + String option = parseResult.regexes.get(0).group(); - SectionNode sectionNode = entryContainer.get("get", SectionNode.class, false); - getParser().setCurrentEvent("custom constant getter", ConstantGetEvent.class); - List items = SkriptUtil.getItemsFromNode(sectionNode); - Trigger getter = new Trigger(getParser().getCurrentScript(), "get @{" + option + "}", new SimpleEvent(), items); + SectionNode sectionNode = entryContainer.get("get", SectionNode.class, false); + getParser().setCurrentEvent("custom constant getter", ConstantGetEvent.class); + List items = SkriptUtil.getItemsFromNode(sectionNode); + Trigger getter = new Trigger(getParser().getCurrentScript(), "get @{" + option + "}", new SimpleEvent(), items); - computeOption(option, getter); - return true; - } + computeOption(option, getter); + return true; + } - private static void computeOption(String option, Trigger getter) { - ConstantGetEvent constantEvent = new ConstantGetEvent(0, null); - getter.execute(constantEvent); - // Get result as a string - String result = StringUtils.join(constantEvent.getOutput()); + private static void computeOption(String option, Trigger getter) { + ConstantGetEvent constantEvent = new ConstantGetEvent(0, null); + getter.execute(constantEvent); + // Get result as a string + String result = StringUtils.join(constantEvent.getOutput()); - // Get options of current script, and add it to that - SkriptReflection.getOptions(ParserInstance.get().getCurrentScript()) - .put(option, result); - } + // Get options of current script, and add it to that + SkriptReflection.getOptions(ParserInstance.get().getCurrentScript()) + .put(option, result); + } } diff --git a/src/main/java/org/skriptlang/reflect/syntax/expression/elements/StructCustomExpression.java b/src/main/java/org/skriptlang/reflect/syntax/expression/elements/StructCustomExpression.java index 7b15df1f..bc26f5a2 100644 --- a/src/main/java/org/skriptlang/reflect/syntax/expression/elements/StructCustomExpression.java +++ b/src/main/java/org/skriptlang/reflect/syntax/expression/elements/StructCustomExpression.java @@ -44,225 +44,225 @@ public class StructCustomExpression extends CustomSyntaxStructure { - public static boolean customExpressionsUsed = false; - - static { - String[] syntax = { - "[:local] [plural:(plural|non[-| ]single)] expression <.+>", - "[:local] [plural:(plural|non[-| ]single)] expression", - "[:local] [plural:(plural|non[-| ]single)] %*classinfos% property <.+>" - }; - EntryValidator.EntryValidatorBuilder builder = customSyntaxValidator() - .addEntryData(new KeyValueEntryData>("return type", null, true) { - @Override - @Nullable - protected Class getValue(String value) { - Class returnType = Classes.getClassFromUserInput(value); - if (returnType == null) - Skript.error("The given return type doesn't exist"); - return returnType; - } - }) - .addEntry("loop of", null, true) - .addSection("get", false); - Arrays.stream(ChangeMode.values()) - .sorted((mode1, mode2) -> { - long words1 = StringUtils.count(mode1.toString(), '_'); - long words2 = StringUtils.count(mode2.toString(), '_'); - return Long.compare(words2, words1); - }) - .map(mode -> mode.toString().replace('_', ' ').toLowerCase(Locale.ENGLISH)) - .forEach(name -> builder.addEntryData(new ChangerEntryData(name, true))); - Skript.registerStructure(StructCustomExpression.class, builder.build(), syntax); - } - - private static final DataTracker dataTracker = new DataTracker<>(); - - static final Map> returnTypes = new HashMap<>(); - static final Map expressionHandlers = new HashMap<>(); - static final Map parserHandlers = new HashMap<>(); - static final Map> hasChanger = new HashMap<>(); - static final Map> changerHandlers = new HashMap<>(); - static final Map[]>> changerTypes = new HashMap<>(); - static final Map loopOfs = new HashMap<>(); - static final Map>> usableSuppliers = new HashMap<>(); - static final Map parseSectionLoaded = new HashMap<>(); - - static { - // noinspection unchecked - Skript.registerExpression(CustomExpression.class, Object.class, ExpressionType.PATTERN_MATCHES_EVERYTHING); - Optional> info = StreamSupport.stream( - Spliterators.spliteratorUnknownSize(Skript.getExpressions(), Spliterator.ORDERED), false) - .filter(i -> i.getElementClass() == CustomExpression.class) - .findFirst(); - info.ifPresent(dataTracker::setInfo); - - dataTracker.addManaged(returnTypes); - dataTracker.addManaged(expressionHandlers); - dataTracker.addManaged(hasChanger); - dataTracker.addManaged(changerHandlers); - dataTracker.addManaged(changerTypes); - dataTracker.addManaged(parserHandlers); - dataTracker.addManaged(loopOfs); - dataTracker.addManaged(usableSuppliers); - dataTracker.addManaged(parseSectionLoaded); - } - - private final Map changerNodes = new HashMap<>(); - private SectionNode parseNode; - - @Override - protected DataTracker getDataTracker() { - return dataTracker; - } - - @SuppressWarnings("unchecked") - @Override - public boolean init(Literal[] args, int matchedPattern, SkriptParser.ParseResult parseResult, - EntryContainer entryContainer) { - customExpressionsUsed = true; - - List patterns = entryContainer.getOptional("patterns", List.class, false); - Script script = parseResult.hasTag("local") ? SkriptUtil.getCurrentScript() : null; - boolean alwaysPlural = parseResult.hasTag("plural"); - - if (matchedPattern != 1 && patterns != null) { - Skript.error("A custom expression with an inline pattern cannot have a 'patterns' entry too"); - return false; - } - - switch (matchedPattern) { - case 0: // expression with an inline pattern - String pattern = parseResult.regexes.get(0).group(); - register(ExpressionSyntaxInfo.create(script, pattern, 1, alwaysPlural, false, false)); - break; - case 1: // expression with a 'patterns' entry - if (patterns == null) { - Skript.error("A custom expression without an inline pattern must have a 'patterns' entry"); - return false; - } - - int i = 1; - for (String p : patterns) { - register(ExpressionSyntaxInfo.create(script, p, i++, alwaysPlural, false, false)); - } - break; - case 2: // property expression - String property = parseResult.regexes.get(0).group(); - String type = Arrays.stream(((Literal>) args[0]).getArray()) - .map(ClassInfo::getCodeName) - .map(codeName -> { - boolean isPlural = Utils.getEnglishPlural(codeName).getSecond(); - - if (!isPlural) { - return Utils.toEnglishPlural(codeName); - } - - return codeName; - }) - .collect(Collectors.joining("/")); - - if (!alwaysPlural) { - type = "$" + type; - } - - register( - ExpressionSyntaxInfo.create(script, "[the] " + property + " of %" + type + "%", 1, alwaysPlural, true, true)); - register(ExpressionSyntaxInfo.create(script, "%" + type + "%'[s] " + property, 1, alwaysPlural, false, true)); - break; - } - - return true; - } - - @Override - public boolean preLoad() { - super.preLoad(); - EntryContainer entryContainer = getEntryContainer(); - - SectionNode[] parseNode = getParseNode(); - if (parseNode == null) - return false; - this.parseNode = parseNode[0]; - whichInfo.forEach(which -> parseSectionLoaded.put(which, this.parseNode == null)); - - Class returnType = entryContainer.getOptional("return type", Class.class, false); - if (returnType != null) - whichInfo.forEach(which -> returnTypes.put(which, returnType)); - - String loopOf = entryContainer.getOptional("loop of", String.class, false); - if (loopOf != null) - whichInfo.forEach(which -> loopOfs.put(which, loopOf)); - - SectionNode usableInNode = entryContainer.getOptional("usable in", SectionNode.class, false); - if (usableInNode != null && !handleUsableEntry(usableInNode, usableSuppliers)) - return false; - - for (ChangeMode mode : ChangeMode.values()) { - String name = mode.toString().replace('_', ' ').toLowerCase(Locale.ENGLISH); - NonNullPair[]> pair = entryContainer.getOptional(name, NonNullPair.class, false); - if (pair == null) - continue; - changerNodes.put(mode, pair.getFirst()); - - whichInfo.forEach(which -> { - List hasChangerList = - hasChanger.computeIfAbsent(which, k -> new ArrayList<>()); - - hasChangerList.add(mode); - }); - - - if (pair.getSecond().length == 0) - continue; - whichInfo.forEach(which -> changerTypes.computeIfAbsent(which, k -> new HashMap<>()) - .put(mode, pair.getSecond()) - ); - } - - return true; - } - - @Override - public boolean load() { - if (parseNode != null) { - SkriptLogger.setNode(parseNode); - SyntaxParseEvent.register(parseNode, whichInfo, parserHandlers); - - whichInfo.forEach(which -> parseSectionLoaded.put(which, true)); - } - - SectionNode getNode = getEntryContainer().get("get", SectionNode.class, false); - SkriptLogger.setNode(getNode); - { - getParser().setCurrentEvent("custom expression getter", ExpressionGetEvent.class); - List items = SkriptUtil.getItemsFromNode(getNode); - whichInfo.forEach(which -> expressionHandlers.put(which, - new Trigger(getParser().getCurrentScript(), "get " + which.getPattern(), new SimpleEvent(), items)) - ); - } - - changerNodes.forEach((changeMode, node) -> { - SkriptLogger.setNode(node); - getParser().setCurrentEvent("custom expression changer", ExpressionChangeEvent.class); - List items = SkriptUtil.getItemsFromNode(node); - whichInfo.forEach(which -> { - Map changerMap = changerHandlers.computeIfAbsent(which, k -> new HashMap<>()); - - String name = changeMode.toString().toLowerCase(Locale.ENGLISH).replace('_', ' '); - changerMap.put(changeMode, new Trigger( - getParser().getCurrentScript(), String.format("%s %s", name, which.getPattern()), new SimpleEvent(), items - )); - }); - }); - - SkriptLogger.setNode(null); - return true; - } - - public static ExpressionSyntaxInfo lookup(Script script, int matchedPattern) { - return dataTracker.lookup(script, matchedPattern); - } + public static boolean customExpressionsUsed = false; + + static { + String[] syntax = { + "[:local] [plural:(plural|non[-| ]single)] expression <.+>", + "[:local] [plural:(plural|non[-| ]single)] expression", + "[:local] [plural:(plural|non[-| ]single)] %*classinfos% property <.+>" + }; + EntryValidator.EntryValidatorBuilder builder = customSyntaxValidator() + .addEntryData(new KeyValueEntryData>("return type", null, true) { + @Override + @Nullable + protected Class getValue(String value) { + Class returnType = Classes.getClassFromUserInput(value); + if (returnType == null) + Skript.error("The given return type doesn't exist"); + return returnType; + } + }) + .addEntry("loop of", null, true) + .addSection("get", false); + Arrays.stream(ChangeMode.values()) + .sorted((mode1, mode2) -> { + long words1 = StringUtils.count(mode1.toString(), '_'); + long words2 = StringUtils.count(mode2.toString(), '_'); + return Long.compare(words2, words1); + }) + .map(mode -> mode.toString().replace('_', ' ').toLowerCase(Locale.ENGLISH)) + .forEach(name -> builder.addEntryData(new ChangerEntryData(name, true))); + Skript.registerStructure(StructCustomExpression.class, builder.build(), syntax); + } + + private static final DataTracker dataTracker = new DataTracker<>(); + + static final Map> returnTypes = new HashMap<>(); + static final Map expressionHandlers = new HashMap<>(); + static final Map parserHandlers = new HashMap<>(); + static final Map> hasChanger = new HashMap<>(); + static final Map> changerHandlers = new HashMap<>(); + static final Map[]>> changerTypes = new HashMap<>(); + static final Map loopOfs = new HashMap<>(); + static final Map>> usableSuppliers = new HashMap<>(); + static final Map parseSectionLoaded = new HashMap<>(); + + static { + // noinspection unchecked + Skript.registerExpression(CustomExpression.class, Object.class, ExpressionType.PATTERN_MATCHES_EVERYTHING); + Optional> info = StreamSupport.stream( + Spliterators.spliteratorUnknownSize(Skript.getExpressions(), Spliterator.ORDERED), false) + .filter(i -> i.getElementClass() == CustomExpression.class) + .findFirst(); + info.ifPresent(dataTracker::setInfo); + + dataTracker.addManaged(returnTypes); + dataTracker.addManaged(expressionHandlers); + dataTracker.addManaged(hasChanger); + dataTracker.addManaged(changerHandlers); + dataTracker.addManaged(changerTypes); + dataTracker.addManaged(parserHandlers); + dataTracker.addManaged(loopOfs); + dataTracker.addManaged(usableSuppliers); + dataTracker.addManaged(parseSectionLoaded); + } + + private final Map changerNodes = new HashMap<>(); + private SectionNode parseNode; + + @Override + protected DataTracker getDataTracker() { + return dataTracker; + } + + @SuppressWarnings("unchecked") + @Override + public boolean init(Literal[] args, int matchedPattern, SkriptParser.ParseResult parseResult, + EntryContainer entryContainer) { + customExpressionsUsed = true; + + List patterns = entryContainer.getOptional("patterns", List.class, false); + Script script = parseResult.hasTag("local") ? SkriptUtil.getCurrentScript() : null; + boolean alwaysPlural = parseResult.hasTag("plural"); + + if (matchedPattern != 1 && patterns != null) { + Skript.error("A custom expression with an inline pattern cannot have a 'patterns' entry too"); + return false; + } + + switch (matchedPattern) { + case 0: // expression with an inline pattern + String pattern = parseResult.regexes.get(0).group(); + register(ExpressionSyntaxInfo.create(script, pattern, 1, alwaysPlural, false, false)); + break; + case 1: // expression with a 'patterns' entry + if (patterns == null) { + Skript.error("A custom expression without an inline pattern must have a 'patterns' entry"); + return false; + } + + int i = 1; + for (String p : patterns) { + register(ExpressionSyntaxInfo.create(script, p, i++, alwaysPlural, false, false)); + } + break; + case 2: // property expression + String property = parseResult.regexes.get(0).group(); + String type = Arrays.stream(((Literal>) args[0]).getArray()) + .map(ClassInfo::getCodeName) + .map(codeName -> { + boolean isPlural = Utils.getEnglishPlural(codeName).getSecond(); + + if (!isPlural) { + return Utils.toEnglishPlural(codeName); + } + + return codeName; + }) + .collect(Collectors.joining("/")); + + if (!alwaysPlural) { + type = "$" + type; + } + + register( + ExpressionSyntaxInfo.create(script, "[the] " + property + " of %" + type + "%", 1, alwaysPlural, true, true)); + register(ExpressionSyntaxInfo.create(script, "%" + type + "%'[s] " + property, 1, alwaysPlural, false, true)); + break; + } + + return true; + } + + @Override + public boolean preLoad() { + super.preLoad(); + EntryContainer entryContainer = getEntryContainer(); + + SectionNode[] parseNode = getParseNode(); + if (parseNode == null) + return false; + this.parseNode = parseNode[0]; + whichInfo.forEach(which -> parseSectionLoaded.put(which, this.parseNode == null)); + + Class returnType = entryContainer.getOptional("return type", Class.class, false); + if (returnType != null) + whichInfo.forEach(which -> returnTypes.put(which, returnType)); + + String loopOf = entryContainer.getOptional("loop of", String.class, false); + if (loopOf != null) + whichInfo.forEach(which -> loopOfs.put(which, loopOf)); + + SectionNode usableInNode = entryContainer.getOptional("usable in", SectionNode.class, false); + if (usableInNode != null && !handleUsableEntry(usableInNode, usableSuppliers)) + return false; + + for (ChangeMode mode : ChangeMode.values()) { + String name = mode.toString().replace('_', ' ').toLowerCase(Locale.ENGLISH); + NonNullPair[]> pair = entryContainer.getOptional(name, NonNullPair.class, false); + if (pair == null) + continue; + changerNodes.put(mode, pair.getFirst()); + + whichInfo.forEach(which -> { + List hasChangerList = + hasChanger.computeIfAbsent(which, k -> new ArrayList<>()); + + hasChangerList.add(mode); + }); + + + if (pair.getSecond().length == 0) + continue; + whichInfo.forEach(which -> changerTypes.computeIfAbsent(which, k -> new HashMap<>()) + .put(mode, pair.getSecond()) + ); + } + + return true; + } + + @Override + public boolean load() { + if (parseNode != null) { + SkriptLogger.setNode(parseNode); + SyntaxParseEvent.register(parseNode, whichInfo, parserHandlers); + + whichInfo.forEach(which -> parseSectionLoaded.put(which, true)); + } + + SectionNode getNode = getEntryContainer().get("get", SectionNode.class, false); + SkriptLogger.setNode(getNode); + { + getParser().setCurrentEvent("custom expression getter", ExpressionGetEvent.class); + List items = SkriptUtil.getItemsFromNode(getNode); + whichInfo.forEach(which -> expressionHandlers.put(which, + new Trigger(getParser().getCurrentScript(), "get " + which.getPattern(), new SimpleEvent(), items)) + ); + } + + changerNodes.forEach((changeMode, node) -> { + SkriptLogger.setNode(node); + getParser().setCurrentEvent("custom expression changer", ExpressionChangeEvent.class); + List items = SkriptUtil.getItemsFromNode(node); + whichInfo.forEach(which -> { + Map changerMap = changerHandlers.computeIfAbsent(which, k -> new HashMap<>()); + + String name = changeMode.toString().toLowerCase(Locale.ENGLISH).replace('_', ' '); + changerMap.put(changeMode, new Trigger( + getParser().getCurrentScript(), String.format("%s %s", name, which.getPattern()), new SimpleEvent(), items + )); + }); + }); + + SkriptLogger.setNode(null); + return true; + } + + public static ExpressionSyntaxInfo lookup(Script script, int matchedPattern) { + return dataTracker.lookup(script, matchedPattern); + } } From b4f3219d653cc31b17b971f3ad42cbb414f6d8db Mon Sep 17 00:00:00 2001 From: _tud <98935832+UnderscoreTud@users.noreply.github.com> Date: Tue, 31 Dec 2024 05:54:11 +0300 Subject: [PATCH 2/2] Fix indentation --- src/main/java/com/btk5h/skriptmirror/Descriptor.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/btk5h/skriptmirror/Descriptor.java b/src/main/java/com/btk5h/skriptmirror/Descriptor.java index ada2e821..10eb6de1 100644 --- a/src/main/java/com/btk5h/skriptmirror/Descriptor.java +++ b/src/main/java/com/btk5h/skriptmirror/Descriptor.java @@ -34,11 +34,11 @@ public final class Descriptor { * A regex {@link Pattern} for a {@link Descriptor}. */ private static final Pattern DESCRIPTOR = - Pattern.compile("" + - "(?:\\[(" + SkriptMirrorUtil.PACKAGE + ")])?" + - "(" + SkriptMirrorUtil.IDENTIFIER + ")" + - "(?:\\[((?:" + PACKAGE_ARRAY + "\\s*,\\s*)*(?:" + PACKAGE_ARRAY + "))])?" - ); + Pattern.compile("" + + "(?:\\[(" + SkriptMirrorUtil.PACKAGE + ")])?" + + "(" + SkriptMirrorUtil.IDENTIFIER + ")" + + "(?:\\[((?:" + PACKAGE_ARRAY + "\\s*,\\s*)*(?:" + PACKAGE_ARRAY + "))])?" + ); private final Class javaClass; private final String name;