drafted out commands
This commit is contained in:
parent
0f138f61a8
commit
8ffdd5556b
3 changed files with 585 additions and 410 deletions
2
pom.xml
2
pom.xml
|
@ -67,7 +67,7 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>info.picocli</groupId>
|
<groupId>info.picocli</groupId>
|
||||||
<artifactId>picocli</artifactId>
|
<artifactId>picocli</artifactId>
|
||||||
<version>2.2.0</version>
|
<version>4.7.7</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
|
|
@ -22,9 +22,6 @@ public class FTLModManager {
|
||||||
|
|
||||||
public static final String APP_NAME = "Slipstream Mod Manager";
|
public static final String APP_NAME = "Slipstream Mod Manager";
|
||||||
public static final ComparableVersion APP_VERSION = new ComparableVersion("1.9.1");
|
public static final ComparableVersion APP_VERSION = new ComparableVersion("1.9.1");
|
||||||
public static final String APP_URL = "TODO";
|
|
||||||
public static final String APP_AUTHOR = "jan-leila";
|
|
||||||
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
// Redirect any libraries' java.util.Logging messages.
|
// Redirect any libraries' java.util.Logging messages.
|
||||||
|
@ -43,7 +40,7 @@ public class FTLModManager {
|
||||||
encoder.setPattern("%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n");
|
encoder.setPattern("%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n");
|
||||||
encoder.start();
|
encoder.start();
|
||||||
|
|
||||||
FileAppender<ILoggingEvent> fileAppender = new FileAppender<ILoggingEvent>();
|
FileAppender<ILoggingEvent> fileAppender = new FileAppender<>();
|
||||||
fileAppender.setContext(lc);
|
fileAppender.setContext(lc);
|
||||||
fileAppender.setName("LogFile");
|
fileAppender.setName("LogFile");
|
||||||
fileAppender.setFile(new File("./modman-log.txt").getAbsolutePath());
|
fileAppender.setFile(new File("./modman-log.txt").getAbsolutePath());
|
||||||
|
@ -59,17 +56,8 @@ public class FTLModManager {
|
||||||
log.debug("OS: {} {}", System.getProperty("os.name"), System.getProperty("os.version"));
|
log.debug("OS: {} {}", System.getProperty("os.name"), System.getProperty("os.version"));
|
||||||
log.debug("VM: {}, {}, {}", System.getProperty("java.vm.name"), System.getProperty("java.version"), System.getProperty("os.arch"));
|
log.debug("VM: {}, {}, {}", System.getProperty("java.vm.name"), System.getProperty("java.version"), System.getProperty("os.arch"));
|
||||||
|
|
||||||
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
|
Thread.setDefaultUncaughtExceptionHandler((t, e) -> log.error("Uncaught exception in thread: {}", t.toString(), e));
|
||||||
@Override
|
|
||||||
public void uncaughtException( Thread t, Throwable e ) {
|
|
||||||
log.error("Uncaught exception in thread: {}", t.toString(), e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (args.length == 0 ) {
|
|
||||||
System.out.println("Project called with no arguments.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
SlipstreamCLI.main(args);
|
SlipstreamCLI.main(args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,11 +13,7 @@ import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipOutputStream;
|
import java.util.zip.ZipOutputStream;
|
||||||
|
|
||||||
import picocli.CommandLine;
|
import picocli.CommandLine;
|
||||||
import picocli.CommandLine.Command;
|
import picocli.CommandLine.*;
|
||||||
import picocli.CommandLine.IVersionProvider;
|
|
||||||
import picocli.CommandLine.Option;
|
|
||||||
import picocli.CommandLine.ParameterException;
|
|
||||||
import picocli.CommandLine.Parameters;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@ -53,330 +49,351 @@ public class SlipstreamCLI {
|
||||||
System.exit(1);
|
System.exit(1);
|
||||||
};
|
};
|
||||||
|
|
||||||
SlipstreamCommand slipstreamCmd = new SlipstreamCommand();
|
CommandLine commandLine = new CommandLine(new BaseCommand())
|
||||||
CommandLine commandLine = new CommandLine( slipstreamCmd );
|
.addSubcommand("start", new StartCommand())
|
||||||
try {
|
.addSubcommand("patch", new PatchCommand())
|
||||||
commandLine.parse( args );
|
.addSubcommand("list", new ListCommand())
|
||||||
}
|
.addSubcommand("clean", new CleanCommand());
|
||||||
catch ( ParameterException e ) {
|
|
||||||
//For multiple subcommands, e.getCommandLine() returns the one that failed.
|
|
||||||
|
|
||||||
System.err.println( "Error parsing commandline: "+ e.getMessage() );
|
commandLine.execute(args);
|
||||||
System.exit( 1 );
|
|
||||||
|
// try {
|
||||||
|
// commandLine.parse(args);
|
||||||
|
// }
|
||||||
|
// catch (ParameterException e) {
|
||||||
|
// //For multiple subcommands, e.getCommandLine() returns the one that failed.
|
||||||
|
//
|
||||||
|
// System.err.println("Error parsing commandline: "+ e.getMessage());
|
||||||
|
// System.exit(1);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// ActionFlow actionFlow = getCommandAction(commandLine);
|
||||||
|
//
|
||||||
|
// switch (actionFlow) {
|
||||||
|
// case VERSION -> {
|
||||||
|
// commandLine.usage(System.out);
|
||||||
|
// System.exit(0);
|
||||||
|
// }
|
||||||
|
// case HELP -> {
|
||||||
|
// commandLine.printVersionHelp(System.out);
|
||||||
|
// System.exit(0);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (slipstreamCmd.validate) {
|
||||||
|
// boolean success = validate(slipstreamCmd.modFileNames);
|
||||||
|
// System.exit(success ? 0 : 1);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// File configFile = new File("modman.cfg");
|
||||||
|
// SlipstreamConfig appConfig = new SlipstreamConfig(configFile);
|
||||||
|
//
|
||||||
|
// if (slipstreamCmd.listMods) {
|
||||||
|
// listMods(appConfig);
|
||||||
|
// System.exit(0);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// File datsDir = null;
|
||||||
|
// if (slipstreamCmd.extractDatsDir != null ||
|
||||||
|
// slipstreamCmd.patch ||
|
||||||
|
// slipstreamCmd.runftl) {
|
||||||
|
// datsDir = getDatsDir(appConfig);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (slipstreamCmd.extractDatsDir != null) {
|
||||||
|
// extractDatsDir(slipstreamCmd, datsDir);
|
||||||
|
// System.exit(0);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (slipstreamCmd.patch) {
|
||||||
|
// boolean success = patch(slipstreamCmd, datsDir);
|
||||||
|
// if (!success) {
|
||||||
|
// System.exit(1);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (slipstreamCmd.runftl) {
|
||||||
|
// boolean success = runFtl(appConfig, datsDir);
|
||||||
|
// System.exit(success ? 0: 1);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// System.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( commandLine.isUsageHelpRequested() ) {
|
// private static ActionFlow getCommandAction(CommandLine commandLine) {
|
||||||
commandLine.usage( System.out );
|
// if (commandLine.isUsageHelpRequested()) {
|
||||||
System.exit( 0 );
|
// return ActionFlow.HELP;
|
||||||
}
|
// }
|
||||||
if ( commandLine.isVersionHelpRequested() ) {
|
// if (commandLine.isVersionHelpRequested()) {
|
||||||
commandLine.printVersionHelp( System.out );
|
// return ActionFlow.VERSION;
|
||||||
System.exit( 0 );
|
// }
|
||||||
}
|
//
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
|
|
||||||
if ( slipstreamCmd.validate ) {
|
// private static void extractDatsDir(RunCommand slipstreamCmd, File datsDir) {
|
||||||
boolean success = validate(slipstreamCmd.modFileNames);
|
// log.info("Extracting dats...");
|
||||||
System.exit( success ? 0 : 1);
|
//
|
||||||
}
|
// File extractDir = slipstreamCmd.extractDatsDir;
|
||||||
|
//
|
||||||
|
// FolderPack dstPack = null;
|
||||||
|
// List<AbstractPack> srcPacks = new ArrayList<AbstractPack>(2);
|
||||||
|
// InputStream is = null;
|
||||||
|
// try {
|
||||||
|
// File ftlDatFile = new File(datsDir, "ftl.dat");
|
||||||
|
// File dataDatFile = new File(datsDir, "data.dat");
|
||||||
|
// File resourceDatFile = new File(datsDir, "resource.dat");
|
||||||
|
//
|
||||||
|
// if (ftlDatFile.exists()) { // FTL 1.6.1.
|
||||||
|
// AbstractPack ftlPack = new PkgPack(ftlDatFile, "r");
|
||||||
|
// srcPacks.add(ftlPack);
|
||||||
|
// }
|
||||||
|
// else if (dataDatFile.exists() && resourceDatFile.exists()) { // FTL 1.01-1.5.13.
|
||||||
|
// AbstractPack dataPack = new FTLPack(dataDatFile, "r");
|
||||||
|
// AbstractPack resourcePack = new FTLPack(resourceDatFile, "r");
|
||||||
|
// srcPacks.add(dataPack);
|
||||||
|
// srcPacks.add(resourcePack);
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// throw new FileNotFoundException(String.format("Could not find either \"%s\" or both \"%s\" and \"%s\"", ftlDatFile.getName(), dataDatFile.getName(), resourceDatFile.getName()));
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (!extractDir.exists()) {
|
||||||
|
// boolean success = extractDir.mkdirs();
|
||||||
|
// if (success) {
|
||||||
|
// log.error("Error extracting dats");
|
||||||
|
// System.exit(1);
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// dstPack = new FolderPack(extractDir);
|
||||||
|
//
|
||||||
|
// for (AbstractPack srcPack : srcPacks) {
|
||||||
|
// List<String> innerPaths = srcPack.list();
|
||||||
|
//
|
||||||
|
// for (String innerPath : innerPaths) {
|
||||||
|
// if (dstPack.contains(innerPath)) {
|
||||||
|
// log.info("While extracting resources, this file was overwritten: "+ innerPath);
|
||||||
|
// dstPack.remove(innerPath);
|
||||||
|
// }
|
||||||
|
// is = srcPack.getInputStream(innerPath);
|
||||||
|
// dstPack.add(innerPath, is);
|
||||||
|
// }
|
||||||
|
// srcPack.close();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// catch (IOException e) {
|
||||||
|
// log.error("Error extracting dats", e);
|
||||||
|
// System.exit(1);
|
||||||
|
// }
|
||||||
|
// finally {
|
||||||
|
// try {if (is != null) is.close();}
|
||||||
|
// catch (IOException ignored) {}
|
||||||
|
//
|
||||||
|
// try {if (dstPack != null) dstPack.close();}
|
||||||
|
// catch (IOException ignored) {}
|
||||||
|
//
|
||||||
|
// for (AbstractPack pack : srcPacks) {
|
||||||
|
// try {pack.close();}
|
||||||
|
// catch (IOException ignored) {}
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private static boolean patch(RunCommand slipstreamCmd, File datsDir) {
|
||||||
|
// log.info("Patching...");
|
||||||
|
//
|
||||||
|
// DelayedDeleteHook deleteHook = new DelayedDeleteHook();
|
||||||
|
// Runtime.getRuntime().addShutdownHook(deleteHook);
|
||||||
|
//
|
||||||
|
// List<File> modFiles = new ArrayList<File>();
|
||||||
|
// if (slipstreamCmd.modFileNames != null) {
|
||||||
|
// for (String modFileName : slipstreamCmd.modFileNames) {
|
||||||
|
// File modFile = new File(modsDir, modFileName);
|
||||||
|
//
|
||||||
|
// if (modFile.isDirectory()) {
|
||||||
|
// log.info("Zipping dir: {}/", modFile.getName());
|
||||||
|
// try {
|
||||||
|
// modFile = createTempMod(modFile);
|
||||||
|
// deleteHook.addDoomedFile(modFile);
|
||||||
|
// }
|
||||||
|
// catch (IOException e) {
|
||||||
|
// log.error("Error zipping dir: {}/", modFile.getName(), e);
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// modFiles.add(modFile);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// boolean globalPanic = slipstreamCmd.globalPanic;
|
||||||
|
//
|
||||||
|
// SilentPatchObserver patchObserver = new SilentPatchObserver();
|
||||||
|
// ModPatchThread patchThread = new ModPatchThread(modFiles, datsDir, backupDir, globalPanic, patchObserver);
|
||||||
|
// Thread.setDefaultUncaughtExceptionHandler(exceptionHandler);
|
||||||
|
// deleteHook.addWatchedThread(patchThread);
|
||||||
|
//
|
||||||
|
// patchThread.start();
|
||||||
|
// while (patchThread.isAlive()) {
|
||||||
|
// try {patchThread.join();}
|
||||||
|
// catch (InterruptedException ignored) {}
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return patchObserver.hasSucceeded();
|
||||||
|
// }
|
||||||
|
|
||||||
File configFile = new File( "modman.cfg" );
|
// private static boolean validate(String[] modFileNames) {
|
||||||
SlipstreamConfig appConfig = new SlipstreamConfig( configFile );
|
// DelayedDeleteHook deleteHook = new DelayedDeleteHook();
|
||||||
|
// Runtime.getRuntime().addShutdownHook(deleteHook);
|
||||||
|
//
|
||||||
|
// log.info("Validating...");
|
||||||
|
//
|
||||||
|
// StringBuilder resultBuf = new StringBuilder();
|
||||||
|
// ReportFormatter formatter = new ReportFormatter();
|
||||||
|
// boolean anyInvalid = false;
|
||||||
|
//
|
||||||
|
// for (String modFileName : modFileNames) {
|
||||||
|
// File modFile = new File(modsDir, modFileName);
|
||||||
|
//
|
||||||
|
// if (modFile.isDirectory()) {
|
||||||
|
// log.info("Zipping dir: {}/", modFile.getName());
|
||||||
|
// try {
|
||||||
|
// modFile = createTempMod(modFile);
|
||||||
|
// deleteHook.addDoomedFile(modFile);
|
||||||
|
// }
|
||||||
|
// catch (IOException e) {
|
||||||
|
// log.error("Error zipping dir: {}/", modFile.getName(), e);
|
||||||
|
//
|
||||||
|
// List<ReportMessage> tmpMessages = new ArrayList<ReportMessage>();
|
||||||
|
// tmpMessages.add(new ReportMessage(ReportMessage.SECTION, modFileName));
|
||||||
|
// tmpMessages.add(new ReportMessage(ReportMessage.EXCEPTION, e.getMessage()));
|
||||||
|
//
|
||||||
|
// formatter.format(tmpMessages, resultBuf, 0);
|
||||||
|
// resultBuf.append("\n");
|
||||||
|
//
|
||||||
|
// anyInvalid = true;
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Report validateReport = ModUtilities.validateModFile(modFile);
|
||||||
|
//
|
||||||
|
// formatter.format(validateReport.messages, resultBuf, 0);
|
||||||
|
// resultBuf.append("\n");
|
||||||
|
//
|
||||||
|
// if (!validateReport.outcome) anyInvalid = true;
|
||||||
|
// }
|
||||||
|
// if (resultBuf.isEmpty()) {
|
||||||
|
// resultBuf.append("No mods were checked.");
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// System.out.println();
|
||||||
|
// System.out.println(resultBuf);
|
||||||
|
// return !anyInvalid;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private static void listMods(SlipstreamConfig appConfig) {
|
||||||
|
// log.info("Listing mods...");
|
||||||
|
//
|
||||||
|
// boolean allowZip = appConfig.getProperty(SlipstreamConfig.ALLOW_ZIP, "false").equals("true");
|
||||||
|
// File[] modFiles = modsDir.listFiles(new ModAndDirFileFilter(allowZip, true));
|
||||||
|
// List<String> dirList = new ArrayList<>();
|
||||||
|
// List<String> fileList = new ArrayList<>();
|
||||||
|
// assert modFiles != null;
|
||||||
|
// for (File f : modFiles) {
|
||||||
|
// if (f.isDirectory())
|
||||||
|
// dirList.add(f.getName() +"/");
|
||||||
|
// else
|
||||||
|
// fileList.add(f.getName());
|
||||||
|
// }
|
||||||
|
// Collections.sort(dirList);
|
||||||
|
// Collections.sort(fileList);
|
||||||
|
// for (String s : dirList) System.out.println(s);
|
||||||
|
// for (String s : fileList) System.out.println(s);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private static boolean runFtl(SlipstreamConfig appConfig, File datsDir) {
|
||||||
|
// log.info("Running FTL...");
|
||||||
|
//
|
||||||
|
// File exeFile = null;
|
||||||
|
// String[] exeArgs = null;
|
||||||
|
//
|
||||||
|
// // Try to run via Steam.
|
||||||
|
// if ("true".equals(appConfig.getProperty(SlipstreamConfig.RUN_STEAM_FTL, "false"))) {
|
||||||
|
//
|
||||||
|
// String steamPath = appConfig.getProperty(SlipstreamConfig.STEAM_EXE_PATH);
|
||||||
|
// if (!steamPath.isEmpty()) {
|
||||||
|
// exeFile = new File(steamPath);
|
||||||
|
//
|
||||||
|
// if (exeFile.exists()) {
|
||||||
|
// exeArgs = new String[] {"-applaunch", FTLUtilities.STEAM_APPID_FTL};
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// log.warn(String.format("%s does not exist: %s", SlipstreamConfig.STEAM_EXE_PATH, exeFile.getAbsolutePath()));
|
||||||
|
// exeFile = null;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (exeFile == null) {
|
||||||
|
// log.warn("Steam executable could not be found, so FTL will be launched directly");
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
// // Try to run directly.
|
||||||
|
// if (exeFile == null) {
|
||||||
|
// exeFile = FTLUtilities.findGameExe(datsDir);
|
||||||
|
//
|
||||||
|
// if (exeFile != null) {
|
||||||
|
// exeArgs = new String[0];
|
||||||
|
// } else {
|
||||||
|
// log.warn("FTL executable could not be found");
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (exeFile != null) {
|
||||||
|
// try {
|
||||||
|
// FTLUtilities.launchExe(exeFile, exeArgs);
|
||||||
|
// }
|
||||||
|
// catch (Exception e) {
|
||||||
|
// log.error("Error launching FTL", e);
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// log.error("No executables were found to launch FTL");
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
|
||||||
if ( slipstreamCmd.listMods ) {
|
// /**
|
||||||
listMods(appConfig);
|
// * Checks the validity of the config's dats path and returns it.
|
||||||
System.exit( 0 );
|
// * Or exits if the path is invalid.
|
||||||
}
|
// */
|
||||||
|
// private static File getDatsDir(SlipstreamConfig appConfig) {
|
||||||
File datsDir = null;
|
// File datsDir = null;
|
||||||
if ( slipstreamCmd.extractDatsDir != null ||
|
// String datsPath = appConfig.getProperty(SlipstreamConfig.FTL_DATS_PATH, "");
|
||||||
slipstreamCmd.patch ||
|
//
|
||||||
slipstreamCmd.runftl ) {
|
// if (!datsPath.isEmpty()) {
|
||||||
datsDir = getDatsDir( appConfig );
|
// log.info("Using FTL dats path from config: "+ datsPath);
|
||||||
}
|
// datsDir = new File(datsPath);
|
||||||
|
// if (!FTLUtilities.isDatsDirValid(datsDir)) {
|
||||||
if ( slipstreamCmd.extractDatsDir != null ) {
|
// log.error("The config's "+ SlipstreamConfig.FTL_DATS_PATH +" does not exist, or it is invalid");
|
||||||
extractDatsDir(slipstreamCmd, datsDir);
|
// datsDir = null;
|
||||||
System.exit( 0 );
|
// }
|
||||||
}
|
// }
|
||||||
|
// else {
|
||||||
if ( slipstreamCmd.patch ) {
|
// log.error("No FTL dats path previously set");
|
||||||
boolean success = patch(slipstreamCmd, datsDir);
|
// }
|
||||||
if (!success) {
|
// if (datsDir == null) {
|
||||||
System.exit( 1 );
|
// log.error("Run the GUI once, or edit the config file, and try again");
|
||||||
}
|
// System.exit(1);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
if ( slipstreamCmd.runftl ) {
|
// return datsDir;
|
||||||
boolean success = runFtl(appConfig, datsDir);
|
// }
|
||||||
System.exit(success ? 0 : 1 );
|
|
||||||
}
|
|
||||||
|
|
||||||
System.exit( 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void extractDatsDir(SlipstreamCommand slipstreamCmd, File datsDir) {
|
|
||||||
log.info( "Extracting dats..." );
|
|
||||||
|
|
||||||
File extractDir = slipstreamCmd.extractDatsDir;
|
|
||||||
|
|
||||||
FolderPack dstPack = null;
|
|
||||||
List<AbstractPack> srcPacks = new ArrayList<AbstractPack>( 2 );
|
|
||||||
InputStream is = null;
|
|
||||||
try {
|
|
||||||
File ftlDatFile = new File( datsDir, "ftl.dat" );
|
|
||||||
File dataDatFile = new File( datsDir, "data.dat" );
|
|
||||||
File resourceDatFile = new File( datsDir, "resource.dat" );
|
|
||||||
|
|
||||||
if ( ftlDatFile.exists() ) { // FTL 1.6.1.
|
|
||||||
AbstractPack ftlPack = new PkgPack( ftlDatFile, "r" );
|
|
||||||
srcPacks.add( ftlPack );
|
|
||||||
}
|
|
||||||
else if ( dataDatFile.exists() && resourceDatFile.exists() ) { // FTL 1.01-1.5.13.
|
|
||||||
AbstractPack dataPack = new FTLPack( dataDatFile, "r" );
|
|
||||||
AbstractPack resourcePack = new FTLPack( resourceDatFile, "r" );
|
|
||||||
srcPacks.add( dataPack );
|
|
||||||
srcPacks.add( resourcePack );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new FileNotFoundException( String.format( "Could not find either \"%s\" or both \"%s\" and \"%s\"", ftlDatFile.getName(), dataDatFile.getName(), resourceDatFile.getName() ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( !extractDir.exists() ) {
|
|
||||||
boolean success = extractDir.mkdirs();
|
|
||||||
if (success) {
|
|
||||||
log.error( "Error extracting dats");
|
|
||||||
System.exit( 1 );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
dstPack = new FolderPack( extractDir );
|
|
||||||
|
|
||||||
for ( AbstractPack srcPack : srcPacks ) {
|
|
||||||
List<String> innerPaths = srcPack.list();
|
|
||||||
|
|
||||||
for ( String innerPath : innerPaths ) {
|
|
||||||
if ( dstPack.contains( innerPath ) ) {
|
|
||||||
log.info( "While extracting resources, this file was overwritten: "+ innerPath );
|
|
||||||
dstPack.remove( innerPath );
|
|
||||||
}
|
|
||||||
is = srcPack.getInputStream( innerPath );
|
|
||||||
dstPack.add( innerPath, is );
|
|
||||||
}
|
|
||||||
srcPack.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch ( IOException e ) {
|
|
||||||
log.error( "Error extracting dats", e );
|
|
||||||
System.exit( 1 );
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
try {if ( is != null ) is.close();}
|
|
||||||
catch ( IOException ignored) {}
|
|
||||||
|
|
||||||
try {if ( dstPack != null ) dstPack.close();}
|
|
||||||
catch ( IOException ignored) {}
|
|
||||||
|
|
||||||
for ( AbstractPack pack : srcPacks ) {
|
|
||||||
try {pack.close();}
|
|
||||||
catch ( IOException ignored) {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean patch(SlipstreamCommand slipstreamCmd, File datsDir) {
|
|
||||||
log.info( "Patching..." );
|
|
||||||
|
|
||||||
DelayedDeleteHook deleteHook = new DelayedDeleteHook();
|
|
||||||
Runtime.getRuntime().addShutdownHook( deleteHook );
|
|
||||||
|
|
||||||
List<File> modFiles = new ArrayList<File>();
|
|
||||||
if ( slipstreamCmd.modFileNames != null ) {
|
|
||||||
for ( String modFileName : slipstreamCmd.modFileNames ) {
|
|
||||||
File modFile = new File( modsDir, modFileName );
|
|
||||||
|
|
||||||
if ( modFile.isDirectory() ) {
|
|
||||||
log.info("Zipping dir: {}/", modFile.getName());
|
|
||||||
try {
|
|
||||||
modFile = createTempMod( modFile );
|
|
||||||
deleteHook.addDoomedFile( modFile );
|
|
||||||
}
|
|
||||||
catch ( IOException e ) {
|
|
||||||
log.error("Error zipping dir: {}/", modFile.getName(), e);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
modFiles.add( modFile );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean globalPanic = slipstreamCmd.globalPanic;
|
|
||||||
|
|
||||||
SilentPatchObserver patchObserver = new SilentPatchObserver();
|
|
||||||
ModPatchThread patchThread = new ModPatchThread( modFiles, datsDir, backupDir, globalPanic, patchObserver );
|
|
||||||
Thread.setDefaultUncaughtExceptionHandler( exceptionHandler );
|
|
||||||
deleteHook.addWatchedThread( patchThread );
|
|
||||||
|
|
||||||
patchThread.start();
|
|
||||||
while ( patchThread.isAlive() ) {
|
|
||||||
try {patchThread.join();}
|
|
||||||
catch ( InterruptedException ignored) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
return patchObserver.hasSucceeded();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean validate(String[] modFileNames) {
|
|
||||||
DelayedDeleteHook deleteHook = new DelayedDeleteHook();
|
|
||||||
Runtime.getRuntime().addShutdownHook( deleteHook );
|
|
||||||
|
|
||||||
log.info( "Validating..." );
|
|
||||||
|
|
||||||
StringBuilder resultBuf = new StringBuilder();
|
|
||||||
ReportFormatter formatter = new ReportFormatter();
|
|
||||||
boolean anyInvalid = false;
|
|
||||||
|
|
||||||
for ( String modFileName : modFileNames ) {
|
|
||||||
File modFile = new File( modsDir, modFileName );
|
|
||||||
|
|
||||||
if ( modFile.isDirectory() ) {
|
|
||||||
log.info("Zipping dir: {}/", modFile.getName());
|
|
||||||
try {
|
|
||||||
modFile = createTempMod( modFile );
|
|
||||||
deleteHook.addDoomedFile( modFile );
|
|
||||||
}
|
|
||||||
catch ( IOException e ) {
|
|
||||||
log.error("Error zipping dir: {}/", modFile.getName(), e);
|
|
||||||
|
|
||||||
List<ReportMessage> tmpMessages = new ArrayList<ReportMessage>();
|
|
||||||
tmpMessages.add( new ReportMessage( ReportMessage.SECTION, modFileName ) );
|
|
||||||
tmpMessages.add( new ReportMessage( ReportMessage.EXCEPTION, e.getMessage() ) );
|
|
||||||
|
|
||||||
formatter.format( tmpMessages, resultBuf, 0 );
|
|
||||||
resultBuf.append( "\n" );
|
|
||||||
|
|
||||||
anyInvalid = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Report validateReport = ModUtilities.validateModFile( modFile );
|
|
||||||
|
|
||||||
formatter.format( validateReport.messages, resultBuf, 0 );
|
|
||||||
resultBuf.append( "\n" );
|
|
||||||
|
|
||||||
if (!validateReport.outcome) anyInvalid = true;
|
|
||||||
}
|
|
||||||
if (resultBuf.isEmpty()) {
|
|
||||||
resultBuf.append( "No mods were checked." );
|
|
||||||
}
|
|
||||||
|
|
||||||
System.out.println();
|
|
||||||
System.out.println(resultBuf);
|
|
||||||
return !anyInvalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void listMods(SlipstreamConfig appConfig) {
|
|
||||||
log.info( "Listing mods..." );
|
|
||||||
|
|
||||||
boolean allowZip = appConfig.getProperty( SlipstreamConfig.ALLOW_ZIP, "false" ).equals( "true" );
|
|
||||||
File[] modFiles = modsDir.listFiles( new ModAndDirFileFilter( allowZip, true ) );
|
|
||||||
List<String> dirList = new ArrayList<>();
|
|
||||||
List<String> fileList = new ArrayList<>();
|
|
||||||
assert modFiles != null;
|
|
||||||
for ( File f : modFiles ) {
|
|
||||||
if ( f.isDirectory() )
|
|
||||||
dirList.add( f.getName() +"/" );
|
|
||||||
else
|
|
||||||
fileList.add( f.getName() );
|
|
||||||
}
|
|
||||||
Collections.sort( dirList );
|
|
||||||
Collections.sort( fileList );
|
|
||||||
for ( String s : dirList ) System.out.println( s );
|
|
||||||
for ( String s : fileList ) System.out.println( s );
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean runFtl(SlipstreamConfig appConfig, File datsDir) {
|
|
||||||
log.info( "Running FTL..." );
|
|
||||||
|
|
||||||
File exeFile = null;
|
|
||||||
String[] exeArgs = null;
|
|
||||||
|
|
||||||
// Try to run via Steam.
|
|
||||||
if ( "true".equals( appConfig.getProperty( SlipstreamConfig.RUN_STEAM_FTL, "false" ) ) ) {
|
|
||||||
|
|
||||||
String steamPath = appConfig.getProperty( SlipstreamConfig.STEAM_EXE_PATH );
|
|
||||||
if (!steamPath.isEmpty()) {
|
|
||||||
exeFile = new File( steamPath );
|
|
||||||
|
|
||||||
if ( exeFile.exists() ) {
|
|
||||||
exeArgs = new String[] {"-applaunch", FTLUtilities.STEAM_APPID_FTL};
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
log.warn( String.format( "%s does not exist: %s", SlipstreamConfig.STEAM_EXE_PATH, exeFile.getAbsolutePath() ) );
|
|
||||||
exeFile = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( exeFile == null ) {
|
|
||||||
log.warn( "Steam executable could not be found, so FTL will be launched directly" );
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
// Try to run directly.
|
|
||||||
if ( exeFile == null ) {
|
|
||||||
exeFile = FTLUtilities.findGameExe( datsDir );
|
|
||||||
|
|
||||||
if ( exeFile != null ) {
|
|
||||||
exeArgs = new String[0];
|
|
||||||
} else {
|
|
||||||
log.warn( "FTL executable could not be found" );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( exeFile != null ) {
|
|
||||||
try {
|
|
||||||
FTLUtilities.launchExe( exeFile, exeArgs );
|
|
||||||
}
|
|
||||||
catch ( Exception e ) {
|
|
||||||
log.error( "Error launching FTL", e );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
log.error( "No executables were found to launch FTL" );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks the validity of the config's dats path and returns it.
|
|
||||||
* Or exits if the path is invalid.
|
|
||||||
*/
|
|
||||||
private static File getDatsDir( SlipstreamConfig appConfig ) {
|
|
||||||
File datsDir = null;
|
|
||||||
String datsPath = appConfig.getProperty( SlipstreamConfig.FTL_DATS_PATH, "" );
|
|
||||||
|
|
||||||
if (!datsPath.isEmpty()) {
|
|
||||||
log.info( "Using FTL dats path from config: "+ datsPath );
|
|
||||||
datsDir = new File( datsPath );
|
|
||||||
if (!FTLUtilities.isDatsDirValid(datsDir)) {
|
|
||||||
log.error( "The config's "+ SlipstreamConfig.FTL_DATS_PATH +" does not exist, or it is invalid" );
|
|
||||||
datsDir = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
log.error( "No FTL dats path previously set" );
|
|
||||||
}
|
|
||||||
if ( datsDir == null ) {
|
|
||||||
log.error( "Run the GUI once, or edit the config file, and try again" );
|
|
||||||
System.exit( 1 );
|
|
||||||
}
|
|
||||||
|
|
||||||
return datsDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -421,43 +438,221 @@ public class SlipstreamCLI {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Command(
|
||||||
|
name = "list",
|
||||||
|
description = "list all available mods"
|
||||||
|
)
|
||||||
|
public static class ListCommand implements Runnable {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
System.out.println("list command");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Command(
|
@Command(
|
||||||
name = "modman",
|
name = "patch",
|
||||||
|
description = "create a patched binary using the available mods"
|
||||||
|
)
|
||||||
|
public static class PatchCommand implements Runnable {
|
||||||
|
@Parameters(index = "0", description = "the location unpatched binary is located at")
|
||||||
|
File binary;
|
||||||
|
|
||||||
|
@Parameters(description = "list of mods that the binary will be patched with before it starts. (defaults to all mods if non are provided)", mapFallbackValue = Option.NULL_VALUE)
|
||||||
|
String mods;
|
||||||
|
|
||||||
|
@Option(names = "--dry", description = "skip the patching step but still run the rest of the application")
|
||||||
|
boolean dry;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
System.out.println("patch command");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command(
|
||||||
|
name = "clean",
|
||||||
|
description = "remove all patched binaries"
|
||||||
|
)
|
||||||
|
public static class CleanCommand implements Runnable {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
System.out.println("clean command");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command(
|
||||||
|
name = "install",
|
||||||
|
description = "install the slipstream mod manager"
|
||||||
|
)
|
||||||
|
public static class InstallCommand implements Runnable {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
System.out.println("install command");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command(
|
||||||
|
name = "uninstall",
|
||||||
|
description = "uninstall the slipstream mod manager"
|
||||||
|
)
|
||||||
|
public static class UninstallCommand implements Runnable {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
System.out.println("uninstall command");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command(
|
||||||
|
name = "start",
|
||||||
abbreviateSynopsis = true,
|
abbreviateSynopsis = true,
|
||||||
sortOptions = false,
|
sortOptions = false,
|
||||||
description = "Perform actions against an FTL installation and/or a list of named mods.",
|
description = "Creates and starts a patched version of FTL.",
|
||||||
footer = "%nIf a named mod is a directory, a temporary zip will be created.",
|
|
||||||
versionProvider = SlipstreamVersionProvider.class
|
versionProvider = SlipstreamVersionProvider.class
|
||||||
)
|
)
|
||||||
public static class SlipstreamCommand {
|
public static class StartCommand implements Runnable {
|
||||||
@Option(names = "--extract-dats", paramLabel = "DIR", description = "extract FTL resources into a dir")
|
|
||||||
File extractDatsDir;
|
|
||||||
|
|
||||||
@Option(names = "--global-panic", description = "patch as if advanced find tags had panic='true'")
|
|
||||||
boolean globalPanic;
|
|
||||||
|
|
||||||
@Option(names = "--list-mods", description = "list available mod names")
|
|
||||||
boolean listMods;
|
|
||||||
|
|
||||||
@Option(names = "--runftl", description = "run the game (standalone or with 'patch')")
|
|
||||||
boolean runftl;
|
|
||||||
|
|
||||||
@Option(names = "--patch", description = "revert to vanilla and add named mods (if any)")
|
|
||||||
boolean patch;
|
|
||||||
|
|
||||||
@Option(names = "--validate", description = "check named mods for problems")
|
|
||||||
boolean validate;
|
|
||||||
|
|
||||||
@Option(names = {"-h", "--help"}, usageHelp = true, description = "display this help and exit")
|
|
||||||
boolean helpRequested;
|
|
||||||
|
|
||||||
@Option(names = "--version", versionHelp = true, description = "output version information and exit")
|
@Option(names = "--version", versionHelp = true, description = "output version information and exit")
|
||||||
boolean versionRequested;
|
boolean isVersionCommand;
|
||||||
|
|
||||||
|
@Option(names = { "--game-folder", "--binary", "--data-folder" }, description = "the location of the game files", converter = GameDirectoryConverter.class, mapFallbackValue = Option.NULL_VALUE)
|
||||||
|
GameDirectory gameDirectory;
|
||||||
|
|
||||||
|
@Parameters(description = "list of mods that the binary will be patched with before it starts. (defaults to all mods if non are provided)", mapFallbackValue = Option.NULL_VALUE)
|
||||||
|
String[] mods;
|
||||||
|
|
||||||
|
@Option(names = "--dry", description = "skip the patching step but still run the rest of the application")
|
||||||
|
boolean dry;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
System.out.println("start command: " + gameDirectory.root.getAbsolutePath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class GameDirectoryConverter implements ITypeConverter<GameDirectory> {
|
||||||
|
|
||||||
|
private GameDirectory getGameDirectory(String fileName) {
|
||||||
|
if (fileName == null ) {
|
||||||
|
// TODO: get this from env variables
|
||||||
|
// TODO: if env variable not set check some common places and prompt the user if they want to use that
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return GameDirectory.createGameDirectory(new File(fileName));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GameDirectory convert(String fileName) {
|
||||||
|
GameDirectory gameDirectory = getGameDirectory(fileName);
|
||||||
|
if (gameDirectory == null) {
|
||||||
|
System.out.println("Game not found. Please specify the --game-folder argument, or set the FTL_GAME_FOLDER environment variable.");
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
return gameDirectory;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class GameDirectory {
|
||||||
|
|
||||||
|
private static final String GAME_FOLDER_NAME = "FTL Faster Than Light";
|
||||||
|
private static final String GAME_DATA_FOLDER_NAME = "data";
|
||||||
|
private static final String MODS_FOLDER_NAME = "mods";
|
||||||
|
private static final String BACKUP_FOLDER_NAME = "backup";
|
||||||
|
private static final String LAUNCH_SCRIPT_FILE_NAME = "FTL";
|
||||||
|
private static final String X86_BINARY_FILE_NAME = "FTL.x86";
|
||||||
|
|
||||||
|
private static boolean isValidGameDirectory(File gameDirectory) {
|
||||||
|
if (
|
||||||
|
!(
|
||||||
|
gameDirectory.exists()
|
||||||
|
&& gameDirectory.isDirectory()
|
||||||
|
&& gameDirectory.getName().equals(GAME_FOLDER_NAME)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
File gameDataFolder = new File(gameDirectory, GAME_DATA_FOLDER_NAME);
|
||||||
|
if (
|
||||||
|
!(
|
||||||
|
gameDataFolder.exists()
|
||||||
|
&& gameDataFolder.isDirectory()
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
File gameLaunchScript = new File(gameDataFolder, LAUNCH_SCRIPT_FILE_NAME);
|
||||||
|
if (
|
||||||
|
!(
|
||||||
|
gameLaunchScript.exists()
|
||||||
|
&& gameLaunchScript.isFile()
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: deal with FTL.amd64
|
||||||
|
File gameBinary = new File(gameDataFolder, X86_BINARY_FILE_NAME);
|
||||||
|
return gameBinary.exists() && gameBinary.isFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
static GameDirectory createGameDirectory(File file) {
|
||||||
|
if (file.isFile()) {
|
||||||
|
String filename = file.getName();
|
||||||
|
if (filename.equals(X86_BINARY_FILE_NAME)) {
|
||||||
|
File root = file.getParentFile().getParentFile();
|
||||||
|
if (isValidGameDirectory(root)) {
|
||||||
|
return new GameDirectory((root));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (file.isDirectory()){
|
||||||
|
if (isValidGameDirectory(file)) {
|
||||||
|
return new GameDirectory(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
String directoryName = file.getName();
|
||||||
|
if (directoryName.equals(GAME_DATA_FOLDER_NAME)) {
|
||||||
|
File root = file.getParentFile();
|
||||||
|
if (isValidGameDirectory(root)) {
|
||||||
|
return new GameDirectory((root));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final File root;
|
||||||
|
public final File dataDir;
|
||||||
|
public final File modsDir;
|
||||||
|
public final File backupDir;
|
||||||
|
public final File launchScript;
|
||||||
|
public final File binary;
|
||||||
|
|
||||||
|
GameDirectory(File root) {
|
||||||
|
this.root = root;
|
||||||
|
this.dataDir = new File(root, "data");
|
||||||
|
this.modsDir = new File(this.dataDir, "mods");
|
||||||
|
this.backupDir = new File(this.dataDir, "backup");
|
||||||
|
this.launchScript = new File(this.dataDir, "FTL");
|
||||||
|
// TODO: this should probably change when we need to use FTL.amd64 instead
|
||||||
|
this.binary = new File(this.dataDir, X86_BINARY_FILE_NAME);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command(name = "slipstream")
|
||||||
|
public static class BaseCommand implements Runnable {
|
||||||
|
@Option(names = {"-h", "--help"}, usageHelp = true, description = "display this help and exit")
|
||||||
|
boolean isHelpCommand;
|
||||||
|
|
||||||
|
@Spec
|
||||||
|
Model.CommandSpec spec;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
// if the command was invoked without subcommand, show the usage help
|
||||||
|
spec.commandLine().usage(System.err);
|
||||||
|
}
|
||||||
|
|
||||||
@Parameters(paramLabel = "MODFILE", description = "names of files or directories in the mods/ dir")
|
|
||||||
String[] modFileNames;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class SlipstreamVersionProvider implements IVersionProvider {
|
public static class SlipstreamVersionProvider implements IVersionProvider {
|
||||||
|
@ -512,15 +707,7 @@ public class SlipstreamCLI {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private record ModAndDirFileFilter(boolean allowZip, boolean allowDirs) implements FileFilter {
|
||||||
private static class ModAndDirFileFilter implements FileFilter {
|
|
||||||
private final boolean allowZip;
|
|
||||||
private final boolean allowDirs;
|
|
||||||
|
|
||||||
public ModAndDirFileFilter( boolean allowZip, boolean allowDirs ) {
|
|
||||||
this.allowZip = allowZip;
|
|
||||||
this.allowDirs = allowDirs;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean accept(File f) {
|
public boolean accept(File f) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue