Compare commits

..

No commits in common. "ccd50b0275d3c1bce8ae0693457edfd26e714006" and "19233266d0da2b56eb3e8e9d94604dc7838d2955" have entirely different histories.

14 changed files with 364 additions and 458 deletions

1
.envrc
View file

@ -1 +0,0 @@
use flake

7
.gitignore vendored
View file

@ -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

25
flake.lock generated
View file

@ -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
}

View file

@ -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}"
'';
};
}
);
};
}

View file

@ -11,8 +11,8 @@
</prerequisites>
<properties>
<jdk.version>1.6</jdk.version>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<maven.compiler.source>1.6</maven.compiler.source>
<maven.compiler.target>1.6</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

View file

@ -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

View file

@ -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

View file

@ -1,4 +1,4 @@
#!/usr/bin/env bash
#!/bin/bash
# Get the script's name.
me=$(basename "$0");

View file

@ -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() {
}

View file

@ -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<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() ) extractDir.mkdirs();
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 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<File> modFiles = new ArrayList<File>();
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<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 == 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<String> dirList = new ArrayList<String>();
List<String> fileList = new ArrayList<String>();
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<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() ) extractDir.mkdirs();
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 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<File> modFiles = new ArrayList<File>();
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<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;
}
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<String> dirList = new ArrayList<String>();
List<String> fileList = new ArrayList<String>();
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.

View file

@ -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+$") )

View file

@ -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

View file

@ -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 );

View file

@ -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<DefaultMutableTreeNode> 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<DefaultMutableTreeNode> 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;
}
}
}