diff --git a/LICENSE-header.txt b/LICENSE-header.txt index b36a90b..7c2e6b3 100644 --- a/LICENSE-header.txt +++ b/LICENSE-header.txt @@ -1,5 +1,5 @@ LegacyDev -Copyright (c) 2016-2020. +Copyright (c) ${year}. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public diff --git a/build.gradle b/build.gradle index c823940..4df3ad5 100644 --- a/build.gradle +++ b/build.gradle @@ -1,32 +1,18 @@ -buildscript { - repositories { - mavenCentral() - } -} - plugins { - id 'net.minecrell.licenser' version '0.3' - id 'org.ajoberstar.grgit' version '4.0.0' - id 'com.github.johnrengelman.shadow' version '5.2.0' + id 'java' + id 'eclipse' + id 'idea' + id 'maven-publish' + id 'org.cadixdev.licenser' version '0.6.1' + id 'org.ajoberstar.grgit' version '4.0.0' } -apply plugin: 'maven' -apply plugin: 'maven-publish' -apply plugin: 'java' -apply plugin: 'eclipse' -apply plugin: 'idea' - -repositories { - mavenCentral() -} - - ext { TAG = '0.0' } def gitVersion = { - def raw = grgit.describe(longDescr: true, tags:true) - def desc = (raw == null ? '0.0-0-unknown' : grgit.describe(longDescr: true, tags:true)).split('-') as List + def raw = grgit.describe(longDescr: true, tags: true) + def desc = (raw == null ? '0.0-0-unknown' : grgit.describe(longDescr: true, tags: true)).split('-') as List def hash = desc.remove(desc.size() - 1) def offset = desc.remove(desc.size() - 1) TAG = desc.join('-') @@ -44,29 +30,42 @@ version = gitVersion() targetCompatibility = sourceCompatibility = compileJava.sourceCompatibility = compileJava.targetCompatibility = '1.8' license { - header project.file('LICENSE-header.txt') - include 'net/minecraftforge/legacydev/**/*.java' - newLine false + header project.file('LICENSE-header.txt') + ext["year"] = '2016-' + Calendar.getInstance().get(Calendar.YEAR) + include 'net/minecraftforge/legacydev/**/*.java' + newLine false } ext { - MANIFEST = manifest{ + MANIFEST = manifest { attributes([ - 'Specification-Title': 'accesstransformers', - 'Specification-Vendor': 'Forge Development LLC', - 'Specification-Version': TAG, - 'Implementation-Title': project.name, - 'Implementation-Version': "${version}+${System.getenv("BUILD_NUMBER")?:0}+${grgit.head().abbreviatedId}", - 'Implementation-Vendor': 'Forge Development LLC', - 'Implementation-Timestamp': new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"), - 'Git-Commit': grgit.head().abbreviatedId, - 'Git-Branch': grgit.branch.current().getName() + 'Specification-Title' : 'accesstransformers', + 'Specification-Vendor' : 'Forge Development LLC', + 'Specification-Version' : TAG, + 'Implementation-Title' : project.name, + 'Implementation-Version' : "${version}+${System.getenv("BUILD_NUMBER") ?: 0}+${grgit.head().abbreviatedId}", + 'Implementation-Vendor' : 'Forge Development LLC', + 'Implementation-Timestamp': new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"), + 'Git-Commit' : grgit.head().abbreviatedId, + 'Git-Branch' : grgit.branch.current().getName() ] as LinkedHashMap, 'net/minecraftforge/legacydev/') } } +repositories { + mavenCentral() + maven { + name 'mojang' + url 'https://libraries.minecraft.net/' + } +} + dependencies { - compile 'net.sf.jopt-simple:jopt-simple:5.0.4' + implementation 'net.sf.jopt-simple:jopt-simple:5.0.4' + implementation('net.minecraft:launchwrapper:1.12') { + exclude group: 'org.ow2.asm' + } + implementation 'com.google.guava:guava:21.0' } compileJava { @@ -79,19 +78,7 @@ task sourcesJar(type: Jar, dependsOn: classes) { manifest.from(MANIFEST) } -task relocateShadowJar(type: com.github.jengelman.gradle.plugins.shadow.tasks.ConfigureShadowRelocation) { - target = tasks.shadowJar - prefix = "${project.group}.${project.name}.reloc" -} - -shadowJar { - dependsOn(relocateShadowJar) - classifier 'fatjar' - manifest.from(MANIFEST) -} - artifacts { - archives shadowJar archives sourcesJar } @@ -103,7 +90,6 @@ publishing { publications { mavenJava(MavenPublication) { artifact sourcesJar - artifact shadowJar artifact jar pom { name = project.archivesBaseName diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 9492014..ae04661 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-6.0.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/src/main/java/net/minecraftforge/gradle/GradleForgeHacks.java b/src/main/java/net/minecraftforge/gradle/GradleForgeHacks.java new file mode 100644 index 0000000..429b5ab --- /dev/null +++ b/src/main/java/net/minecraftforge/gradle/GradleForgeHacks.java @@ -0,0 +1,286 @@ +/* + * LegacyDev + * Copyright (c) 2016-2020. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +package net.minecraftforge.gradle; + +import com.google.common.base.Charsets; +import com.google.common.base.Joiner; +import com.google.common.base.Splitter; +import com.google.common.base.Strings; +import com.google.common.io.Files; +import net.minecraft.launchwrapper.IClassTransformer; +import net.minecraft.launchwrapper.LaunchClassLoader; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.*; +import java.util.jar.Attributes; +import java.util.jar.JarFile; +import java.util.jar.Manifest; + +public class GradleForgeHacks { + public static final Map CORE_MAP = new HashMap<>(); + private static final Logger LOGGER = LogManager.getLogger(); + /* ----------- COREMOD AND AT HACK --------- */ + private static final String NO_CORE_SEARCH = "--noCoreSearch"; + // coremod hack + private static final String COREMOD_VAR = "fml.coreMods.load"; + private static final String COREMOD_MF = "FMLCorePlugin"; + // AT hack + private static final String MOD_ATD_CLASS = "net.minecraftforge.fml.common.asm.transformers.ModAccessTransformer"; + private static final String MOD_AT_METHOD = "addJar"; + + public static void searchCoremods(List args) { + // check for argument + if (args.contains(NO_CORE_SEARCH)) { + // no core searching + LOGGER.info("GradleForgeHacks coremod searching disabled!"); + + // remove it so it cant potentially screw up the bounced start class + args.remove(NO_CORE_SEARCH); + + return; + } + + // initialize AT hack Method + AtRegistrar atRegistrar = new AtRegistrar(); + + URLClassLoader urlClassLoader = (URLClassLoader) GradleForgeHacks.class.getClassLoader(); + for (URL url : urlClassLoader.getURLs()) { + try { + searchCoremodAtUrl(url, atRegistrar); + } catch (IOException | InvocationTargetException | IllegalAccessException | URISyntaxException e) { + LOGGER.warn("GradleForgeHacks failed to search for coremod at url {}", url, e); + } + } + + // set coremod property. + Set coremodsSet = new HashSet<>(); + String coremodVar = System.getProperty(COREMOD_VAR); + if (!Strings.isNullOrEmpty(coremodVar)) + coremodsSet.addAll(Splitter.on(',').splitToList(coremodVar)); + coremodsSet.addAll(CORE_MAP.keySet()); + System.setProperty(COREMOD_VAR, Joiner.on(',').join(coremodsSet)); + + // ok.. tweaker hack now. + if (!Strings.isNullOrEmpty(System.getenv("tweakClass"))) { + args.add("--tweakClass"); + args.add("net.minecraftforge.gradle.tweakers.CoremodTweaker"); + } + } + + private static void searchCoremodAtUrl(URL url, AtRegistrar atRegistrar) throws IOException, InvocationTargetException, IllegalAccessException, URISyntaxException { + if (!url.getProtocol().startsWith("file")) // because file urls start with file:// + return; // this isn't a file + + File coreMod = new File(url.toURI().getPath()); + if (!coreMod.exists()) + return; + + Manifest manifest = null; + if (coreMod.isDirectory()) { + File manifestMF = new File(coreMod, "META-INF/MANIFEST.MF"); + if (manifestMF.exists()) { + FileInputStream stream = new FileInputStream(manifestMF); + manifest = new Manifest(stream); + stream.close(); + } + } else if (coreMod.getName().endsWith("jar")) { // its a jar + try (JarFile jar = new JarFile(coreMod)) { + manifest = jar.getManifest(); + if (manifest != null) { + atRegistrar.addJar(jar, manifest); + } + } + } + + // we got the manifest? use it. + if (manifest != null) { + String clazz = manifest.getMainAttributes().getValue(COREMOD_MF); + if (!Strings.isNullOrEmpty(clazz)) { + LOGGER.info("Found and added coremod: " + clazz); + CORE_MAP.put(clazz, coreMod); + } + } + } + + /** + * Hack to register jar ATs with Minecraft Forge + */ + private static final class AtRegistrar { + private static final Attributes.Name FMLAT = new Attributes.Name("FMLAT"); + + private Method newMethod = null; + private Method oldMethod = null; + + private AtRegistrar() { + try { + Class modAtdClass = Class.forName(MOD_ATD_CLASS); + try { + newMethod = modAtdClass.getDeclaredMethod(MOD_AT_METHOD, JarFile.class, String.class); + } catch (NoSuchMethodException | SecurityException ignored) { + try { + oldMethod = modAtdClass.getDeclaredMethod(MOD_AT_METHOD, JarFile.class); + } catch (NoSuchMethodException | SecurityException ignored2) { + LOGGER.error("Failed to find method {}.{}", MOD_ATD_CLASS, MOD_AT_METHOD); + } + } + } catch (ClassNotFoundException e) { + LOGGER.error("Failed to find class {}", MOD_ATD_CLASS); + } + } + + public void addJar(JarFile jarFile, Manifest manifest) throws InvocationTargetException, IllegalAccessException { + if (newMethod != null) { + String ats = manifest.getMainAttributes().getValue(FMLAT); + if (ats != null && !ats.isEmpty()) { + newMethod.invoke(null, jarFile, ats); + } + } else if (oldMethod != null) { + oldMethod.invoke(null, jarFile); + } + } + } + + /* ----------- CUSTOM TWEAKER FOR COREMOD HACK --------- */ + + // here and not in the tweaker package because classloader hell + @SuppressWarnings("unused") + public static final class AccessTransformerTransformer implements IClassTransformer { + private static final String AT_CLASS = "net.minecraftforge.fml.common.asm.transformers.AccessTransformer"; + private static final String AT_MOD_CLASS = "net.minecraftforge.fml.common.asm.transformers.AccessTransformer$Modifier"; + + public AccessTransformerTransformer() { + doStuff((LaunchClassLoader) getClass().getClassLoader()); + } + + private void doStuff(LaunchClassLoader classloader) { + Class atClass; + try { + atClass = Class.forName(AT_CLASS); + } catch (ClassNotFoundException e) { + LOGGER.log(Level.ERROR, "Could not find AccessTransformer class."); + return; + } + + // Find all non-default access transformers + List accessTransformers = new ArrayList<>(); + for (IClassTransformer transformer : classloader.getTransformers()) { + Class clazz = transformer.getClass(); + if (clazz != atClass && atClass.isInstance(transformer)) { + accessTransformers.add(transformer); + } + } + + // impossible! but i will ignore it. + if (accessTransformers.isEmpty()) { + LOGGER.log(Level.ERROR, "ModAccessTransformer was somehow not found."); + return; + } + + // grab the list of Modifiers I wanna mess with + Collection modifiers = new ArrayList<>(); + try { + // super class of ModAccessTransformer is AccessTransformer + Field f = atClass.getDeclaredFields()[1]; // its the modifiers map. Only non-static field there. + f.setAccessible(true); + + for (IClassTransformer transformer : accessTransformers) { + modifiers.addAll(((com.google.common.collect.Multimap) f.get(transformer)).values()); + } + } catch (Throwable t) { + LOGGER.log(Level.ERROR, "AccessTransformer.modifiers field was somehow not found..."); + return; + } + + if (modifiers.isEmpty()) + return; // hell no am I gonna do stuff if its empty.. + + // grab the field I wanna hack + Field nameField; + try { + // get 1 from the collection + nameField = Class.forName(AT_MOD_CLASS).getDeclaredField("name"); + nameField.setAccessible(true); // its already public, but just in case + } catch (Throwable t) { + LOGGER.log(Level.ERROR, "AccessTransformer.Modifier.name field was somehow not found..."); + return; + } + + // read the field and method CSV files. + Map nameMap = new HashMap<>(); + try { + String csvDir = System.getProperty("net.minecraftforge.gradle.GradleStart.csvDir"); + if (csvDir != null) { + readCsv(new File(csvDir, "fields.csv"), nameMap); + readCsv(new File(csvDir, "methods.csv"), nameMap); + } + } catch (IOException e) { + // If I cant find these.. something is wrong. + LOGGER.log(Level.ERROR, "Could not load CSV files!"); + e.printStackTrace(); + return; + } + + if (!nameMap.isEmpty()) { + LOGGER.log(Level.INFO, "Remapping AccessTransformer rules..."); + + // finally hit the modifiers + for (Object modifier : modifiers) { // these are instances of AccessTransformer.Modifier + try { + String name = (String) nameField.get(modifier); + String newName = nameMap.get(name); + if (newName != null) + nameField.set(modifier, newName); + } catch (Exception e) { + // impossible. It would have failed earlier if possible. + } + } + } + } + + private void readCsv(File file, Map map) throws IOException { + LOGGER.log(Level.DEBUG, "Reading CSV file: {}", file); + Splitter split = Splitter.on(',').trimResults().limit(3); + for (String line : Files.readLines(file, Charsets.UTF_8)) { + if (line.startsWith("searge")) // header line + continue; + + List splits = split.splitToList(line); + map.put(splits.get(0), splits.get(1)); + } + } + + @Override + public byte[] transform(String name, String transformedName, byte[] basicClass) { + return basicClass; // nothing here + } + } +} diff --git a/src/main/java/net/minecraftforge/gradle/tweakers/AccessTransformerTweaker.java b/src/main/java/net/minecraftforge/gradle/tweakers/AccessTransformerTweaker.java new file mode 100644 index 0000000..636c60c --- /dev/null +++ b/src/main/java/net/minecraftforge/gradle/tweakers/AccessTransformerTweaker.java @@ -0,0 +1,47 @@ +/* + * LegacyDev + * Copyright (c) 2016-2020. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +package net.minecraftforge.gradle.tweakers; + +import net.minecraft.launchwrapper.ITweaker; +import net.minecraft.launchwrapper.LaunchClassLoader; + +import java.io.File; +import java.util.List; + +@SuppressWarnings("unused") +public class AccessTransformerTweaker implements ITweaker { + @Override + public void injectIntoClassLoader(LaunchClassLoader classLoader) { + // so I can get it in the right ClassLaoder + classLoader.registerTransformer("net.minecraftforge.gradle.GradleForgeHacks$AccessTransformerTransformer"); + } + + @Override + public void acceptOptions(List args, File gameDir, File assetsDir, String profile) {} + + @Override + public String getLaunchTarget() { + return null; + } + + @Override + public String[] getLaunchArguments() { + return new String[0]; + } +} diff --git a/src/main/java/net/minecraftforge/gradle/tweakers/CoremodTweaker.java b/src/main/java/net/minecraftforge/gradle/tweakers/CoremodTweaker.java new file mode 100644 index 0000000..273f6c1 --- /dev/null +++ b/src/main/java/net/minecraftforge/gradle/tweakers/CoremodTweaker.java @@ -0,0 +1,115 @@ +/* + * LegacyDev + * Copyright (c) 2016-2020. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +package net.minecraftforge.gradle.tweakers; + +import net.minecraft.launchwrapper.ITweaker; +import net.minecraft.launchwrapper.Launch; +import net.minecraft.launchwrapper.LaunchClassLoader; +import net.minecraftforge.gradle.GradleForgeHacks; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.io.File; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.util.List; +import java.util.Map; + +@SuppressWarnings("unused") +public class CoremodTweaker implements ITweaker { + protected static final Logger LOGGER = LogManager.getLogger("CoremodTweaker"); + private static final String COREMOD_CLASS = "net.minecraftforge.fml.relauncher.CoreModManager"; + private static final String TWEAKER_SORT_FIELD = "tweakSorting"; + + @Override + @SuppressWarnings("unchecked") + public void injectIntoClassLoader(LaunchClassLoader classLoader) { + try { + Field coreModList = Class.forName("net.minecraftforge.fml.relauncher.CoreModManager", true, classLoader).getDeclaredField("loadPlugins"); + coreModList.setAccessible(true); + + // grab constructor. + Class clazz = (Class) Class.forName("net.minecraftforge.fml.relauncher.CoreModManager$FMLPluginWrapper", true, classLoader); + Constructor construct = (Constructor) clazz.getConstructors()[0]; + construct.setAccessible(true); + + Field[] fields = clazz.getDeclaredFields(); + Field pluginField = fields[1]; // 1 + Field fileField = fields[3]; // 3 + Field listField = fields[2]; // 2 + + Field.setAccessible(clazz.getConstructors(), true); + Field.setAccessible(fields, true); + + List oldList = (List) coreModList.get(null); + + for (int i = 0; i < oldList.size(); i++) { + ITweaker tweaker = oldList.get(i); + + if (clazz.isInstance(tweaker)) { + Object coreMod = pluginField.get(tweaker); + Object oldFile = fileField.get(tweaker); + File newFile = GradleForgeHacks.CORE_MAP.get(coreMod.getClass().getCanonicalName()); + + LOGGER.info("Injecting location in coremod {}", coreMod.getClass().getCanonicalName()); + + if (newFile != null && oldFile == null) { + // build new tweaker. + oldList.set(i, construct.newInstance(fields[0].get(tweaker), // name + coreMod, // coremod + newFile, // location + fields[4].getInt(tweaker), // sort index? + ((List) listField.get(tweaker)).toArray(new String[0]))); + } + } + } + } catch (Throwable t) { + LOGGER.log(Level.ERROR, "Something went wrong with the coremod adding."); + t.printStackTrace(); + } + + // inject the additional AT tweaker + String atTweaker = "net.minecraftforge.gradle.tweakers.AccessTransformerTweaker"; + ((List) Launch.blackboard.get("TweakClasses")).add(atTweaker); + + // make sure its after the deobf tweaker + try { + Field f = Class.forName(COREMOD_CLASS, true, classLoader).getDeclaredField(TWEAKER_SORT_FIELD); + f.setAccessible(true); + ((Map) f.get(null)).put(atTweaker, 1001); + } catch (Throwable t) { + LOGGER.log(Level.ERROR, "Something went wrong with the adding the AT tweaker adding."); + t.printStackTrace(); + } + } + + @Override + public String getLaunchTarget() { + return null; + } + + @Override + public String[] getLaunchArguments() { + return new String[0]; + } + + @Override + public void acceptOptions(List args, File gameDir, File assetsDir, String profile) {} +} diff --git a/src/main/java/net/minecraftforge/legacydev/Main.java b/src/main/java/net/minecraftforge/legacydev/Main.java index 239339e..ccde401 100644 --- a/src/main/java/net/minecraftforge/legacydev/Main.java +++ b/src/main/java/net/minecraftforge/legacydev/Main.java @@ -1,6 +1,6 @@ /* * LegacyDev - * Copyright (c) 2016-2020. + * Copyright (c) 2016-2023. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -18,6 +18,12 @@ */ package net.minecraftforge.legacydev; +import com.google.common.base.Preconditions; +import joptsimple.NonOptionArgumentSpec; +import joptsimple.OptionParser; +import joptsimple.OptionSet; +import net.minecraftforge.gradle.GradleForgeHacks; + import java.io.IOException; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; @@ -28,9 +34,6 @@ import java.util.Map; import java.util.logging.LogManager; import java.util.logging.Logger; -import joptsimple.NonOptionArgumentSpec; -import joptsimple.OptionParser; -import joptsimple.OptionSet; public class Main { static Logger LOGGER = setupLogger(); @@ -63,27 +66,29 @@ protected void start(String[] args) throws ClassNotFoundException, NoSuchMethodE System.setProperty("net.minecraftforge.gradle.GradleStart.srg.srg-mcp", srg2mcp); } - String[] cleanArgs = parseArgs(args); + List cleanArgs = parseArgs(args); + + GradleForgeHacks.searchCoremods(cleanArgs); StringBuilder b = new StringBuilder(); b.append('['); - for (int x = 0; x < cleanArgs.length; x++) { - b.append(cleanArgs[x]); - if ("--accessToken".equalsIgnoreCase(cleanArgs[x])) { + int size = cleanArgs.size(); + for (int x = 0; x < size; x++) { + b.append(cleanArgs.get(x)); + if ("--accessToken".equalsIgnoreCase(cleanArgs.get(x))) { b.append(", {REDACTED}"); x++; } - if (x < cleanArgs.length - 1) + if (x < size - 1) b.append(", "); } b.append(']'); - LOGGER.info("Running with arguments: " + b.toString()); - + LOGGER.info("Running with arguments: " + b); Class cls = Class.forName(mainClass); Method main = cls.getDeclaredMethod("main", String[].class); - main.invoke(null, new Object[] { cleanArgs }); + main.invoke(null, new Object[] { cleanArgs.toArray(new String[0]) }); } protected void handleNatives(String path) { } @@ -92,7 +97,7 @@ protected Map getDefaultArguments() { return new LinkedHashMap<>(); } - private String[] parseArgs(String[] args) { + private List parseArgs(String[] args) { final Map defaults = getDefaultArguments(); final OptionParser parser = new OptionParser(); @@ -132,7 +137,7 @@ private String[] parseArgs(String[] args) { lst.addAll(extras); - return lst.toArray(new String[lst.size()]); + return lst; } protected String getenv(String name) { diff --git a/src/main/java/net/minecraftforge/legacydev/MainClient.java b/src/main/java/net/minecraftforge/legacydev/MainClient.java index e58d74b..9617e82 100644 --- a/src/main/java/net/minecraftforge/legacydev/MainClient.java +++ b/src/main/java/net/minecraftforge/legacydev/MainClient.java @@ -1,6 +1,6 @@ /* * LegacyDev - * Copyright (c) 2016-2020. + * Copyright (c) 2016-2023. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public diff --git a/src/main/java/net/minecraftforge/legacydev/MainServer.java b/src/main/java/net/minecraftforge/legacydev/MainServer.java index 33b78ce..1b415a1 100644 --- a/src/main/java/net/minecraftforge/legacydev/MainServer.java +++ b/src/main/java/net/minecraftforge/legacydev/MainServer.java @@ -1,6 +1,6 @@ /* * LegacyDev - * Copyright (c) 2016-2020. + * Copyright (c) 2016-2023. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public