From 4d2bbc8054375c972604b874136101bb7ef2e9db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=9D=8F=E9=BB=91?= Date: Sun, 15 Aug 2021 03:57:11 +0800 Subject: [PATCH] 1.16 --- build.gradle | 6 +- gradle/wrapper/gradle-wrapper.properties | 2 +- .../izzel/taboolib/gradle/MethodVisit.groovy | 17 ++ .../izzel/taboolib/gradle/RelocateJar.groovy | 124 +++++++++--- .../gradle/TabooLibClassVisitor.groovy | 10 + .../taboolib/gradle/TabooLibExtension.groovy | 6 + .../gradle/TabooLibMethodVisitor.groovy | 183 ++++++++++++++++++ .../taboolib/gradle/TabooLibPlugin.groovy | 4 +- .../gradle/description/Platforms.groovy | 16 +- .../java/io/izzel/taboolib/gradle/Bridge.java | 19 ++ .../taboolib/gradle/OptimizeFileReader.kt | 134 +++++++++++++ .../io/izzel/taboolib/gradle/Platforms.kt | 13 ++ 12 files changed, 492 insertions(+), 42 deletions(-) create mode 100644 src/main/groovy/io/izzel/taboolib/gradle/MethodVisit.groovy create mode 100644 src/main/groovy/io/izzel/taboolib/gradle/TabooLibMethodVisitor.groovy create mode 100644 src/main/java/io/izzel/taboolib/gradle/Bridge.java create mode 100644 src/main/kotlin/io/izzel/taboolib/gradle/OptimizeFileReader.kt create mode 100644 src/main/kotlin/io/izzel/taboolib/gradle/Platforms.kt diff --git a/build.gradle b/build.gradle index 7246d98..d33a079 100644 --- a/build.gradle +++ b/build.gradle @@ -3,10 +3,13 @@ plugins { id 'maven-publish' id 'java-gradle-plugin' id 'com.gradle.plugin-publish' version '0.12.0' + id 'org.jetbrains.kotlin.jvm' version '1.5.10' } +apply plugin: 'kotlin' + group 'io.izzel.taboolib' -version '1.14' +version '1.16' configurations { embed @@ -24,6 +27,7 @@ dependencies { embed 'org.ow2.asm:asm:8.0.1' embed 'org.ow2.asm:asm-commons:8.0.1' embed 'com.google.code.gson:gson:2.8.7' + embed 'org.jetbrains.kotlin:kotlin-stdlib' } jar { diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ae45383..f603712 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.3-all.zip +distributionUrl=https://skymc.oss-cn-shanghai.aliyuncs.com/files/gradle-6.5-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/src/main/groovy/io/izzel/taboolib/gradle/MethodVisit.groovy b/src/main/groovy/io/izzel/taboolib/gradle/MethodVisit.groovy new file mode 100644 index 0000000..d1303b4 --- /dev/null +++ b/src/main/groovy/io/izzel/taboolib/gradle/MethodVisit.groovy @@ -0,0 +1,17 @@ +package io.izzel.taboolib.gradle + +import groovy.transform.EqualsAndHashCode +import groovy.transform.TupleConstructor + +@TupleConstructor +@EqualsAndHashCode +class MethodVisit { + + String owner + String name + + @Override + String toString() { + return owner.substring(owner.lastIndexOf("/") + 1) + "." + name + "()" + } +} \ No newline at end of file diff --git a/src/main/groovy/io/izzel/taboolib/gradle/RelocateJar.groovy b/src/main/groovy/io/izzel/taboolib/gradle/RelocateJar.groovy index 2f98c2b..36b5339 100644 --- a/src/main/groovy/io/izzel/taboolib/gradle/RelocateJar.groovy +++ b/src/main/groovy/io/izzel/taboolib/gradle/RelocateJar.groovy @@ -41,52 +41,96 @@ class RelocateJar extends DefaultTask { @TaskAction def relocate() { + // 缓存 + def optimize = [] def isolated = new TreeMap>() + def methodVisits = new TreeMap>() + + // 配置 def mapping = relocations.collectEntries { [(it.key.replace('.', '/')), it.value.replace('.', '/')] } def remapper = new RelocateRemapper(relocations, mapping as Map) + + // 文件 def index = inJar.name.lastIndexOf('.') def name = inJar.name.substring(0, index) + (classifier == null ? "" : "-" + classifier) + inJar.name.substring(index) def outJar = new File(inJar.getParentFile(), name) def tempOut1 = File.createTempFile(name, ".jar") + + // 第一次工作 new JarOutputStream(new FileOutputStream(tempOut1)).withCloseable { out -> int n def buf = new byte[32768] new JarFile(inJar).withCloseable { jarFile -> - jarFile.entries().each { def jarEntry -> - if (tabooExt.exclude.stream().noneMatch { String e -> jarEntry.name.matches(e) }) { - jarFile.getInputStream(jarEntry).withCloseable { - if (jarEntry.name.endsWith(".class")) { - def reader = new ClassReader(it) - def writer = new ClassWriter(0) - def visitor = new TabooLibClassVisitor(writer, project) - def rem = new ClassRemapper(visitor, remapper) - remapper.remapper = rem - reader.accept(rem, 0) - isolated.putAll(visitor.isolated) - try { - out.putNextEntry(new JarEntry(remapper.map(jarEntry.name))) - } catch(ZipException zipException) { - println(zipException) - return true - } - out.write(writer.toByteArray()) - } else { - try { - out.putNextEntry(new JarEntry(remapper.map(jarEntry.name))) - } catch(ZipException ex) { - println(ex) - return true - } - while ((n = it.read(buf)) != -1) { - out.write(buf, 0, n) - } - } - null + jarFile.entries().each { JarEntry jarEntry -> + def path = jarEntry.name + // 忽略用户定义的文件 + if (tabooExt.exclude.stream().any { String e -> path.startsWith(e) }) { + return + } + // 忽略模块文件 + if (path.endsWith(".kotlin_module")) { + return + } + // 忽略优化指示文件 + if (path.startsWith("META-INF/tf") && path.endsWith(".json")) { + optimize.add(Bridge.newOptimizeFileReader(project, jarFile.getInputStream(jarEntry))) + return + } + // 忽略 Kotlin 依赖 + def options = tabooExt.options + if (path == "taboolib/common/env/KotlinEnv.class" && options.contains("skip-kotlin")) { + return + } + // 忽略依赖加载部分代码 + if (path.startsWith("taboolib/common/env") && options.contains("skip-env")) { + return + } + // 忽略 common 模块打包的第三方库 + if (path.startsWith("taboolib/library/asm") || path.startsWith("taboolib/library/jarrelocator")) { + if (options.contains("skip-env") || options.contains("skip-env-relocate")) { + return } } + jarFile.getInputStream(jarEntry).withCloseable { + if (path.endsWith(".class")) { + def reader = new ClassReader(it) + def writer = new ClassWriter(0) + def visitor = new TabooLibClassVisitor(writer, project) + def rem = new ClassRemapper(visitor, remapper) + remapper.remapper = rem + reader.accept(rem, 0) + // 提取孤立类 + isolated.putAll(visitor.isolated) + // 提取方法访问记录 + methodVisits.put(relocate(project, jarEntry.name), visitor.methodVisits) + // 写回文件 + // 拦截报错防止文件名称重复导致编译终止 + try { + out.putNextEntry(new JarEntry(remapper.map(path))) + } catch (ZipException zipException) { + println(zipException) + return true + } + out.write(writer.toByteArray()) + } else { + try { + out.putNextEntry(new JarEntry(remapper.map(path))) + } catch (ZipException ex) { + println(ex) + return true + } + while ((n = it.read(buf)) != -1) { + out.write(buf, 0, n) + } + } + null + } } } } + + // 数据整理 + // 类 -> 谁正在使用 def use = new TreeMap>() remapper.use.each { it.value.each { e -> @@ -95,11 +139,19 @@ class RelocateJar extends DefaultTask { use.computeIfAbsent(key) { new HashSet() }.add(value) } } + def visits = methodVisits[methodVisits.keySet().first()] + if (visits != null) { + visits.each { + println(it) + } + } def transfer = new TreeMap() isolated.each { transfer[relocate(project, it.key)] = it.value.stream().map { i -> relocate(project, i) }.collect(Collectors.toList()) } isolated = transfer + + // 第二次工作 def tempOut2 = File.createTempFile(name, ".jar") new JarOutputStream(new FileOutputStream(tempOut2)).withCloseable { out -> int n @@ -107,14 +159,16 @@ class RelocateJar extends DefaultTask { def del = new HashSet() def exclude = new HashSet() new JarFile(tempOut1).withCloseable { jarFile -> - jarFile.entries().each { def jarEntry -> + jarFile.entries().each { JarEntry jarEntry -> + if (optimize.any { it.exclude(jarEntry.name, use) }) { + return + } jarFile.getInputStream(jarEntry).withCloseable { if (jarEntry.name.endsWith(".class")) { def nameWithOutExtension = getNameWithOutExtension(jarEntry.name) if (use.containsKey(nameWithOutExtension.toString()) && !exclude.contains(nameWithOutExtension)) { exclude.add(nameWithOutExtension) if (isIsolated(use, use[nameWithOutExtension], isolated, nameWithOutExtension)) { - println(" Isolated ${nameWithOutExtension}") del.add(nameWithOutExtension) } } @@ -173,4 +227,10 @@ class RelocateJar extends DefaultTask { return false } } + + + @Override + public String toString() { + return "RelocateJar{}"; + } } diff --git a/src/main/groovy/io/izzel/taboolib/gradle/TabooLibClassVisitor.groovy b/src/main/groovy/io/izzel/taboolib/gradle/TabooLibClassVisitor.groovy index 05cbeb8..c47a6c3 100644 --- a/src/main/groovy/io/izzel/taboolib/gradle/TabooLibClassVisitor.groovy +++ b/src/main/groovy/io/izzel/taboolib/gradle/TabooLibClassVisitor.groovy @@ -3,14 +3,19 @@ package io.izzel.taboolib.gradle import org.gradle.api.Project import org.objectweb.asm.AnnotationVisitor import org.objectweb.asm.ClassVisitor +import org.objectweb.asm.MethodVisitor import org.objectweb.asm.Opcodes class TabooLibClassVisitor extends ClassVisitor { String name + Project project + Map> isolated = new HashMap() + Set methodVisits = new HashSet<>() + List annotations = [ "Lorg/spongepowered/api/plugin/Plugin;", "Lorg/spongepowered/plugin/jvm/Plugin;", @@ -28,6 +33,11 @@ class TabooLibClassVisitor extends ClassVisitor { super.visit(version, access, name, signature, superName, interfaces) } + @Override + MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { + return new TabooLibMethodVisitor(super.visitMethod(access, name, descriptor, signature, exceptions), this) + } + @Override AnnotationVisitor visitAnnotation(String descriptor, boolean visible) { if (descriptor == "L${project.group.replace('.', '/')}/taboolib/common/Isolated;") { diff --git a/src/main/groovy/io/izzel/taboolib/gradle/TabooLibExtension.groovy b/src/main/groovy/io/izzel/taboolib/gradle/TabooLibExtension.groovy index daf274c..7390725 100644 --- a/src/main/groovy/io/izzel/taboolib/gradle/TabooLibExtension.groovy +++ b/src/main/groovy/io/izzel/taboolib/gradle/TabooLibExtension.groovy @@ -19,10 +19,16 @@ class TabooLibExtension { Map relocation = new LinkedHashMap<>() + List options = [] + def install(String... name) { name.each { modules += it } } + def options(String... opt) { + opt.each { options += it } + } + def exclude(String match) { exclude += match } diff --git a/src/main/groovy/io/izzel/taboolib/gradle/TabooLibMethodVisitor.groovy b/src/main/groovy/io/izzel/taboolib/gradle/TabooLibMethodVisitor.groovy new file mode 100644 index 0000000..1009962 --- /dev/null +++ b/src/main/groovy/io/izzel/taboolib/gradle/TabooLibMethodVisitor.groovy @@ -0,0 +1,183 @@ +package io.izzel.taboolib.gradle + + +import groovy.transform.EqualsAndHashCode +import groovy.transform.TupleConstructor +import org.objectweb.asm.AnnotationVisitor +import org.objectweb.asm.Attribute +import org.objectweb.asm.Handle +import org.objectweb.asm.Label +import org.objectweb.asm.MethodVisitor +import org.objectweb.asm.Opcodes +import org.objectweb.asm.TypePath + +class TabooLibMethodVisitor extends MethodVisitor { + + TabooLibClassVisitor classVisitor + + TabooLibMethodVisitor(MethodVisitor methodVisitor, TabooLibClassVisitor classVisitor) { + super(Opcodes.ASM7, methodVisitor) + this.classVisitor = classVisitor + } + + @Override + void visitParameter(String name, int access) { + super.visitParameter(name, access) + } + + @Override + AnnotationVisitor visitAnnotationDefault() { + return super.visitAnnotationDefault() + } + + @Override + AnnotationVisitor visitAnnotation(String descriptor, boolean visible) { + return super.visitAnnotation(descriptor, visible) + } + + @Override + AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String descriptor, boolean visible) { + return super.visitTypeAnnotation(typeRef, typePath, descriptor, visible) + } + + @Override + void visitAnnotableParameterCount(int parameterCount, boolean visible) { + super.visitAnnotableParameterCount(parameterCount, visible) + } + + @Override + AnnotationVisitor visitParameterAnnotation(int parameter, String descriptor, boolean visible) { + return super.visitParameterAnnotation(parameter, descriptor, visible) + } + + @Override + void visitAttribute(Attribute attribute) { + super.visitAttribute(attribute) + } + + @Override + void visitCode() { + super.visitCode() + } + + @Override + void visitFrame(int type, int numLocal, Object[] local, int numStack, Object[] stack) { + super.visitFrame(type, numLocal, local, numStack, stack) + } + + @Override + void visitInsn(int opcode) { + super.visitInsn(opcode) + } + + @Override + void visitIntInsn(int opcode, int operand) { + super.visitIntInsn(opcode, operand) + } + + @Override + void visitVarInsn(int opcode, int i) { + super.visitVarInsn(opcode, i) + } + + @Override + void visitTypeInsn(int opcode, String type) { + super.visitTypeInsn(opcode, type) + } + + @Override + void visitFieldInsn(int opcode, String owner, String name, String descriptor) { + super.visitFieldInsn(opcode, owner, name, descriptor) + } + + @Override + void visitMethodInsn(int opcode, String owner, String name, String descriptor) { + super.visitMethodInsn(opcode, owner, name, descriptor) + } + + @Override + void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) { + classVisitor.methodVisits.add(new MethodVisit(owner, name)) + super.visitMethodInsn(opcode, owner, name, descriptor, isInterface) + } + + @Override + void visitInvokeDynamicInsn(String name, String descriptor, Handle bootstrapMethodHandle, Object... bootstrapMethodArguments) { + super.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments) + } + + @Override + void visitJumpInsn(int opcode, Label label) { + super.visitJumpInsn(opcode, label) + } + + @Override + void visitLabel(Label label) { + super.visitLabel(label) + } + + @Override + void visitLdcInsn(Object value) { + super.visitLdcInsn(value) + } + + @Override + void visitIincInsn(int i, int increment) { + super.visitIincInsn(i, increment) + } + + @Override + void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels) { + super.visitTableSwitchInsn(min, max, dflt, labels) + } + + @Override + void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) { + super.visitLookupSwitchInsn(dflt, keys, labels) + } + + @Override + void visitMultiANewArrayInsn(String descriptor, int numDimensions) { + super.visitMultiANewArrayInsn(descriptor, numDimensions) + } + + @Override + AnnotationVisitor visitInsnAnnotation(int typeRef, TypePath typePath, String descriptor, boolean visible) { + return super.visitInsnAnnotation(typeRef, typePath, descriptor, visible) + } + + @Override + void visitTryCatchBlock(Label start, Label end, Label handler, String type) { + super.visitTryCatchBlock(start, end, handler, type) + } + + @Override + AnnotationVisitor visitTryCatchAnnotation(int typeRef, TypePath typePath, String descriptor, boolean visible) { + return super.visitTryCatchAnnotation(typeRef, typePath, descriptor, visible) + } + + @Override + void visitLocalVariable(String name, String descriptor, String signature, Label start, Label end, int index) { + super.visitLocalVariable(name, descriptor, signature, start, end, index) + } + + @Override + AnnotationVisitor visitLocalVariableAnnotation(int typeRef, TypePath typePath, Label[] start, Label[] end, int[] index, String descriptor, boolean visible) { + return super.visitLocalVariableAnnotation(typeRef, typePath, start, end, index, descriptor, visible) + } + + @Override + void visitLineNumber(int line, Label start) { + super.visitLineNumber(line, start) + } + + @Override + void visitMaxs(int maxStack, int maxLocals) { + super.visitMaxs(maxStack, maxLocals) + } + + @Override + void visitEnd() { + super.visitEnd() + } +} diff --git a/src/main/groovy/io/izzel/taboolib/gradle/TabooLibPlugin.groovy b/src/main/groovy/io/izzel/taboolib/gradle/TabooLibPlugin.groovy index ae1ef43..0cc47c5 100644 --- a/src/main/groovy/io/izzel/taboolib/gradle/TabooLibPlugin.groovy +++ b/src/main/groovy/io/izzel/taboolib/gradle/TabooLibPlugin.groovy @@ -30,8 +30,10 @@ class TabooLibPlugin implements Plugin { task.inJar = task.inJar ?: jarTask.archivePath task.relocations = tabooExt.relocation task.classifier = tabooExt.classifier - task.relocations['kotlin'] = 'taboolib.library.kotlin_' + kv task.relocations['taboolib'] = project.group.toString() + '.taboolib' + if (!tabooExt.options.contains("skip-kotlin")) { + task.relocations['kotlin'] = 'taboolib.library.kotlin_' + kv + } } } } diff --git a/src/main/groovy/io/izzel/taboolib/gradle/description/Platforms.groovy b/src/main/groovy/io/izzel/taboolib/gradle/description/Platforms.groovy index 1531e46..406895a 100644 --- a/src/main/groovy/io/izzel/taboolib/gradle/description/Platforms.groovy +++ b/src/main/groovy/io/izzel/taboolib/gradle/description/Platforms.groovy @@ -2,23 +2,25 @@ package io.izzel.taboolib.gradle.description enum Platforms { - BUKKIT('platform-bukkit', 'plugin.yml', new BuilderBukkit()), + BUKKIT('Bukkit', 'platform-bukkit', 'plugin.yml', new BuilderBukkit()), - NUKKIT('platform-nukkit', 'nukkit.yml', new BuilderNukkit()), + NUKKIT('Nukkit', 'platform-nukkit', 'nukkit.yml', new BuilderNukkit()), - BUNGEE('platform-bungee', 'bungee.yml', new BuilderBungee()), + BUNGEE('Bungee', 'platform-bungee', 'bungee.yml', new BuilderBungee()), - VELOCITY('platform-velocity', 'velocity-plugin.json', new BuilderVelocity()), + VELOCITY('Velocity', 'platform-velocity', 'velocity-plugin.json', new BuilderVelocity()), - SPONGE7('platform-sponge-api7', 'mcmod.info', new BuilderSponge7()), + SPONGE7('Sponge7', 'platform-sponge-api7', 'mcmod.info', new BuilderSponge7()), - SPONGE8('platform-sponge-api8', 'META-INF/plugins.json', new BuilderSponge8()); + SPONGE8('Sponge8', 'platform-sponge-api8', 'META-INF/plugins.json', new BuilderSponge8()); + String key String module String file Builder builder - Platforms(module, file, builder) { + Platforms(key, module, file, builder) { + this.key = key this.module = module this.file = file this.builder = builder diff --git a/src/main/java/io/izzel/taboolib/gradle/Bridge.java b/src/main/java/io/izzel/taboolib/gradle/Bridge.java new file mode 100644 index 0000000..dab7bd8 --- /dev/null +++ b/src/main/java/io/izzel/taboolib/gradle/Bridge.java @@ -0,0 +1,19 @@ +package io.izzel.taboolib.gradle; + +import org.gradle.api.Project; + +import java.io.InputStream; + +/** + * taboolib-gradle-plugin + * io.izzel.taboolib.gradle.KotlinFactory + * + * @author sky + * @since 2021/8/14 1:43 下午 + */ +public class Bridge { + + public static OptimizeFileReader newOptimizeFileReader(Project project, InputStream inputStream) { + return new OptimizeFileReader(project, inputStream); + } +} diff --git a/src/main/kotlin/io/izzel/taboolib/gradle/OptimizeFileReader.kt b/src/main/kotlin/io/izzel/taboolib/gradle/OptimizeFileReader.kt new file mode 100644 index 0000000..5931203 --- /dev/null +++ b/src/main/kotlin/io/izzel/taboolib/gradle/OptimizeFileReader.kt @@ -0,0 +1,134 @@ +package io.izzel.taboolib.gradle + +import com.google.gson.JsonParser +import org.gradle.api.Project +import java.io.InputStream +import java.nio.charset.StandardCharsets + +/** + * taboolib-gradle-plugin + * io.izzel.taboolib.gradle.OptimizeFileReader + * + * @author sky + * @since 2021/8/14 1:18 下午 + */ +class OptimizeFileReader(project: Project, input: InputStream) { + + val optimize = ArrayList() + val group = ArrayList() + val exclude = ArrayList() + + init { + try { + val jsonSource = input.readBytes().toString(StandardCharsets.UTF_8) + val json = JsonParser.parseString(jsonSource).asJsonObject + if (json.has("optimize")) { + json.getAsJsonArray("optimize").forEach { ele -> + optimize += Optimize( + relocate(project, ele.asJsonObject["class"].asString), + Optimize.Type.valueOf(ele.asJsonObject["type"].asString) + ) + } + } + if (json.has("group")) { + json.getAsJsonArray("group").forEach { ele -> + var depend: Group.Depend? = null + if (ele.asJsonObject.has("depend")) { + depend = Group.Depend( + ele.asJsonObject["depend"].asJsonObject["name"].asJsonArray.map { relocate(project, it.asString) }, + ele.asJsonObject["depend"].asJsonObject["exclude"].asJsonArray.map { relocate(project, it.asString) } + ) + } + group += Group( + ele.asJsonObject["check"].asJsonArray.map { relocate(project, it.asString) }, + ele.asJsonObject["member"].asJsonArray.map { relocate(project, it.asString) }, + ele.asJsonObject["exclude"]?.asJsonArray?.map { relocate(project, it.asString) }?.toList() ?: emptyList(), + depend, + Group.Mode.valueOf(ele.asJsonObject["mode"].asString) + ) + } + } + if (json.has("exclude")) { + exclude += json.getAsJsonArray("exclude").map { relocate(project, it.asString) } + } + } catch (ex: Throwable) { + ex.printStackTrace() + } + } + + fun relocate(project: Project, name: String): String { + return if (name.startsWith("taboolib")) { + project.group.toString().replace('.', '/') + '/' + name.replace('.', '/') + } else { + name.replace('.', '/') + } + } + + fun exclude(name: String, use: Map>): Boolean { + if (exclude.any { name.startsWith(it) }) { + return true + } + if (group.any { it.exclude(name, use) }) { + return true + } + return false + } + + class Optimize(val path: String, val type: Type) { + + enum class Type { + + METHOD + } + } + + class Group(check: List, member: List, exclude: List, val depend: Depend? = null, val mode: Mode) { + + val check = check.platformFlatten() + + val member = member.platformFlatten() + + val exclude = exclude.platformFlatten() + + class Depend(name: List, exclude: List) { + + val name = name.platformFlatten() + + val exclude = exclude.platformFlatten() + } + + enum class Mode { + + REMOVE + } + + fun exclude(name: String, use: Map>): Boolean { + if (member.any { name.startsWith(it) }) { + if (depend != null) { + val fail = depend.name.any { n -> + val set = use[n]!!.toMutableList() + set.remove(n) + set.removeAll(depend.exclude) + set.isNotEmpty() + } + if (fail) { + return false + } + } + for (s in check) { + val set = use[s]!!.toMutableList() + set.remove(s) + set.removeAll(check) + set.removeAll(member) + set.removeAll(exclude) + if (set.isNotEmpty()) { + return false + } + } + return true + } else { + return false + } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/io/izzel/taboolib/gradle/Platforms.kt b/src/main/kotlin/io/izzel/taboolib/gradle/Platforms.kt new file mode 100644 index 0000000..bd6bf30 --- /dev/null +++ b/src/main/kotlin/io/izzel/taboolib/gradle/Platforms.kt @@ -0,0 +1,13 @@ +package io.izzel.taboolib.gradle + +val platforms = listOf("Bukkit", "Nukkit", "Bungee", "Sponge7", "Sponge8", "Velocity") + +fun List.platformFlatten(): List { + return flatMap { + if (it.contains("{platform}")) { + platforms.map { p -> it.replace("{platform}", p) } + } else { + listOf(it) + } + } +} \ No newline at end of file