diff --git a/.envrc b/.envrc deleted file mode 100644 index 8392d15..0000000 --- a/.envrc +++ /dev/null @@ -1 +0,0 @@ -use flake \ No newline at end of file diff --git a/.gitignore b/.gitignore index 9ab7d63..2b925ad 100644 --- a/.gitignore +++ b/.gitignore @@ -5,19 +5,18 @@ target/ *.bak ~$* + # Windows image file caches Thumbs.db # Windows folder config file Desktop.ini + # Mac junk .DS_Store + # IdeaJ *.idea *.iml - -# enviroemnt packages -.direnv - diff --git a/flake.lock b/flake.lock deleted file mode 100644 index 353863f..0000000 --- a/flake.lock +++ /dev/null @@ -1,25 +0,0 @@ -{ - "nodes": { - "nixpkgs": { - "locked": { - "lastModified": 1754725699, - "narHash": "sha256-iAcj9T/Y+3DBy2J0N+yF9XQQQ8IEb5swLFzs23CdP88=", - "rev": "85dbfc7aaf52ecb755f87e577ddbe6dbbdbc1054", - "revCount": 841808, - "type": "tarball", - "url": "https://api.flakehub.com/f/pinned/NixOS/nixpkgs/0.1.841808%2Brev-85dbfc7aaf52ecb755f87e577ddbe6dbbdbc1054/01989280-4b63-70f9-95b3-49c511cb4d92/source.tar.gz" - }, - "original": { - "type": "tarball", - "url": "https://flakehub.com/f/NixOS/nixpkgs/0.1" - } - }, - "root": { - "inputs": { - "nixpkgs": "nixpkgs" - } - } - }, - "root": "root", - "version": 7 -} diff --git a/flake.nix b/flake.nix deleted file mode 100644 index 2951bbe..0000000 --- a/flake.nix +++ /dev/null @@ -1,69 +0,0 @@ -{ - description = "A Nix-flake-based Java development environment"; - - inputs.nixpkgs.url = "https://flakehub.com/f/NixOS/nixpkgs/0.1"; - - outputs = - inputs: - let - javaVersion = 17; - - supportedSystems = [ - "x86_64-linux" - "aarch64-linux" - "x86_64-darwin" - "aarch64-darwin" - ]; - forEachSupportedSystem = - f: - inputs.nixpkgs.lib.genAttrs supportedSystems ( - system: - f { - pkgs = import inputs.nixpkgs { - inherit system; - overlays = [ inputs.self.overlays.default ]; - }; - } - ); - in - { - overlays.default = - final: prev: - let - jdk = prev."jdk${toString javaVersion}"; - in - { - inherit jdk; - maven = prev.maven.override { jdk_headless = jdk; }; - gradle = prev.gradle.override { java = jdk; }; - lombok = prev.lombok.override { inherit jdk; }; - }; - - devShells = forEachSupportedSystem ( - { pkgs }: - { - default = pkgs.mkShell { - packages = with pkgs; [ - gcc - gradle - jdk - maven - ncurses - patchelf - zlib - ]; - - shellHook = - let - loadLombok = "-javaagent:${pkgs.lombok}/share/java/lombok.jar"; - prev = "\${JAVA_TOOL_OPTIONS:+ $JAVA_TOOL_OPTIONS}"; - in - '' - export JAVA_TOOL_OPTIONS="${loadLombok}${prev}" - ''; - }; - } - ); - }; -} - diff --git a/pom.xml b/pom.xml index 53264db..b235564 100644 --- a/pom.xml +++ b/pom.xml @@ -11,8 +11,8 @@ 1.6 - 21 - 21 + 1.6 + 1.6 UTF-8 diff --git a/shell.nix b/shell.nix deleted file mode 100644 index d7c46b9..0000000 --- a/shell.nix +++ /dev/null @@ -1,14 +0,0 @@ -( - import - ( - let - lock = builtins.fromJSON (builtins.readFile ./flake.lock); - in - fetchTarball { - url = lock.nodes.flake-compat.locked.url or "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz"; - sha256 = lock.nodes.flake-compat.locked.narHash; - } - ) - {src = ./.;} -) -.shellNix diff --git a/skel_unix/modman-cli.sh b/skel_unix/modman-cli.sh index 9c7124c..00104c8 100644 --- a/skel_unix/modman-cli.sh +++ b/skel_unix/modman-cli.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/bash # Get the absolute path to this script's folder. if echo "$0" | awk '{exit(!/^\//);}'; then diff --git a/skel_unix/modman.command b/skel_unix/modman.command index 3b63900..1381d8f 100644 --- a/skel_unix/modman.command +++ b/skel_unix/modman.command @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/bash # Get the script's name. me=$(basename "$0"); diff --git a/src/main/java/net/vhati/modmanager/FTLModManager.java b/src/main/java/net/vhati/modmanager/FTLModManager.java index c431262..b4fa76b 100644 --- a/src/main/java/net/vhati/modmanager/FTLModManager.java +++ b/src/main/java/net/vhati/modmanager/FTLModManager.java @@ -1,14 +1,19 @@ package net.vhati.modmanager; import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.io.InputStreamReader; import java.io.IOException; -import java.nio.charset.StandardCharsets; +import java.nio.charset.Charset; import java.util.Date; +import java.util.Properties; import javax.swing.JFileChooser; import javax.swing.JOptionPane; import javax.swing.LookAndFeel; import javax.swing.SwingUtilities; import javax.swing.UIManager; +import javax.swing.UIManager.LookAndFeelInfo; import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.classic.spi.ILoggingEvent; @@ -31,8 +36,8 @@ 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 final String APP_URL = "https://subsetgames.com/forum/viewtopic.php?f=12&t=17102"; + public static final String APP_AUTHOR = "Vhati"; public static void main( String[] args ) { @@ -48,7 +53,7 @@ public class FTLModManager { PatternLayoutEncoder encoder = new PatternLayoutEncoder(); encoder.setContext( lc ); - encoder.setCharset(StandardCharsets.UTF_8); + encoder.setCharset( Charset.forName( "UTF-8" ) ); encoder.setPattern( "%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n" ); encoder.start(); @@ -71,7 +76,7 @@ public class FTLModManager { Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { @Override public void uncaughtException( Thread t, Throwable e ) { - log.error("Uncaught exception in thread: {}", t.toString(), e); + log.error( "Uncaught exception in thread: "+ t.toString(), e ); } }); @@ -81,15 +86,20 @@ public class FTLModManager { } // Ensure all popups are triggered from the event dispatch thread. - SwingUtilities.invokeLater(FTLModManager::guiInit); + + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + guiInit(); + } + }); } private static void guiInit() { try { - // TODO: get mods file from env var // Nag if the jar was double-clicked. - if (!new File("./mods/").exists()) { + if ( new File( "./mods/" ).exists() == false ) { String currentPath = new File( "." ).getAbsoluteFile().getParentFile().getAbsolutePath(); log.error( String.format( "Slipstream could not find its own folder (Currently in \"%s\"), exiting...", currentPath ) ); @@ -98,13 +108,46 @@ public class FTLModManager { throw new ExitException(); } - // TODO: get config file from env var File configFile = new File( "modman.cfg" ); - SlipstreamConfig appConfig = new SlipstreamConfig(configFile); + boolean writeConfig = false; + Properties props = new Properties(); + props.setProperty( SlipstreamConfig.ALLOW_ZIP, "false" ); + props.setProperty( SlipstreamConfig.FTL_DATS_PATH, "" ); // Prompt. + props.setProperty( SlipstreamConfig.STEAM_DISTRO, "" ); // Prompt. + props.setProperty( SlipstreamConfig.STEAM_EXE_PATH, "" ); // Prompt. + props.setProperty( SlipstreamConfig.RUN_STEAM_FTL, "" ); // Prompt. + props.setProperty( SlipstreamConfig.NEVER_RUN_FTL, "false" ); + props.setProperty( SlipstreamConfig.UPDATE_CATALOG, "" ); // Prompt. + props.setProperty( SlipstreamConfig.UPDATE_APP, "" ); // Prompt. + props.setProperty( SlipstreamConfig.USE_DEFAULT_UI, "false" ); + props.setProperty( SlipstreamConfig.REMEMBER_GEOMETRY, "true" ); + // "manager_geometry" doesn't have a default. + + // Read the config file. + InputStream in = null; + try { + if ( configFile.exists() ) { + log.debug( "Loading config file" ); + in = new FileInputStream( configFile ); + props.load( new InputStreamReader( in, "UTF-8" ) ); + } else { + writeConfig = true; // Create a new cfg, but only if necessary. + } + } + catch ( IOException e ) { + log.error( "Error loading config", e ); + showErrorDialog( "Error loading config from "+ configFile.getPath() ); + } + finally { + try {if ( in != null ) in.close();} + catch ( IOException e ) {} + } + + SlipstreamConfig appConfig = new SlipstreamConfig( props, configFile ); // Look-and-Feel. - boolean useDefaultUI = Boolean.parseBoolean(appConfig.getProperty(SlipstreamConfig.USE_DEFAULT_UI, "false")); + boolean useDefaultUI = "true".equals( appConfig.getProperty( SlipstreamConfig.USE_DEFAULT_UI, "false" ) ); if ( !useDefaultUI ) { LookAndFeel defaultLaf = UIManager.getLookAndFeel(); @@ -114,7 +157,7 @@ public class FTLModManager { log.debug( "Setting system look and feel: "+ UIManager.getSystemLookAndFeelClassName() ); // SystemLaf is risky. It may throw an exception, or lead to graphical bugs. - // Problems are generally caused by custom Windows themes. + // Problems are geneally caused by custom Windows themes. UIManager.setLookAndFeel( UIManager.getSystemLookAndFeelClassName() ); } catch ( Exception e ) { @@ -122,6 +165,7 @@ public class FTLModManager { log.info( "Setting "+ SlipstreamConfig.USE_DEFAULT_UI +"=true in the config file to prevent this error..." ); appConfig.setProperty( SlipstreamConfig.USE_DEFAULT_UI, "true" ); + writeConfig = true; try { UIManager.setLookAndFeel( defaultLaf ); @@ -176,6 +220,7 @@ public class FTLModManager { if ( datsDir != null ) { appConfig.setProperty( SlipstreamConfig.FTL_DATS_PATH, datsDir.getAbsolutePath() ); + writeConfig = true; log.info( "FTL dats located at: "+ datsDir.getAbsolutePath() ); } } @@ -192,9 +237,11 @@ public class FTLModManager { int steamBasedResponse = JOptionPane.showConfirmDialog( null, "Was FTL installed via Steam?", "Confirm", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE ); if ( steamBasedResponse == JOptionPane.YES_OPTION ) { appConfig.setProperty( SlipstreamConfig.STEAM_DISTRO, "true" ); + writeConfig = true; } else { appConfig.setProperty( SlipstreamConfig.STEAM_DISTRO, "false" ); + writeConfig = true; } } @@ -248,6 +295,7 @@ public class FTLModManager { if ( steamExeFile != null ) { appConfig.setProperty( SlipstreamConfig.STEAM_EXE_PATH, steamExeFile.getAbsolutePath() ); + writeConfig = true; log.info( "Steam located at: "+ steamExeFile.getAbsolutePath() ); } } @@ -260,9 +308,11 @@ public class FTLModManager { int launchResponse = JOptionPane.showOptionDialog( null, "Would you prefer to launch FTL directly, or via Steam?", "How to Launch?", JOptionPane.DEFAULT_OPTION, JOptionPane.PLAIN_MESSAGE, null, launchOptions, launchOptions[1] ); if ( launchResponse == 0 ) { appConfig.setProperty( SlipstreamConfig.RUN_STEAM_FTL, "false" ); + writeConfig = true; } else if ( launchResponse == 1 ) { appConfig.setProperty( SlipstreamConfig.RUN_STEAM_FTL, "true" ); + writeConfig = true; } } } @@ -290,6 +340,18 @@ public class FTLModManager { appConfig.setProperty( SlipstreamConfig.UPDATE_CATALOG, "0" ); appConfig.setProperty( SlipstreamConfig.UPDATE_APP, "0" ); } + writeConfig = true; + } + + if ( writeConfig ) { + try { + appConfig.writeConfig(); + } + catch ( IOException e ) { + String errorMsg = String.format( "Error writing config to \"%s\"", configFile.getPath() ); + log.error( errorMsg, e ); + showErrorDialog( errorMsg ); + } } ManagerFrame frame = null; @@ -326,6 +388,8 @@ public class FTLModManager { JOptionPane.showMessageDialog( null, message, "Error", JOptionPane.ERROR_MESSAGE ); } + + private static class ExitException extends RuntimeException { public ExitException() { } diff --git a/src/main/java/net/vhati/modmanager/cli/SlipstreamCLI.java b/src/main/java/net/vhati/modmanager/cli/SlipstreamCLI.java index a10f407..3ad7f5b 100644 --- a/src/main/java/net/vhati/modmanager/cli/SlipstreamCLI.java +++ b/src/main/java/net/vhati/modmanager/cli/SlipstreamCLI.java @@ -51,6 +51,7 @@ public class SlipstreamCLI { private static Thread.UncaughtExceptionHandler exceptionHandler = null; + public static void main( String[] args ) { exceptionHandler = new Thread.UncaughtExceptionHandler() { @@ -82,117 +83,16 @@ public class SlipstreamCLI { 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 ); - } - - private static void extractDatsDir(SlipstreamCommand slipstreamCmd, File datsDir) { - log.info( "Extracting dats..." ); - - File extractDir = slipstreamCmd.extractDatsDir; - - FolderPack dstPack = null; - List srcPacks = new ArrayList( 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() ) extractDir.mkdirs(); - - dstPack = new FolderPack( extractDir ); - - for ( AbstractPack srcPack : srcPacks ) { - List 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 ex ) {} - - try {if ( dstPack != null ) dstPack.close();} - catch ( IOException ex ) {} - - for ( AbstractPack pack : srcPacks ) { - try {pack.close();} - catch ( IOException ex ) {} - } - } - } - - private static boolean patch(SlipstreamCommand slipstreamCmd, File datsDir) { - log.info( "Patching..." ); - DelayedDeleteHook deleteHook = new DelayedDeleteHook(); Runtime.getRuntime().addShutdownHook( deleteHook ); - List modFiles = new ArrayList(); - if ( slipstreamCmd.modFileNames != null ) { + if ( slipstreamCmd.validate ) { // Exits (0/1). + log.info( "Validating..." ); + + StringBuilder resultBuf = new StringBuilder(); + ReportFormatter formatter = new ReportFormatter(); + boolean anyInvalid = false; + for ( String modFileName : slipstreamCmd.modFileNames ) { File modFile = new File( modsDir, modFileName ); @@ -204,155 +104,270 @@ public class SlipstreamCLI { } catch ( IOException e ) { log.error( String.format( "Error zipping dir: %s/", modFile.getName() ), e ); - return false; + + List tmpMessages = new ArrayList(); + 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 == false ) anyInvalid = true; + } + if ( resultBuf.length() == 0 ) { + resultBuf.append( "No mods were checked." ); + } + + System.out.println(); + System.out.println( resultBuf.toString() ); + System.exit( anyInvalid ? 1 : 0 ); + } + + File configFile = new File( "modman.cfg" ); + SlipstreamConfig appConfig = getConfig( configFile ); + + if ( slipstreamCmd.listMods ) { // Exits. + log.info( "Listing mods..." ); + + boolean allowZip = appConfig.getProperty( SlipstreamConfig.ALLOW_ZIP, "false" ).equals( "true" ); + File[] modFiles = modsDir.listFiles( new ModAndDirFileFilter( allowZip, true ) ); + List dirList = new ArrayList(); + List fileList = new ArrayList(); + 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 ); + + System.exit( 0 ); + } + + File datsDir = null; + if ( slipstreamCmd.extractDatsDir != null || + slipstreamCmd.patch || + slipstreamCmd.runftl ) { + datsDir = getDatsDir( appConfig ); + } + + if ( slipstreamCmd.extractDatsDir != null ) { // Exits (0/1). + log.info( "Extracting dats..." ); + + File extractDir = slipstreamCmd.extractDatsDir; + + FolderPack dstPack = null; + List srcPacks = new ArrayList( 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() ) extractDir.mkdirs(); + + dstPack = new FolderPack( extractDir ); + + for ( AbstractPack srcPack : srcPacks ) { + List 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 ex ) {} + + try {if ( dstPack != null ) dstPack.close();} + catch ( IOException ex ) {} + + for ( AbstractPack pack : srcPacks ) { + try {pack.close();} + catch ( IOException ex ) {} + } + } + + System.exit( 0 ); + } + + if ( slipstreamCmd.patch ) { // Exits sometimes (1 on failure). + log.info( "Patching..." ); + + List modFiles = new ArrayList(); + for ( String modFileName : slipstreamCmd.modFileNames ) { + File modFile = new File( modsDir, modFileName ); + + if ( modFile.isDirectory() ) { + log.info( String.format( "Zipping dir: %s/", modFile.getName() ) ); + try { + modFile = createTempMod( modFile ); + deleteHook.addDoomedFile( modFile ); + } + catch ( IOException e ) { + log.error( String.format( "Error zipping dir: %s/", modFile.getName() ), e ); + System.exit( 1 ); } } modFiles.add( modFile ); } - } - boolean globalPanic = slipstreamCmd.globalPanic; + boolean globalPanic = slipstreamCmd.globalPanic; - SilentPatchObserver patchObserver = new SilentPatchObserver(); - ModPatchThread patchThread = new ModPatchThread( modFiles, datsDir, backupDir, globalPanic, patchObserver ); - patchThread.setDefaultUncaughtExceptionHandler( exceptionHandler ); - deleteHook.addWatchedThread( patchThread ); + SilentPatchObserver patchObserver = new SilentPatchObserver(); + ModPatchThread patchThread = new ModPatchThread( modFiles, datsDir, backupDir, globalPanic, patchObserver ); + patchThread.setDefaultUncaughtExceptionHandler( exceptionHandler ); + deleteHook.addWatchedThread( patchThread ); - patchThread.start(); - while ( patchThread.isAlive() ) { - try {patchThread.join();} - catch ( InterruptedException e ) {} - } - - if ( !patchObserver.hasSucceeded() ) return false; - return true; - } - - 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( String.format( "Zipping dir: %s/", modFile.getName() ) ); - try { - modFile = createTempMod( modFile ); - deleteHook.addDoomedFile( modFile ); - } - catch ( IOException e ) { - log.error( String.format( "Error zipping dir: %s/", modFile.getName() ), e ); - - List tmpMessages = new ArrayList(); - 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; - } + patchThread.start(); + while ( patchThread.isAlive() ) { + try {patchThread.join();} + catch ( InterruptedException e ) {} } - Report validateReport = ModUtilities.validateModFile( modFile ); - - formatter.format( validateReport.messages, resultBuf, 0 ); - resultBuf.append( "\n" ); - - if ( validateReport.outcome == false ) anyInvalid = true; - } - if ( resultBuf.length() == 0 ) { - resultBuf.append( "No mods were checked." ); + if ( !patchObserver.hasSucceeded() ) System.exit( 1 ); } - System.out.println(); - System.out.println(resultBuf); - return !anyInvalid; - } + if ( slipstreamCmd.runftl ) { // Exits (0/1). + log.info( "Running FTL..." ); - private static void listMods(SlipstreamConfig appConfig) { - log.info( "Listing mods..." ); + File exeFile = null; + String[] exeArgs = null; - boolean allowZip = appConfig.getProperty( SlipstreamConfig.ALLOW_ZIP, "false" ).equals( "true" ); - File[] modFiles = modsDir.listFiles( new ModAndDirFileFilter( allowZip, true ) ); - List dirList = new ArrayList(); - List fileList = new ArrayList(); - 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 ); - } + // Try to run via Steam. + if ( "true".equals( appConfig.getProperty( SlipstreamConfig.RUN_STEAM_FTL, "false" ) ) ) { - private static boolean runFtl(SlipstreamConfig appConfig, File datsDir) { - log.info( "Running FTL..." ); + String steamPath = appConfig.getProperty( SlipstreamConfig.STEAM_EXE_PATH ); + if ( steamPath.length() > 0 ) { + exeFile = new File( steamPath ); - 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.length() > 0 ) { - exeFile = new File( steamPath ); - - if ( exeFile.exists() ) { - exeArgs = new String[] {"-applaunch", FTLUtilities.STEAM_APPID_FTL}; + 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; + } } - 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 ) { - log.warn( "Steam executable could not be found, so FTL will be launched directly" ); - } + exeFile = FTLUtilities.findGameExe( datsDir ); - } - // 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 ) { - exeArgs = new String[0]; - } else { - log.warn( "FTL executable could not be found" ); + try { + FTLUtilities.launchExe( exeFile, exeArgs ); + } + catch ( Exception e ) { + log.error( "Error launching FTL", e ); + System.exit( 1 ); + } } + else { + log.error( "No executables were found to launch FTL" ); + System.exit( 1 ); + } + + System.exit( 0 ); } - 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; + System.exit( 0 ); } + + /** + * Loads settings from a config file. + * + * If an error occurs, it'll be logged, + * and default settings will be returned. + */ + private static SlipstreamConfig getConfig( File configFile ) { + + Properties props = new Properties(); + props.setProperty( SlipstreamConfig.ALLOW_ZIP, "false" ); + props.setProperty( SlipstreamConfig.FTL_DATS_PATH, "" ); + props.setProperty( SlipstreamConfig.STEAM_EXE_PATH, "" ); + props.setProperty( SlipstreamConfig.RUN_STEAM_FTL, "false" ); + props.setProperty( SlipstreamConfig.NEVER_RUN_FTL, "false" ); + props.setProperty( SlipstreamConfig.USE_DEFAULT_UI, "false" ); + props.setProperty( SlipstreamConfig.REMEMBER_GEOMETRY, "true" ); + // "update_catalog" doesn't have a default. + // "update_app" doesn't have a default. + // "manager_geometry" doesn't have a default. + + // Read the config file. + InputStream in = null; + try { + if ( configFile.exists() ) { + log.trace( "Loading properties from config file" ); + in = new FileInputStream( configFile ); + props.load( new InputStreamReader( in, "UTF-8" ) ); + } + } + catch ( IOException e ) { + log.error( "Error loading config", e ); + } + finally { + try {if ( in != null ) in.close();} + catch ( IOException e ) {} + } + + SlipstreamConfig appConfig = new SlipstreamConfig( props, configFile ); + return appConfig; + } + + /** * Checks the validity of the config's dats path and returns it. * Or exits if the path is invalid. diff --git a/src/main/java/net/vhati/modmanager/core/SlipstreamConfig.java b/src/main/java/net/vhati/modmanager/core/SlipstreamConfig.java index c6fa448..fe66234 100644 --- a/src/main/java/net/vhati/modmanager/core/SlipstreamConfig.java +++ b/src/main/java/net/vhati/modmanager/core/SlipstreamConfig.java @@ -1,21 +1,18 @@ package net.vhati.modmanager.core; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.swing.*; -import java.io.*; -import java.nio.charset.StandardCharsets; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Properties; -import java.util.concurrent.atomic.AtomicBoolean; public class SlipstreamConfig { - private static final Logger log = LoggerFactory.getLogger( SlipstreamConfig.class ); public static final String ALLOW_ZIP = "allow_zip"; public static final String FTL_DATS_PATH = "ftl_dats_path"; @@ -29,35 +26,12 @@ public class SlipstreamConfig { public static final String REMEMBER_GEOMETRY = "remember_geometry"; public static final String MANAGER_GEOMETRY = "manager_geometry"; - private final Properties config; - private final File configFile; + private Properties config; + private File configFile; - private final AtomicBoolean shutdownHookInitialized; - - public SlipstreamConfig(File configFile) { - this.shutdownHookInitialized = new AtomicBoolean(false); - - config = getProperties(); - - // Read the config file. - InputStream in = null; - try { - if ( configFile.exists() ) { - log.debug( "Loading config file" ); - in = new FileInputStream( configFile ); - config.load( new InputStreamReader( in, StandardCharsets.UTF_8) ); - scheduleShutdown(); - } - } - catch ( IOException e ) { - log.error( "Error loading config", e ); - showErrorDialog( "Error loading config from "+ configFile.getPath() ); - } - finally { - try {if ( in != null ) in.close();} - catch ( IOException ignored) {} - } + public SlipstreamConfig( Properties config, File configFile ) { + this.config = config; this.configFile = configFile; } @@ -68,23 +42,8 @@ public class SlipstreamConfig { this.configFile = srcConfig.getConfigFile(); this.config = new Properties(); this.config.putAll( srcConfig.getConfig() ); - this.shutdownHookInitialized = srcConfig.shutdownHookInitialized; } - private static Properties getProperties() { - Properties props = new Properties(); - props.setProperty( SlipstreamConfig.ALLOW_ZIP, "false" ); - props.setProperty( SlipstreamConfig.FTL_DATS_PATH, "" ); // Prompt. - props.setProperty( SlipstreamConfig.STEAM_DISTRO, "" ); // Prompt. - props.setProperty( SlipstreamConfig.STEAM_EXE_PATH, "" ); // Prompt. - props.setProperty( SlipstreamConfig.RUN_STEAM_FTL, "" ); // Prompt. - props.setProperty( SlipstreamConfig.NEVER_RUN_FTL, "false" ); - props.setProperty( SlipstreamConfig.UPDATE_CATALOG, "" ); // Prompt. - props.setProperty( SlipstreamConfig.UPDATE_APP, "" ); // Prompt. - props.setProperty( SlipstreamConfig.USE_DEFAULT_UI, "false" ); - props.setProperty( SlipstreamConfig.REMEMBER_GEOMETRY, "true" ); - return props; - } public Properties getConfig() { return config; } @@ -92,30 +51,9 @@ public class SlipstreamConfig { public Object setProperty( String key, String value ) { - scheduleShutdown(); return config.setProperty( key, value ); } - private void scheduleShutdown() { - if (!shutdownHookInitialized.compareAndExchange(false, true)) { - Runtime.getRuntime().addShutdownHook(new Thread(() -> { - try { - this.writeConfig(); - } catch (IOException e) { - String errorMsg = String.format( "Error writing config to \"%s\"", configFile.getPath() ); - log.error( errorMsg, e ); - // TODO: only show this error when in gui mode - showErrorDialog( errorMsg ); - } - })); - } - - } - - private static void showErrorDialog( String message ) { - JOptionPane.showMessageDialog( null, message, "Error", JOptionPane.ERROR_MESSAGE ); - } - public int getPropertyAsInt( String key, int defaultValue ) { String s = config.getProperty( key ); if ( s != null && s.matches("^\\d+$") ) diff --git a/src/main/java/net/vhati/modmanager/ui/ManagerFrame.java b/src/main/java/net/vhati/modmanager/ui/ManagerFrame.java index 742e6f7..1bfcf30 100644 --- a/src/main/java/net/vhati/modmanager/ui/ManagerFrame.java +++ b/src/main/java/net/vhati/modmanager/ui/ManagerFrame.java @@ -1065,7 +1065,7 @@ public class ManagerFrame extends JFrame implements ActionListener, ModsScanObse * Set this to false before an abnormal exit. */ public void setDisposeNormally( boolean b ) { - disposeNormally = b; + disposeNormally = false; } @Override diff --git a/src/main/java/net/vhati/modmanager/ui/ModPatchDialog.java b/src/main/java/net/vhati/modmanager/ui/ModPatchDialog.java index bfa7932..80a2376 100644 --- a/src/main/java/net/vhati/modmanager/ui/ModPatchDialog.java +++ b/src/main/java/net/vhati/modmanager/ui/ModPatchDialog.java @@ -13,7 +13,7 @@ public class ModPatchDialog extends ProgressDialog implements ModPatchObserver { public ModPatchDialog( Frame owner, boolean continueOnSuccess ) { - super( owner, continueOnSuccess ); + super( owner, true ); this.setTitle( "Patching..." ); this.setSize( 400, 160 ); diff --git a/src/main/java/net/vhati/modmanager/ui/ModXMLSandbox.java b/src/main/java/net/vhati/modmanager/ui/ModXMLSandbox.java index 401ead3..8a07df2 100644 --- a/src/main/java/net/vhati/modmanager/ui/ModXMLSandbox.java +++ b/src/main/java/net/vhati/modmanager/ui/ModXMLSandbox.java @@ -524,33 +524,32 @@ public class ModXMLSandbox extends JFrame implements ActionListener { */ @SuppressWarnings("unchecked") private void buildTreeFromString( DefaultTreeModel treeModel, String path ) { -// Method commented out to get application to compile. Figure out what this did and fix it -// DefaultMutableTreeNode rootNode = (DefaultMutableTreeNode)treeModel.getRoot(); -// DefaultMutableTreeNode currentNode = rootNode; -// -// String[] chunks = path.split( "/" ); -// -// for ( int i=0; i < chunks.length; i++ ) { -// String chunk = chunks[i]; -// if ( i < chunks.length-1 ) -// chunk += "/"; -// -// boolean found = false; -// Enumeration enumIt = currentNode.children(); -// while ( enumIt.hasMoreElements() ) { -// DefaultMutableTreeNode tmpNode = enumIt.nextElement(); -// if ( chunk.equals( tmpNode.getUserObject() ) ) { -// found = true; -// currentNode = tmpNode; -// break; -// } -// } -// if ( !found ) { -// DefaultMutableTreeNode newNode = new DefaultMutableTreeNode( chunk ); -// currentNode.insert( newNode, currentNode.getChildCount() ); -// currentNode = newNode; -// } -// } + DefaultMutableTreeNode rootNode = (DefaultMutableTreeNode)treeModel.getRoot(); + DefaultMutableTreeNode currentNode = rootNode; + + String[] chunks = path.split( "/" ); + + for ( int i=0; i < chunks.length; i++ ) { + String chunk = chunks[i]; + if ( i < chunks.length-1 ) + chunk += "/"; + + boolean found = false; + Enumeration enumIt = currentNode.children(); + while ( enumIt.hasMoreElements() ) { + DefaultMutableTreeNode tmpNode = enumIt.nextElement(); + if ( chunk.equals( tmpNode.getUserObject() ) ) { + found = true; + currentNode = tmpNode; + break; + } + } + if ( !found ) { + DefaultMutableTreeNode newNode = new DefaultMutableTreeNode( chunk ); + currentNode.insert( newNode, currentNode.getChildCount() ); + currentNode = newNode; + } + } }