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>
|
||||
<groupId>info.picocli</groupId>
|
||||
<artifactId>picocli</artifactId>
|
||||
<version>2.2.0</version>
|
||||
<version>4.7.7</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
|
|
@ -22,9 +22,6 @@ public class FTLModManager {
|
|||
|
||||
public static final String APP_NAME = "Slipstream Mod Manager";
|
||||
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) {
|
||||
// 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.start();
|
||||
|
||||
FileAppender<ILoggingEvent> fileAppender = new FileAppender<ILoggingEvent>();
|
||||
FileAppender<ILoggingEvent> fileAppender = new FileAppender<>();
|
||||
fileAppender.setContext(lc);
|
||||
fileAppender.setName("LogFile");
|
||||
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("VM: {}, {}, {}", System.getProperty("java.vm.name"), System.getProperty("java.version"), System.getProperty("os.arch"));
|
||||
|
||||
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
|
||||
@Override
|
||||
public void uncaughtException( Thread t, Throwable e ) {
|
||||
log.error("Uncaught exception in thread: {}", t.toString(), e);
|
||||
}
|
||||
});
|
||||
Thread.setDefaultUncaughtExceptionHandler((t, 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,11 +13,7 @@ import java.util.zip.ZipEntry;
|
|||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import picocli.CommandLine;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.IVersionProvider;
|
||||
import picocli.CommandLine.Option;
|
||||
import picocli.CommandLine.ParameterException;
|
||||
import picocli.CommandLine.Parameters;
|
||||
import picocli.CommandLine.*;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -53,330 +49,351 @@ public class SlipstreamCLI {
|
|||
System.exit(1);
|
||||
};
|
||||
|
||||
SlipstreamCommand slipstreamCmd = new SlipstreamCommand();
|
||||
CommandLine commandLine = new CommandLine( slipstreamCmd );
|
||||
try {
|
||||
commandLine.parse( args );
|
||||
}
|
||||
catch ( ParameterException e ) {
|
||||
//For multiple subcommands, e.getCommandLine() returns the one that failed.
|
||||
CommandLine commandLine = new CommandLine(new BaseCommand())
|
||||
.addSubcommand("start", new StartCommand())
|
||||
.addSubcommand("patch", new PatchCommand())
|
||||
.addSubcommand("list", new ListCommand())
|
||||
.addSubcommand("clean", new CleanCommand());
|
||||
|
||||
System.err.println( "Error parsing commandline: "+ e.getMessage() );
|
||||
System.exit( 1 );
|
||||
commandLine.execute(args);
|
||||
|
||||
// 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() ) {
|
||||
commandLine.usage( System.out );
|
||||
System.exit( 0 );
|
||||
}
|
||||
if ( commandLine.isVersionHelpRequested() ) {
|
||||
commandLine.printVersionHelp( System.out );
|
||||
System.exit( 0 );
|
||||
}
|
||||
// private static ActionFlow getCommandAction(CommandLine commandLine) {
|
||||
// if (commandLine.isUsageHelpRequested()) {
|
||||
// return ActionFlow.HELP;
|
||||
// }
|
||||
// if (commandLine.isVersionHelpRequested()) {
|
||||
// return ActionFlow.VERSION;
|
||||
// }
|
||||
//
|
||||
// return null;
|
||||
// }
|
||||
|
||||
if ( slipstreamCmd.validate ) {
|
||||
boolean success = validate(slipstreamCmd.modFileNames);
|
||||
System.exit( success ? 0 : 1);
|
||||
}
|
||||
// private static void extractDatsDir(RunCommand 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(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" );
|
||||
SlipstreamConfig appConfig = new SlipstreamConfig( configFile );
|
||||
// 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;
|
||||
// }
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
// /**
|
||||
// * 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(
|
||||
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,
|
||||
sortOptions = false,
|
||||
description = "Perform actions against an FTL installation and/or a list of named mods.",
|
||||
footer = "%nIf a named mod is a directory, a temporary zip will be created.",
|
||||
description = "Creates and starts a patched version of FTL.",
|
||||
versionProvider = SlipstreamVersionProvider.class
|
||||
)
|
||||
public static class SlipstreamCommand {
|
||||
@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;
|
||||
|
||||
public static class StartCommand implements Runnable {
|
||||
@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 {
|
||||
|
@ -512,15 +707,7 @@ public class SlipstreamCLI {
|
|||
}
|
||||
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
private record ModAndDirFileFilter(boolean allowZip, boolean allowDirs) implements FileFilter {
|
||||
|
||||
@Override
|
||||
public boolean accept(File f) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue