gt:         return ret == null ? new File[0] : ret;
context: /*
   * Minecraft Forge
   * Copyright (c) 2016.
   *
   * 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.fml.relauncher;
  
  import java.io.Closeable;
  import java.io.File;
  import java.io.FileFilter;
  import java.io.FileInputStream;
  import java.io.IOException;
  import java.lang.reflect.Method;
  import java.net.MalformedURLException;
  import java.net.URL;
  import java.net.URLClassLoader;
  import java.security.cert.Certificate;
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.Calendar;
  import java.util.HashMap;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
  import java.util.function.ToIntFunction;
  import java.util.jar.Attributes;
  import java.util.jar.JarFile;
  import java.util.jar.Manifest;
  
  import net.minecraft.launchwrapper.ITweaker;
  import net.minecraft.launchwrapper.Launch;
  import net.minecraft.launchwrapper.LaunchClassLoader;
  import net.minecraftforge.fml.common.CertificateHelper;
  import net.minecraftforge.fml.common.FMLLog;
  import net.minecraftforge.fml.common.asm.ASMTransformerWrapper;
  import net.minecraftforge.fml.common.asm.transformers.ModAccessTransformer;
  import net.minecraftforge.fml.common.launcher.FMLInjectionAndSortingTweaker;
  import net.minecraftforge.fml.common.launcher.FMLTweaker;
  import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin.DependsOn;
  import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin.MCVersion;
  import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin.Name;
  import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin.SortingIndex;
  import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin.TransformerExclusions;
  import net.minecraftforge.fml.relauncher.libraries.Artifact;
  import net.minecraftforge.fml.relauncher.libraries.LibraryManager;
  import net.minecraftforge.fml.relauncher.libraries.Repository;
  
  import com.google.common.base.Strings;
  import com.google.common.collect.ImmutableList;
  import com.google.common.collect.Lists;
  import com.google.common.collect.Maps;
  import com.google.common.collect.ObjectArrays;
  import com.google.common.collect.Sets;
  import com.google.common.primitives.Ints;
  
  public class CoreModManager {
      private static final Attributes.Name COREMODCONTAINSFMLMOD = new Attributes.Name("FMLCorePluginContainsFMLMod");
      private static final Attributes.Name MODTYPE = new Attributes.Name("ModType");
      private static String[] rootPlugins = { "net.minecraftforge.fml.relauncher.FMLCorePlugin", "net.minecraftforge.classloading.FMLForgePlugin" };
      private static List<String> ignoredModFiles = Lists.newArrayList();
      private static Map<String, List<String>> transformers = Maps.newHashMap();
      private static List<FMLPluginWrapper> loadPlugins;
      private static boolean deobfuscatedEnvironment;
      private static FMLTweaker tweaker;
      private static File mcDir;
      private static List<String> candidateModFiles = Lists.newArrayList();
      private static List<String> accessTransformers = Lists.newArrayList();
      private static Set<String> rootNames = Sets.newHashSet();
  
      static
      {
          for(String cls : rootPlugins)
          {
              rootNames.add(cls.substring(cls.lastIndexOf('.') + 1));
          }
      }
  
      private static class FMLPluginWrapper implements ITweaker {
          public final String name;
          public final IFMLLoadingPlugin coreModInstance;
          public final List<String> predepends;
          public final File location;
          public final int sortIndex;
  
          public FMLPluginWrapper(String name, IFMLLoadingPlugin coreModInstance, File location, int sortIndex, String... predepends)
          {
              super();
              this.name = name;
              this.coreModInstance = coreModInstance;
              this.location = location;
              this.sortIndex = sortIndex;
              this.predepends = Lists.newArrayList(predepends);
          }
  
          @Override
          public String toString()
          {
              return String.format("%s {%s}", this.name, this.predepends);
          }
  
          @Override
          public void acceptOptions(List<String> args, File gameDir, File assetsDir, String profile)
          {
              // NO OP
          }
  
          @Override
          public void injectIntoClassLoader(LaunchClassLoader classLoader)
          {
              FMLLog.log.debug("Injecting coremod {} \\{{}\\} class transformers", name, coreModInstance.getClass().getName());
              List<String> ts = Lists.newArrayList();
              if (coreModInstance.getASMTransformerClass() != null) for (String transformer : coreModInstance.getASMTransformerClass())
              {
                  FMLLog.log.trace("Registering transformer {}", transformer);
                  classLoader.registerTransformer(ASMTransformerWrapper.getTransformerWrapper(classLoader, transformer, name));
                  ts.add(transformer);
              }
              if(!rootNames.contains(name))
              {
                  String loc;
                  if(location == null) loc = "unknown";
                  else loc = location.getName();
                  transformers.put(name + " (" + loc + ")", ts);
              }
              FMLLog.log.debug("Injection complete");
  
              FMLLog.log.debug("Running coremod plugin for {} \\{{}\\}", name, coreModInstance.getClass().getName());
              Map<String, Object> data = new HashMap<String, Object>();
              data.put("mcLocation", mcDir);
              data.put("coremodList", loadPlugins);
              data.put("runtimeDeobfuscationEnabled", !deobfuscatedEnvironment);
              FMLLog.log.debug("Running coremod plugin {}", name);
              data.put("coremodLocation", location);
              coreModInstance.injectData(data);
              String setupClass = coreModInstance.getSetupClass();
              if (setupClass != null)
              {
                  try
                  {
                      IFMLCallHook call = (IFMLCallHook) Class.forName(setupClass, true, classLoader).newInstance();
                      Map<String, Object> callData = new HashMap<String, Object>();
                      callData.put("runtimeDeobfuscationEnabled", !deobfuscatedEnvironment);
                      callData.put("mcLocation", mcDir);
                      callData.put("classLoader", classLoader);
                      callData.put("coremodLocation", location);
                      callData.put("deobfuscationFileName", FMLInjectionData.debfuscationDataName());
                      call.injectData(callData);
                      call.call();
                  }
                  catch (Exception e)
                  {
                      throw new RuntimeException(e);
                  }
              }
              FMLLog.log.debug("Coremod plugin class {} run successfully", coreModInstance.getClass().getSimpleName());
  
              String modContainer = coreModInstance.getModContainerClass();
              if (modContainer != null)
              {
                  FMLInjectionData.containers.add(modContainer);
              }
          }
  
          @Override
          public String getLaunchTarget()
          {
              return "";
          }
  
          @Override
          public String[] getLaunchArguments()
          {
              return new String[0];
          }
  
      }
  
      public static void handleLaunch(File mcDir, LaunchClassLoader classLoader, FMLTweaker tweaker)
      {
          CoreModManager.mcDir = mcDir;
          CoreModManager.tweaker = tweaker;
  
          //TODO: Detect this better? Support install time deobfusication? Decouple deobf from dev? Add dev flag in GradleStart?
          try
          {
              // Are we in a 'decompiled' environment?
              byte[] bs = classLoader.getClassBytes("net.minecraft.world.World");
              if (bs != null)
              {
                  FMLLog.log.info("Managed to load a deobfuscated Minecraft name- we are in a deobfuscated environment. Skipping runtime deobfuscation");
                  deobfuscatedEnvironment = true;
              }
          }
          catch (IOException e1)
          {
              // NOOP
          }
  
          if (!deobfuscatedEnvironment)
          {
              FMLLog.log.debug("Enabling runtime deobfuscation");
          }
  
          tweaker.injectCascadingTweak("net.minecraftforge.fml.common.launcher.FMLInjectionAndSortingTweaker");
          try
          {
              classLoader.registerTransformer("net.minecraftforge.fml.common.asm.transformers.PatchingTransformer");
          }
          catch (Exception e)
          {
              throw new RuntimeException("The patch transformer failed to load! This is critical, loading cannot continue!", e);
          }
  
          loadPlugins = new ArrayList<FMLPluginWrapper>();
          for (String rootPluginName : rootPlugins)
          {
              loadCoreMod(classLoader, rootPluginName, new File(FMLTweaker.getJarLocation()));
          }
  
          if (loadPlugins.isEmpty())
          {
              throw new RuntimeException("A fatal error has occurred - no valid fml load plugin was found - this is a completely corrupt FML installation.");
          }
  
          FMLLog.log.debug("All fundamental core mods are successfully located");
          // Now that we have the root plugins loaded - lets see what else might
          // be around
          String commandLineCoremods = System.getProperty("fml.coreMods.load", "");
          for (String coreModClassName : commandLineCoremods.split(","))
          {
              if (coreModClassName.isEmpty())
              {
                  continue;
              }
              FMLLog.log.info("Found a command line coremod : {}", coreModClassName);
              loadCoreMod(classLoader, coreModClassName, null);
          }
          discoverCoreMods(mcDir, classLoader);
  
      }
  
      private static void findDerpMods(LaunchClassLoader classLoader, File modDir, File modDirVer)
      {
          File[] derplist = listFiles(path -> path.getName().endsWith(".jar.zip"), modDir, modDirVer);
          if (derplist != null && derplist.length > 0)
          {
              FMLLog.log.fatal("FML has detected several badly downloaded jar files,  which have been named as zip files. You probably need to download them again, or they may not work properly");
              for (File f : derplist)
                  FMLLog.log.fatal("Problem file : {}", f.getName());
          }
  
          FileFilter derpdirfilter = pathname -> pathname.isDirectory() && new File(pathname,"META-INF").isDirectory();
          File[] derpdirlist = listFiles(derpdirfilter, modDir, modDirVer);
          if (derpdirlist != null && derpdirlist.length > 0)
          {
              FMLLog.log.fatal("There appear to be jars extracted into the mods directory. This is VERY BAD and will almost NEVER WORK WELL");
              FMLLog.log.fatal("You should place original jars only in the mods directory. NEVER extract them to the mods directory.");
              FMLLog.log.fatal("The directories below appear to be extracted jar files. Fix this before you continue.");
  
              for (File f : derpdirlist)
              {
                  FMLLog.log.fatal("Directory {} contains {}", f.getName(), Arrays.asList(new File(f,"META-INF").list()));
              }
  
              RuntimeException re = new RuntimeException("Extracted mod jars found, loading will NOT continue");
              // We're generating a crash report for the launcher to show to the user here
              // Does this actually work with the obfed names?
              try
              {
                  Class<?> crashreportclass = classLoader.loadClass("b");
                  Object crashreport = crashreportclass.getMethod("a", Throwable.class, String.class).invoke(null, re, "FML has discovered extracted jar files in the mods directory.\nThis breaks mod loading functionality completely.\nRemove the directories and replace with the jar files originally provided.");
                  File crashreportfile = new File(new File(modDir.getParentFile(),"crash-reports"),String.format("fml-crash-%1$tY-%1$tm-%1$td_%1$tH.%1$tM.%1$tS.txt",Calendar.getInstance()));
                  crashreportclass.getMethod("a",File.class).invoke(crashreport, crashreportfile);
                  FMLLog.log.fatal("#@!@# FML has crashed the game deliberately. Crash report saved to: #@!@# {}", crashreportfile.getAbsolutePath());
              } catch (Exception e)
              {
                  FMLLog.log.fatal("#@!@# FML has crashed while generating a crash report, please report this. #@!@#", e);
                  // NOOP - hopefully
              }
              throw re;
          }
      }
  
      private static File[] listFiles(FileFilter filter, File ... dirs)
      {
          File[] ret = null;
          for (File dir : dirs)
          {
              if (!dir.isDirectory() || !dir.exists())
                  continue;
              if (ret == null)
                  ret = dir.listFiles(filter);
              else
                  ret = ObjectArrays.concat(ret, dir.listFiles(filter), File.class);
          }
  