package de.geolykt.starloader.launcher;
import java.io.IOException;
import java.io.Reader;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.CodeSource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.LoggerFactory;
import org.stianloader.micromixin.transform.api.MixinTransformer;
import org.stianloader.micromixin.transform.api.supertypes.ClassWrapperPool;
import net.minestom.server.extras.selfmodification.HierarchyClassLoader;
import net.minestom.server.extras.selfmodification.MinestomRootClassLoader;
import de.geolykt.starloader.mod.DirectoryExtensionPrototypeList;
import de.geolykt.starloader.mod.ExtensionPrototype;
import de.geolykt.starloader.mod.NamedExtensionPrototype;
import de.geolykt.starloader.transformers.StarplaneAnnotationsInlineTransformer;
import de.geolykt.starloader.util.JavaInterop;
/**
* An entrypoint that is meant for debugging SLL mods within an IDE.
* As such it heavily relies on system properties in order to work. The following properties
* are used by this class:
*
*
*
de.geolykt.starloader.launcher.CLILauncher.mainClass: The main class to run after the launcher initialized fully (for galimulator it is com.example.Main).
*
de.geolykt.starloader.launcher.IDELauncher.bootURLs: A JSON-array of URLs to add to the root classloader.
*
de.geolykt.starloader.launcher.IDELauncher.modURLs: A JSON-array of JSON-arrays that specify the URLs used for each mod. That is each array is it's own mod "unit" and may point to a directory or a JAR-file. Mods from the specified mod directory will also be added, should the mod directory be defined via a system property.
*
de.geolykt.starloader.launcher.IDELauncher.modDirectory: Fully qualified path to the mod directory to use.
*
de.geolykt.starloader.launcher.IDELauncher.inlineStarplaneAnnotations: Whether the {@link StarplaneAnnotationsInlineTransformer} should be used.
*
org.stianloader.sll.IDELauncher.propertyExpansionSource (optional): The path to a .properties file from which property expansions within the extension.json file should occur. Only affects mods declared via the 'modURLs' system property.
*
org.stianloader.sll.IDELauncher.smapURIAliases (optional, micromixin exclusive): A JSON-encoded map which maps the {@link CodeSource} URI of classes as they appear on the classpath to the URI as is used by micromixin for generating SMAPs. There is probably no good reason to have this, but perhaps you can find a good use for it.
*
*
* @since 4.0.0
*/
public class IDELauncher {
public static void main(String[] args) {
String mainClass = System.getProperty("de.geolykt.starloader.launcher.CLILauncher.mainClass");
if (mainClass == null) {
LoggerFactory.getLogger(IDELauncher.class).warn("Main class not set! Falling back to com.example.Main");
mainClass = "com.example.Main";
}
String modDirectory = System.getProperty("de.geolykt.starloader.launcher.IDELauncher.modDirectory");
String modURLs = System.getProperty("de.geolykt.starloader.launcher.IDELauncher.modURLs");
if (modURLs == null) {
if (modDirectory == null) {
LoggerFactory.getLogger(IDELauncher.class).error("Unable to find the URLs of mods. Cannot proceed!");
} else {
LoggerFactory.getLogger(IDELauncher.class).warn("Unable to find the URLs of mods.");
}
} else if (modDirectory == null) {
LoggerFactory.getLogger(IDELauncher.class).warn("Extension directory undefined.");
}
String bootURLs = System.getProperty("de.geolykt.starloader.launcher.IDELauncher.bootURLs");
if (bootURLs == null) {
LoggerFactory.getLogger(IDELauncher.class).error("Unable to find the URLs that need to be added to the root classloader. Cannot proceed!");
}
if ((modURLs == null && modDirectory == null) || bootURLs == null) {
throw new IllegalStateException("The modURLs and/or the bootURLs system property is not set.");
}
boolean inlineSPAnnotations = Boolean.getBoolean("de.geolykt.starloader.launcher.IDELauncher.inlineStarplaneAnnotations");
List bootPaths = new ArrayList<>();
List> mods = new ArrayList<>();
Map expansionProperties = null;
readExpansionProperties: {
String expansionPropertiesPath = System.getProperty("org.stianloader.sll.IDELauncher.propertyExpansionSource");
if (expansionPropertiesPath == null) {
break readExpansionProperties;
}
Path propertiesPath = Paths.get(expansionPropertiesPath);
if (Files.notExists(propertiesPath)) {
LoggerFactory.getLogger(IDELauncher.class).error("The propertyExpansionSource system property points to a non-existent file: '{}'", propertiesPath);
break readExpansionProperties;
}
Properties properties = new Properties();
try (Reader reader = Files.newBufferedReader(propertiesPath, StandardCharsets.UTF_8)) {
properties.load(reader);
} catch (IOException e) {
LoggerFactory.getLogger(IDELauncher.class).error("Cannot read properties clared by the propertyExpansionSource system property defined as path '{}'", propertiesPath, e);
break readExpansionProperties;
}
expansionProperties = new HashMap<>();
for (Map.Entry