Added support for extracting/sandboxing FTL 1.6.1's resources (patching is WIP)
This commit is contained in:
parent
34a71e0aa5
commit
f0df7faab8
10 changed files with 344 additions and 198 deletions
|
@ -75,6 +75,15 @@ public abstract class AbstractPack {
|
||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tidies up the dat before closing (possibly mandatory).
|
||||||
|
*
|
||||||
|
* @returns a result, or null if nothing happened
|
||||||
|
*/
|
||||||
|
public RepackResult repack() throws IOException {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -466,6 +466,7 @@ public class FTLPack extends AbstractPack {
|
||||||
* Repacks the dat file. This will remove gaps, which could
|
* Repacks the dat file. This will remove gaps, which could
|
||||||
* be created when adding, removing or replacing files.
|
* be created when adding, removing or replacing files.
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public RepackResult repack() throws IOException {
|
public RepackResult repack() throws IOException {
|
||||||
long bytesChanged = 0;
|
long bytesChanged = 0;
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ package net.vhati.ftldat;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
|
@ -733,6 +733,7 @@ public class PkgPack extends AbstractPack {
|
||||||
* All innerPaths will be rewritten to the paths region, sorted by
|
* All innerPaths will be rewritten to the paths region, sorted by
|
||||||
* dataOffset.
|
* dataOffset.
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public RepackResult repack() throws IOException {
|
public RepackResult repack() throws IOException {
|
||||||
long bytesChanged = 0;
|
long bytesChanged = 0;
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import java.io.BufferedOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileFilter;
|
import java.io.FileFilter;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
|
@ -17,13 +18,13 @@ import java.util.zip.ZipOutputStream;
|
||||||
|
|
||||||
import net.vhati.ftldat.AbstractPack;
|
import net.vhati.ftldat.AbstractPack;
|
||||||
import net.vhati.ftldat.FolderPack;
|
import net.vhati.ftldat.FolderPack;
|
||||||
|
import net.vhati.ftldat.PkgPack;
|
||||||
import net.vhati.ftldat.FTLPack;
|
import net.vhati.ftldat.FTLPack;
|
||||||
import net.vhati.modmanager.FTLModManager;
|
import net.vhati.modmanager.FTLModManager;
|
||||||
import net.vhati.modmanager.core.DelayedDeleteHook;
|
import net.vhati.modmanager.core.DelayedDeleteHook;
|
||||||
import net.vhati.modmanager.core.FTLUtilities;
|
import net.vhati.modmanager.core.FTLUtilities;
|
||||||
import net.vhati.modmanager.core.ModPatchObserver;
|
import net.vhati.modmanager.core.ModPatchObserver;
|
||||||
import net.vhati.modmanager.core.ModPatchThread;
|
import net.vhati.modmanager.core.ModPatchThread;
|
||||||
import net.vhati.modmanager.core.ModPatchThread.BackedUpDat;
|
|
||||||
import net.vhati.modmanager.core.ModUtilities;
|
import net.vhati.modmanager.core.ModUtilities;
|
||||||
import net.vhati.modmanager.core.Report;
|
import net.vhati.modmanager.core.Report;
|
||||||
import net.vhati.modmanager.core.Report.ReportFormatter;
|
import net.vhati.modmanager.core.Report.ReportFormatter;
|
||||||
|
@ -124,7 +125,7 @@ public class SlipstreamCLI {
|
||||||
boolean anyInvalid = false;
|
boolean anyInvalid = false;
|
||||||
|
|
||||||
for ( String modFileName : cmdline.getArgs() ) {
|
for ( String modFileName : cmdline.getArgs() ) {
|
||||||
File modFile = new File(modsDir, modFileName);
|
File modFile = new File( modsDir, modFileName );
|
||||||
|
|
||||||
if ( modFile.isDirectory() ) {
|
if ( modFile.isDirectory() ) {
|
||||||
log.info( String.format( "Zipping dir: %s/", modFile.getName() ) );
|
log.info( String.format( "Zipping dir: %s/", modFile.getName() ) );
|
||||||
|
@ -133,7 +134,7 @@ public class SlipstreamCLI {
|
||||||
deleteHook.addDoomedFile( modFile );
|
deleteHook.addDoomedFile( modFile );
|
||||||
}
|
}
|
||||||
catch ( IOException e ) {
|
catch ( IOException e ) {
|
||||||
log.error( String.format( "Error zipping \"%s/\".", modFile.getName() ), e );
|
log.error( String.format( "Error zipping dir: %s/", modFile.getName() ), e );
|
||||||
|
|
||||||
List<ReportMessage> tmpMessages = new ArrayList<ReportMessage>();
|
List<ReportMessage> tmpMessages = new ArrayList<ReportMessage>();
|
||||||
tmpMessages.add( new ReportMessage( ReportMessage.SECTION, modFileName ) );
|
tmpMessages.add( new ReportMessage( ReportMessage.SECTION, modFileName ) );
|
||||||
|
@ -200,46 +201,61 @@ public class SlipstreamCLI {
|
||||||
String extractPath = cmdline.getOptionValue( "extract-dats" );
|
String extractPath = cmdline.getOptionValue( "extract-dats" );
|
||||||
File extractDir = new File( extractPath );
|
File extractDir = new File( extractPath );
|
||||||
|
|
||||||
File dataDatFile = new File( datsDir, "data.dat" );
|
FolderPack dstPack = null;
|
||||||
File resDatFile = new File( datsDir, "resource.dat" );
|
List<AbstractPack> srcPacks = new ArrayList<AbstractPack>( 2 );
|
||||||
File[] datFiles = new File[] {dataDatFile, resDatFile};
|
|
||||||
|
|
||||||
AbstractPack srcP = null;
|
|
||||||
AbstractPack dstP = null;
|
|
||||||
InputStream is = null;
|
InputStream is = null;
|
||||||
try {
|
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();
|
if ( !extractDir.exists() ) extractDir.mkdirs();
|
||||||
|
|
||||||
dstP = new FolderPack( extractDir );
|
dstPack = new FolderPack( extractDir );
|
||||||
|
|
||||||
for ( File datFile : datFiles ) {
|
for ( AbstractPack srcPack : srcPacks ) {
|
||||||
srcP = new FTLPack( datFile, "r" );
|
List<String> innerPaths = srcPack.list();
|
||||||
List<String> innerPaths = srcP.list();
|
|
||||||
|
|
||||||
for ( String innerPath : innerPaths ) {
|
for ( String innerPath : innerPaths ) {
|
||||||
if ( dstP.contains( innerPath ) ) {
|
if ( dstPack.contains( innerPath ) ) {
|
||||||
log.info( "While extracting resources, this file was overwritten: "+ innerPath );
|
log.info( "While extracting resources, this file was overwritten: "+ innerPath );
|
||||||
dstP.remove( innerPath );
|
dstPack.remove( innerPath );
|
||||||
}
|
}
|
||||||
is = srcP.getInputStream( innerPath );
|
is = srcPack.getInputStream( innerPath );
|
||||||
dstP.add( innerPath, is );
|
dstPack.add( innerPath, is );
|
||||||
}
|
}
|
||||||
srcP.close();
|
srcPack.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch ( IOException e ) {
|
catch ( IOException e ) {
|
||||||
log.error( "Error extracting dats.", e );
|
log.error( "Error extracting dats", e );
|
||||||
System.exit( 1 );
|
System.exit( 1 );
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
try {if ( is != null ) is.close();}
|
try {if ( is != null ) is.close();}
|
||||||
catch ( IOException ex ) {}
|
catch ( IOException ex ) {}
|
||||||
|
|
||||||
try {if ( srcP != null ) srcP.close();}
|
try {if ( dstPack != null ) dstPack.close();}
|
||||||
catch ( IOException ex ) {}
|
catch ( IOException ex ) {}
|
||||||
|
|
||||||
try {if ( dstP != null ) dstP.close();}
|
for ( AbstractPack pack : srcPacks ) {
|
||||||
catch ( IOException ex ) {}
|
try {pack.close();}
|
||||||
|
catch ( IOException ex ) {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
System.exit( 0 );
|
System.exit( 0 );
|
||||||
|
@ -259,7 +275,7 @@ public class SlipstreamCLI {
|
||||||
deleteHook.addDoomedFile( modFile );
|
deleteHook.addDoomedFile( modFile );
|
||||||
}
|
}
|
||||||
catch ( IOException e ) {
|
catch ( IOException e ) {
|
||||||
log.error( String.format( "Error zipping \"%s/\".", modFile.getName() ), e );
|
log.error( String.format( "Error zipping dir: %s/", modFile.getName() ), e );
|
||||||
System.exit( 1 );
|
System.exit( 1 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -267,17 +283,10 @@ public class SlipstreamCLI {
|
||||||
modFiles.add( modFile );
|
modFiles.add( modFile );
|
||||||
}
|
}
|
||||||
|
|
||||||
BackedUpDat dataDat = new BackedUpDat();
|
|
||||||
dataDat.datFile = new File( datsDir, "data.dat" );
|
|
||||||
dataDat.bakFile = new File( backupDir, "data.dat.bak" );
|
|
||||||
BackedUpDat resDat = new BackedUpDat();
|
|
||||||
resDat.datFile = new File( datsDir, "resource.dat" );
|
|
||||||
resDat.bakFile = new File( backupDir, "resource.dat.bak" );
|
|
||||||
|
|
||||||
boolean globalPanic = cmdline.hasOption( "global-panic" );
|
boolean globalPanic = cmdline.hasOption( "global-panic" );
|
||||||
|
|
||||||
SilentPatchObserver patchObserver = new SilentPatchObserver();
|
SilentPatchObserver patchObserver = new SilentPatchObserver();
|
||||||
ModPatchThread patchThread = new ModPatchThread( modFiles, dataDat, resDat, globalPanic, patchObserver );
|
ModPatchThread patchThread = new ModPatchThread( modFiles, datsDir, backupDir, globalPanic, patchObserver );
|
||||||
patchThread.setDefaultUncaughtExceptionHandler( exceptionHandler );
|
patchThread.setDefaultUncaughtExceptionHandler( exceptionHandler );
|
||||||
deleteHook.addWatchedThread( patchThread );
|
deleteHook.addWatchedThread( patchThread );
|
||||||
|
|
||||||
|
@ -301,7 +310,7 @@ public class SlipstreamCLI {
|
||||||
exeArgs = new String[] {"-applaunch", FTLUtilities.STEAM_APPID_FTL};
|
exeArgs = new String[] {"-applaunch", FTLUtilities.STEAM_APPID_FTL};
|
||||||
|
|
||||||
if ( exeFile == null ) {
|
if ( exeFile == null ) {
|
||||||
log.warn( "Steam executable could not be found. FTL will be launched directly." );
|
log.warn( "Steam executable could not be found; FTL will be launched directly" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( exeFile == null ) {
|
if ( exeFile == null ) {
|
||||||
|
@ -309,7 +318,7 @@ public class SlipstreamCLI {
|
||||||
exeArgs = new String[0];
|
exeArgs = new String[0];
|
||||||
|
|
||||||
if ( exeFile == null ) {
|
if ( exeFile == null ) {
|
||||||
log.warn( "FTL executable could not be found." );
|
log.warn( "FTL executable could not be found" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,12 +326,12 @@ public class SlipstreamCLI {
|
||||||
try {
|
try {
|
||||||
FTLUtilities.launchExe( exeFile, exeArgs );
|
FTLUtilities.launchExe( exeFile, exeArgs );
|
||||||
} catch ( Exception e ) {
|
} catch ( Exception e ) {
|
||||||
log.error( "Error launching FTL.", e );
|
log.error( "Error launching FTL", e );
|
||||||
System.exit( 1 );
|
System.exit( 1 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
log.error( "No executables were found to launch FTL." );
|
log.error( "No executables were found to launch FTL" );
|
||||||
System.exit( 1 );
|
System.exit( 1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -352,13 +361,13 @@ public class SlipstreamCLI {
|
||||||
InputStream in = null;
|
InputStream in = null;
|
||||||
try {
|
try {
|
||||||
if ( configFile.exists() ) {
|
if ( configFile.exists() ) {
|
||||||
log.trace( "Loading properties from config file." );
|
log.trace( "Loading properties from config file" );
|
||||||
in = new FileInputStream( configFile );
|
in = new FileInputStream( configFile );
|
||||||
config.load( new InputStreamReader( in, "UTF-8" ) );
|
config.load( new InputStreamReader( in, "UTF-8" ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch ( IOException e ) {
|
catch ( IOException e ) {
|
||||||
log.error( "Error loading config.", e );
|
log.error( "Error loading config", e );
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
try {if ( in != null ) in.close();}
|
try {if ( in != null ) in.close();}
|
||||||
|
@ -381,14 +390,14 @@ public class SlipstreamCLI {
|
||||||
log.info( "Using FTL dats path from config: "+ datsPath );
|
log.info( "Using FTL dats path from config: "+ datsPath );
|
||||||
datsDir = new File( datsPath );
|
datsDir = new File( datsPath );
|
||||||
if ( FTLUtilities.isDatsDirValid( datsDir ) == false ) {
|
if ( FTLUtilities.isDatsDirValid( datsDir ) == false ) {
|
||||||
log.error( "The config's ftl_dats_path does not exist." );
|
log.error( "The config's ftl_dats_path does not exist" );
|
||||||
datsDir = null;
|
datsDir = null;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.error( "No FTL dats path previously set." );
|
log.error( "No FTL dats path previously set" );
|
||||||
}
|
}
|
||||||
if ( datsDir == null ) {
|
if ( datsDir == null ) {
|
||||||
log.error( "Run the GUI once, or edit the config file, and try again." );
|
log.error( "Run the GUI once, or edit the config file, and try again" );
|
||||||
System.exit( 1 );
|
System.exit( 1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,22 +19,34 @@ public class FTLUtilities {
|
||||||
/**
|
/**
|
||||||
* Confirms the FTL resources dir exists and contains the dat files.
|
* Confirms the FTL resources dir exists and contains the dat files.
|
||||||
*
|
*
|
||||||
|
* This checks for either "ftl.dat" or both "data.dat" and "resource.dat".
|
||||||
|
*
|
||||||
* Note: Do d.getCanonicalFile() to resolve any symlinks first!
|
* Note: Do d.getCanonicalFile() to resolve any symlinks first!
|
||||||
*/
|
*/
|
||||||
public static boolean isDatsDirValid( File d ) {
|
public static boolean isDatsDirValid( File d ) {
|
||||||
if ( !d.exists() || !d.isDirectory() ) return false;
|
if ( !d.exists() || !d.isDirectory() ) return false;
|
||||||
if ( !new File( d, "data.dat" ).exists() ) return false;
|
|
||||||
if ( !new File( d, "resource.dat" ).exists() ) return false;
|
if ( new File( d, "ftl.dat" ).exists() ) return true;
|
||||||
return true;
|
|
||||||
|
if ( new File( d, "data.dat" ).exists() && new File( d, "resource.dat" ).exists() ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the FTL resources dir, or null.
|
* Returns the FTL resources dir, or null.
|
||||||
|
*
|
||||||
|
* Windows: Steam, GOG, HumbleBundle
|
||||||
|
* Linux (Wine): GOG, HumbleBundle
|
||||||
|
* Linux: Steam, HumbleBundle
|
||||||
|
* OSX: Steam, HumbleBundle
|
||||||
*/
|
*/
|
||||||
public static File findDatsDir() {
|
public static File findDatsDir() {
|
||||||
String steamPath = "Steam/steamapps/common/FTL Faster Than Light/resources";
|
String steamPath = "Steam/steamapps/common/FTL Faster Than Light";
|
||||||
String gogPath = "GOG.com/Faster Than Light/resources";
|
String gogPath = "GOG.com/Faster Than Light";
|
||||||
String humblePath = "FTL/resources";
|
String humblePath = "FTL";
|
||||||
|
|
||||||
String programFiles86 = System.getenv( "ProgramFiles(x86)" );
|
String programFiles86 = System.getenv( "ProgramFiles(x86)" );
|
||||||
String programFiles = System.getenv( "ProgramFiles" );
|
String programFiles = System.getenv( "ProgramFiles" );
|
||||||
|
@ -55,18 +67,32 @@ public class FTLUtilities {
|
||||||
candidates.add( new File( new File( programFiles86 ), steamPath ) );
|
candidates.add( new File( new File( programFiles86 ), steamPath ) );
|
||||||
candidates.add( new File( new File( programFiles86 ), gogPath ) );
|
candidates.add( new File( new File( programFiles86 ), gogPath ) );
|
||||||
candidates.add( new File( new File( programFiles86 ), humblePath ) );
|
candidates.add( new File( new File( programFiles86 ), humblePath ) );
|
||||||
|
|
||||||
|
candidates.add( new File( new File( programFiles86 ), steamPath +"/resources" ) );
|
||||||
|
candidates.add( new File( new File( programFiles86 ), gogPath +"/resources" ) );
|
||||||
|
candidates.add( new File( new File( programFiles86 ), humblePath +"/resources" ) );
|
||||||
}
|
}
|
||||||
if ( programFiles != null ) {
|
if ( programFiles != null ) {
|
||||||
candidates.add( new File( new File( programFiles ), steamPath ) );
|
candidates.add( new File( new File( programFiles ), steamPath ) );
|
||||||
candidates.add( new File( new File( programFiles ), gogPath ) );
|
candidates.add( new File( new File( programFiles ), gogPath ) );
|
||||||
candidates.add( new File( new File( programFiles ), humblePath ) );
|
candidates.add( new File( new File( programFiles ), humblePath ) );
|
||||||
|
|
||||||
|
candidates.add( new File( new File( programFiles ), steamPath +"/resources" ) );
|
||||||
|
candidates.add( new File( new File( programFiles ), gogPath +"/resources" ) );
|
||||||
|
candidates.add( new File( new File( programFiles ), humblePath +"/resources" ) );
|
||||||
}
|
}
|
||||||
// Linux - Steam.
|
// Linux - Steam.
|
||||||
if ( xdgDataHome != null ) {
|
if ( xdgDataHome != null ) {
|
||||||
|
candidates.add( new File( xdgDataHome +"/Steam/steamapps/common/FTL Faster Than Light/data" ) );
|
||||||
|
candidates.add( new File( xdgDataHome +"/Steam/SteamApps/common/FTL Faster Than Light/data" ) );
|
||||||
|
|
||||||
candidates.add( new File( xdgDataHome +"/Steam/steamapps/common/FTL Faster Than Light/data/resources" ) );
|
candidates.add( new File( xdgDataHome +"/Steam/steamapps/common/FTL Faster Than Light/data/resources" ) );
|
||||||
candidates.add( new File( xdgDataHome +"/Steam/SteamApps/common/FTL Faster Than Light/data/resources" ) );
|
candidates.add( new File( xdgDataHome +"/Steam/SteamApps/common/FTL Faster Than Light/data/resources" ) );
|
||||||
}
|
}
|
||||||
if ( home != null ) {
|
if ( home != null ) {
|
||||||
|
candidates.add( new File( home +"/.steam/steam/steamapps/common/FTL Faster Than Light/data" ) );
|
||||||
|
candidates.add( new File( home +"/.steam/steam/SteamApps/common/FTL Faster Than Light/data" ) );
|
||||||
|
|
||||||
candidates.add( new File( home +"/.steam/steam/steamapps/common/FTL Faster Than Light/data/resources" ) );
|
candidates.add( new File( home +"/.steam/steam/steamapps/common/FTL Faster Than Light/data/resources" ) );
|
||||||
candidates.add( new File( home +"/.steam/steam/SteamApps/common/FTL Faster Than Light/data/resources" ) );
|
candidates.add( new File( home +"/.steam/steam/SteamApps/common/FTL Faster Than Light/data/resources" ) );
|
||||||
}
|
}
|
||||||
|
@ -76,6 +102,11 @@ public class FTLUtilities {
|
||||||
candidates.add( new File( winePrefix +"/drive_c/Program Files (x86)/"+ humblePath ) );
|
candidates.add( new File( winePrefix +"/drive_c/Program Files (x86)/"+ humblePath ) );
|
||||||
candidates.add( new File( winePrefix +"/drive_c/Program Files/"+ gogPath ) );
|
candidates.add( new File( winePrefix +"/drive_c/Program Files/"+ gogPath ) );
|
||||||
candidates.add( new File( winePrefix +"/drive_c/Program Files/"+ humblePath ) );
|
candidates.add( new File( winePrefix +"/drive_c/Program Files/"+ humblePath ) );
|
||||||
|
|
||||||
|
candidates.add( new File( winePrefix +"/drive_c/Program Files (x86)/"+ gogPath +"/resources" ) );
|
||||||
|
candidates.add( new File( winePrefix +"/drive_c/Program Files (x86)/"+ humblePath +"/resources" ) );
|
||||||
|
candidates.add( new File( winePrefix +"/drive_c/Program Files/"+ gogPath +"/resources" ) );
|
||||||
|
candidates.add( new File( winePrefix +"/drive_c/Program Files/"+ humblePath +"/resources" ) );
|
||||||
}
|
}
|
||||||
// OSX - Steam.
|
// OSX - Steam.
|
||||||
if ( home != null ) {
|
if ( home != null ) {
|
||||||
|
@ -113,28 +144,30 @@ public class FTLUtilities {
|
||||||
|
|
||||||
String message = "";
|
String message = "";
|
||||||
message += "You will now be prompted to locate FTL manually.\n";
|
message += "You will now be prompted to locate FTL manually.\n";
|
||||||
message += "Select '(FTL dir)/resources/data.dat'.\n";
|
message += "Look in {FTL dir} to select 'ftl.dat' or 'data.dat'.\n";
|
||||||
message += "Or 'FTL.app', if you're on OSX.";
|
message += "\n";
|
||||||
|
message += "It may be buried under a subdirectory called 'resources/'.\n";
|
||||||
|
message += "Or select 'FTL.app', if you're on OSX.";
|
||||||
JOptionPane.showMessageDialog( parentComponent, message, "Find FTL", JOptionPane.INFORMATION_MESSAGE );
|
JOptionPane.showMessageDialog( parentComponent, message, "Find FTL", JOptionPane.INFORMATION_MESSAGE );
|
||||||
|
|
||||||
final JFileChooser fc = new JFileChooser();
|
final JFileChooser fc = new JFileChooser();
|
||||||
fc.setDialogTitle( "Find data.dat or FTL.app" );
|
fc.setDialogTitle( "Find ftl.dat or data.dat or FTL.app" );
|
||||||
fc.setFileHidingEnabled( false );
|
fc.setFileHidingEnabled( false );
|
||||||
fc.addChoosableFileFilter(new FileFilter() {
|
fc.addChoosableFileFilter(new FileFilter() {
|
||||||
@Override
|
@Override
|
||||||
public String getDescription() {
|
public String getDescription() {
|
||||||
return "FTL Data File - (FTL dir)/resources/data.dat";
|
return "FTL Data File - ftl.dat|data.dat";
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public boolean accept( File f ) {
|
public boolean accept( File f ) {
|
||||||
return f.isDirectory() || f.getName().equals( "data.dat" ) || f.getName().equals( "FTL.app" );
|
return f.isDirectory() || f.getName().equals( "ftl.dat" ) || f.getName().equals( "data.dat" ) || f.getName().equals( "FTL.app" );
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
fc.setMultiSelectionEnabled(false);
|
fc.setMultiSelectionEnabled( false );
|
||||||
|
|
||||||
if ( fc.showOpenDialog( parentComponent ) == JFileChooser.APPROVE_OPTION ) {
|
if ( fc.showOpenDialog( parentComponent ) == JFileChooser.APPROVE_OPTION ) {
|
||||||
File f = fc.getSelectedFile();
|
File f = fc.getSelectedFile();
|
||||||
if ( f.getName().equals( "data.dat" ) ) {
|
if ( f.getName().equals( "ftl.dat" ) || f.getName().equals( "data.dat" ) ) {
|
||||||
result = f.getParentFile();
|
result = f.getParentFile();
|
||||||
}
|
}
|
||||||
else if ( f.getName().endsWith( ".app" ) && f.isDirectory() ) {
|
else if ( f.getName().endsWith( ".app" ) && f.isDirectory() ) {
|
||||||
|
@ -152,29 +185,60 @@ public class FTLUtilities {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the executable that will launch FTL, or null.
|
* Returns the executable that will launch FTL, or null.
|
||||||
*
|
*
|
||||||
* On Windows, FTLGame.exe is one dir above "resources/".
|
* FTL 1.01-1.5.13:
|
||||||
* On Linux, FTL is a script, one dir above "resources/".
|
* Windows
|
||||||
|
* {FTL dir}/resources/*.dat
|
||||||
|
* {FTL dir}/FTLGame.exe
|
||||||
|
* Linux
|
||||||
|
* {FTL dir}/data/resources/*.dat
|
||||||
|
* {FTL dir}/data/FTL
|
||||||
|
* OSX
|
||||||
|
* {FTL dir}/Contents/Resources/*.dat
|
||||||
|
* {FTL dir}
|
||||||
|
*
|
||||||
|
* FTL 1.6.1:
|
||||||
|
* Windows
|
||||||
|
* {FTL dir}/*.dat
|
||||||
|
* {FTL dir}/FTLGame.exe
|
||||||
|
* Linux
|
||||||
|
* {FTL dir}/data/*.dat
|
||||||
|
* {FTL dir}/data/FTL
|
||||||
|
* OSX
|
||||||
|
* {FTL dir}/Contents/Resources/*.dat
|
||||||
|
* {FTL dir}
|
||||||
|
*
|
||||||
|
* On Windows, FTLGame.exe is a binary.
|
||||||
|
* On Linux, FTL is a script.
|
||||||
* On OSX, FTL.app is the grandparent dir itself (a bundle).
|
* On OSX, FTL.app is the grandparent dir itself (a bundle).
|
||||||
*/
|
*/
|
||||||
public static File findGameExe( File datsDir ) {
|
public static File findGameExe( File datsDir ) {
|
||||||
File result = null;
|
File result = null;
|
||||||
|
|
||||||
if ( System.getProperty( "os.name" ).startsWith( "Windows" ) ) {
|
if ( System.getProperty( "os.name" ).startsWith( "Windows" ) ) {
|
||||||
File ftlDir = datsDir.getParentFile();
|
|
||||||
if ( ftlDir != null ) {
|
for ( File candidateDir : new File[] {datsDir, datsDir.getParentFile()} ) {
|
||||||
File exeFile = new File( ftlDir, "FTLGame.exe" );
|
if ( candidateDir == null ) continue;
|
||||||
if ( exeFile.exists() ) result = exeFile;
|
|
||||||
|
File exeFile = new File( candidateDir, "FTLGame.exe" );
|
||||||
|
if ( exeFile.exists() ) {
|
||||||
|
result = exeFile;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ( System.getProperty( "os.name" ).equals( "Linux" ) ) {
|
else if ( System.getProperty( "os.name" ).equals( "Linux" ) ) {
|
||||||
File ftlDir = datsDir.getParentFile();
|
|
||||||
if ( ftlDir != null ) {
|
for ( File candidateDir : new File[] {datsDir, datsDir.getParentFile()} ) {
|
||||||
File exeFile = new File( ftlDir, "FTL" );
|
if ( candidateDir == null ) continue;
|
||||||
if ( exeFile.exists() ) result = exeFile;
|
|
||||||
|
File exeFile = new File( candidateDir, "FTL" );
|
||||||
|
if ( exeFile.exists() ) {
|
||||||
|
result = exeFile;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ( System.getProperty( "os.name" ).contains( "OS X" ) ) {
|
else if ( System.getProperty( "os.name" ).contains( "OS X" ) ) {
|
||||||
|
@ -189,16 +253,16 @@ public class FTLUtilities {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the executable that will launch Steam, or null.
|
* Returns the executable that will launch Steam, or null.
|
||||||
*
|
*
|
||||||
* On Windows, Steam.exe.
|
* On Windows, "Steam.exe".
|
||||||
* On Linux, steam is a script. ( http://moritzmolch.com/815 )
|
* On Linux, "steam" is a script. ( http://moritzmolch.com/815 )
|
||||||
* On OSX, Steam.app is the grandparent dir itself (a bundle).
|
* On OSX, "Steam.app" is a bundle.
|
||||||
*
|
*
|
||||||
* The args to launch FTL are: ["-applaunch", STEAM_APPID_FTL]
|
* The args to launch FTL are: ["-applaunch", STEAM_APPID_FTL]
|
||||||
*/
|
*/
|
||||||
|
@ -237,7 +301,6 @@ public class FTLUtilities {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Launches an executable.
|
* Launches an executable.
|
||||||
*
|
*
|
||||||
|
@ -245,6 +308,8 @@ public class FTLUtilities {
|
||||||
* On Linux, a binary or script.
|
* On Linux, a binary or script.
|
||||||
* On OSX, an *.app bundle dir.
|
* On OSX, an *.app bundle dir.
|
||||||
*
|
*
|
||||||
|
* OSX bundles are executed with: "open -a bundle.app".
|
||||||
|
*
|
||||||
* @param exeFile see findGameExe() or findSteamExe()
|
* @param exeFile see findGameExe() or findSteamExe()
|
||||||
* @param exeArgs arguments for the executable
|
* @param exeArgs arguments for the executable
|
||||||
* @return a Process object, or null
|
* @return a Process object, or null
|
||||||
|
@ -278,7 +343,6 @@ public class FTLUtilities {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the directory for user profiles and saved games, or null.
|
* Returns the directory for user profiles and saved games, or null.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -15,7 +15,10 @@ import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipInputStream;
|
import java.util.zip.ZipInputStream;
|
||||||
|
|
||||||
import net.vhati.ftldat.AbstractPack;
|
import net.vhati.ftldat.AbstractPack;
|
||||||
|
import net.vhati.ftldat.AbstractPack.RepackResult;
|
||||||
import net.vhati.ftldat.FTLPack;
|
import net.vhati.ftldat.FTLPack;
|
||||||
|
import net.vhati.ftldat.PkgPack;
|
||||||
|
import net.vhati.ftldat.PackContainer;
|
||||||
import net.vhati.ftldat.PackUtilities;
|
import net.vhati.ftldat.PackUtilities;
|
||||||
import net.vhati.modmanager.core.ModPatchObserver;
|
import net.vhati.modmanager.core.ModPatchObserver;
|
||||||
import net.vhati.modmanager.core.ModUtilities;
|
import net.vhati.modmanager.core.ModUtilities;
|
||||||
|
@ -36,8 +39,8 @@ public class ModPatchThread extends Thread {
|
||||||
private Thread shutdownHook = null;
|
private Thread shutdownHook = null;
|
||||||
|
|
||||||
private List<File> modFiles = new ArrayList<File>();
|
private List<File> modFiles = new ArrayList<File>();
|
||||||
private BackedUpDat dataDat = null;
|
private File datsDir = null;
|
||||||
private BackedUpDat resDat = null;
|
private File backupDir = null;
|
||||||
private boolean globalPanic = false;
|
private boolean globalPanic = false;
|
||||||
private ModPatchObserver observer = null;
|
private ModPatchObserver observer = null;
|
||||||
|
|
||||||
|
@ -48,10 +51,11 @@ public class ModPatchThread extends Thread {
|
||||||
private final int progRepackMax = 5;
|
private final int progRepackMax = 5;
|
||||||
private int progMilestone = 0;
|
private int progMilestone = 0;
|
||||||
|
|
||||||
public ModPatchThread( List<File> modFiles, BackedUpDat dataDat, BackedUpDat resDat, boolean globalPanic, ModPatchObserver observer ) {
|
|
||||||
|
public ModPatchThread( List<File> modFiles, File datsDir, File backupDir, boolean globalPanic, ModPatchObserver observer ) {
|
||||||
this.modFiles.addAll( modFiles );
|
this.modFiles.addAll( modFiles );
|
||||||
this.dataDat = dataDat;
|
this.datsDir = datsDir;
|
||||||
this.resDat = resDat;
|
this.backupDir = backupDir;
|
||||||
this.globalPanic = globalPanic;
|
this.globalPanic = globalPanic;
|
||||||
this.observer = observer;
|
this.observer = observer;
|
||||||
}
|
}
|
||||||
|
@ -103,10 +107,7 @@ public class ModPatchThread extends Thread {
|
||||||
|
|
||||||
observer.patchingProgress( 0, progMax );
|
observer.patchingProgress( 0, progMax );
|
||||||
|
|
||||||
BackedUpDat[] allDats = new BackedUpDat[] {dataDat, resDat};
|
PackContainer packContainer = null;
|
||||||
|
|
||||||
FTLPack dataP = null;
|
|
||||||
FTLPack resP = null;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
int backupsCreated = 0;
|
int backupsCreated = 0;
|
||||||
|
@ -114,20 +115,34 @@ public class ModPatchThread extends Thread {
|
||||||
int modsInstalled = 0;
|
int modsInstalled = 0;
|
||||||
int datsRepacked = 0;
|
int datsRepacked = 0;
|
||||||
|
|
||||||
|
File ftlDatFile = new File( datsDir, "ftl.dat" );
|
||||||
|
File dataDatFile = new File( datsDir, "data.dat" );
|
||||||
|
File resourceDatFile = new File( datsDir, "resource.dat" );
|
||||||
|
|
||||||
|
List<BackedUpDat> backedUpDats = new ArrayList<BackedUpDat>( 2 );
|
||||||
|
for ( File datFile : new File[] {ftlDatFile, dataDatFile, resourceDatFile} ) {
|
||||||
|
if ( !datFile.exists() ) continue;
|
||||||
|
|
||||||
|
BackedUpDat bud = new BackedUpDat();
|
||||||
|
bud.datFile = datFile;
|
||||||
|
bud.bakFile = new File( backupDir, datFile.getName() +".bak" );
|
||||||
|
backedUpDats.add( bud );
|
||||||
|
}
|
||||||
|
|
||||||
// Don't let dats be read-only.
|
// Don't let dats be read-only.
|
||||||
for ( BackedUpDat dat : allDats ) {
|
for ( BackedUpDat bud : backedUpDats ) {
|
||||||
if ( dat.datFile.exists() ) dat.datFile.setWritable( true );
|
if ( bud.datFile.exists() ) bud.datFile.setWritable( true );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create backup dats, if necessary.
|
// Create backup dats, if necessary.
|
||||||
for ( BackedUpDat dat : allDats ) {
|
for ( BackedUpDat bud : backedUpDats ) {
|
||||||
if ( !dat.bakFile.exists() ) {
|
if ( !bud.bakFile.exists() ) {
|
||||||
log.info( String.format( "Backing up \"%s\".", dat.datFile.getName() ) );
|
log.info( String.format( "Backing up \"%s\".", bud.datFile.getName() ) );
|
||||||
observer.patchingStatus( String.format( "Backing up \"%s\".", dat.datFile.getName() ) );
|
observer.patchingStatus( String.format( "Backing up \"%s\".", bud.datFile.getName() ) );
|
||||||
|
|
||||||
PackUtilities.copyFile( dat.datFile, dat.bakFile );
|
PackUtilities.copyFile( bud.datFile, bud.bakFile );
|
||||||
backupsCreated++;
|
backupsCreated++;
|
||||||
observer.patchingProgress( progMilestone + progBackupMax/allDats.length*backupsCreated, progMax );
|
observer.patchingProgress( progMilestone + progBackupMax/backedUpDats.size()*backupsCreated, progMax );
|
||||||
|
|
||||||
if ( !keepRunning ) return false;
|
if ( !keepRunning ) return false;
|
||||||
}
|
}
|
||||||
|
@ -136,17 +151,17 @@ public class ModPatchThread extends Thread {
|
||||||
observer.patchingProgress( progMilestone, progMax );
|
observer.patchingProgress( progMilestone, progMax );
|
||||||
observer.patchingStatus( null );
|
observer.patchingStatus( null );
|
||||||
|
|
||||||
if ( backupsCreated != allDats.length ) {
|
if ( backupsCreated != backedUpDats.size() ) {
|
||||||
// Clobber current dat files with their respective backups.
|
// Clobber current dat files with their respective backups.
|
||||||
// But don't bother if we made those backups just now.
|
// But don't bother if we made those backups just now.
|
||||||
|
|
||||||
for ( BackedUpDat dat : allDats ) {
|
for ( BackedUpDat bud : backedUpDats ) {
|
||||||
log.info( String.format( "Restoring vanilla \"%s\"...", dat.datFile.getName() ) );
|
log.info( String.format( "Restoring vanilla \"%s\"...", bud.datFile.getName() ) );
|
||||||
observer.patchingStatus( String.format( "Restoring vanilla \"%s\"...", dat.datFile.getName() ) );
|
observer.patchingStatus( String.format( "Restoring vanilla \"%s\"...", bud.datFile.getName() ) );
|
||||||
|
|
||||||
PackUtilities.copyFile( dat.bakFile, dat.datFile );
|
PackUtilities.copyFile( bud.bakFile, bud.datFile );
|
||||||
datsClobbered++;
|
datsClobbered++;
|
||||||
observer.patchingProgress( progMilestone + progClobberMax/allDats.length*datsClobbered, progMax );
|
observer.patchingProgress( progMilestone + progClobberMax/backedUpDats.size()*datsClobbered, progMax );
|
||||||
|
|
||||||
if ( !keepRunning ) return false;
|
if ( !keepRunning ) return false;
|
||||||
}
|
}
|
||||||
|
@ -161,30 +176,48 @@ public class ModPatchThread extends Thread {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
dataP = new FTLPack( dataDat.datFile, "r+" );
|
packContainer = new PackContainer();
|
||||||
resP = new FTLPack( resDat.datFile, "r+" );
|
if ( ftlDatFile.exists() ) { // FTL 1.6.1.
|
||||||
|
AbstractPack ftlPack = new PkgPack( ftlDatFile, "r+" );
|
||||||
|
|
||||||
Map<String,AbstractPack> topFolderMap = new HashMap<String,AbstractPack>();
|
packContainer.setPackFor( "audio/", ftlPack );
|
||||||
topFolderMap.put( "data", dataP );
|
packContainer.setPackFor( "data/", ftlPack );
|
||||||
topFolderMap.put( "audio", resP );
|
packContainer.setPackFor( "fonts/", ftlPack );
|
||||||
topFolderMap.put( "fonts", resP );
|
packContainer.setPackFor( "img/", ftlPack );
|
||||||
topFolderMap.put( "img", resP );
|
packContainer.setPackFor( null, ftlPack );
|
||||||
topFolderMap.put( "mod-appendix", null );
|
// Supposedly "exe_icon.png" has been observed at top-level?
|
||||||
|
}
|
||||||
|
else if ( dataDatFile.exists() && resourceDatFile.exists() ) { // FTL 1.01-1.5.13.
|
||||||
|
AbstractPack dataPack = new FTLPack( dataDatFile, "r+" );
|
||||||
|
AbstractPack resourcePack = new FTLPack( resourceDatFile, "r+" );
|
||||||
|
|
||||||
|
packContainer.setPackFor( "audio/", resourcePack );
|
||||||
|
packContainer.setPackFor( "data/", dataPack );
|
||||||
|
packContainer.setPackFor( "fonts/", resourcePack );
|
||||||
|
packContainer.setPackFor( "img/", resourcePack );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new IOException( String.format( "Could not find either \"%s\" or both \"%s\" and \"%s\"", ftlDatFile.getName(), dataDatFile.getName(), resourceDatFile.getName() ) );
|
||||||
|
}
|
||||||
|
packContainer.setPackFor( "mod-appendix/", null );
|
||||||
|
|
||||||
// Track modified innerPaths in case they're clobbered.
|
// Track modified innerPaths in case they're clobbered.
|
||||||
List<String> moddedItems = new ArrayList<String>();
|
List<String> moddedItems = new ArrayList<String>();
|
||||||
|
|
||||||
List<String> knownPaths = new ArrayList<String>();
|
List<String> knownPaths = new ArrayList<String>();
|
||||||
knownPaths.addAll( dataP.list() );
|
for ( AbstractPack pack : packContainer.getPacks() ) {
|
||||||
knownPaths.addAll( resP.list() );
|
knownPaths.addAll( pack.list() );
|
||||||
|
}
|
||||||
|
|
||||||
List<String> knownPathsLower = new ArrayList<String>( knownPaths.size() );
|
List<String> knownPathsLower = new ArrayList<String>( knownPaths.size() );
|
||||||
for ( String innerPath : knownPaths ) {
|
for ( String innerPath : knownPaths ) {
|
||||||
knownPathsLower.add( innerPath.toLowerCase() );
|
knownPathsLower.add( innerPath.toLowerCase() );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Group1: parentPath, Group2: topFolder, Group3: fileName
|
List<String> knownRoots = packContainer.getRoots();
|
||||||
Pattern pathPtn = Pattern.compile( "^(([^/]+)/(?:.*/)?)([^/]+)$" );
|
|
||||||
|
// Group1: parentPath/, Group2: root/, Group3: fileName.
|
||||||
|
Pattern pathPtn = Pattern.compile( "^(?:(([^/]+/)(?:.*/)?))?([^/]+)$" );
|
||||||
|
|
||||||
for ( File modFile : modFiles ) {
|
for ( File modFile : modFiles ) {
|
||||||
if ( !keepRunning ) return false;
|
if ( !keepRunning ) return false;
|
||||||
|
@ -216,12 +249,12 @@ public class ModPatchThread extends Thread {
|
||||||
}
|
}
|
||||||
|
|
||||||
String parentPath = m.group( 1 );
|
String parentPath = m.group( 1 );
|
||||||
String topFolder = m.group( 2 );
|
String root = m.group( 2 );
|
||||||
String fileName = m.group( 3 );
|
String fileName = m.group( 3 );
|
||||||
|
|
||||||
AbstractPack ftlP = topFolderMap.get( topFolder );
|
AbstractPack pack = packContainer.getPackFor( innerPath );
|
||||||
if ( ftlP == null ) {
|
if ( pack == null ) {
|
||||||
if ( !topFolderMap.containsKey( topFolder ) )
|
if ( !knownRoots.contains( root ) )
|
||||||
log.warn( String.format( "Unexpected innerPath: %s", innerPath ) );
|
log.warn( String.format( "Unexpected innerPath: %s", innerPath ) );
|
||||||
zis.closeEntry();
|
zis.closeEntry();
|
||||||
continue;
|
continue;
|
||||||
|
@ -237,24 +270,24 @@ public class ModPatchThread extends Thread {
|
||||||
innerPath = parentPath + fileName.replaceAll( "[.](?:xml[.]append|append[.]xml)$", ".xml" );
|
innerPath = parentPath + fileName.replaceAll( "[.](?:xml[.]append|append[.]xml)$", ".xml" );
|
||||||
innerPath = checkCase( innerPath, knownPaths, knownPathsLower );
|
innerPath = checkCase( innerPath, knownPaths, knownPathsLower );
|
||||||
|
|
||||||
if ( !ftlP.contains( innerPath ) ) {
|
if ( !pack.contains( innerPath ) ) {
|
||||||
log.warn( String.format( "Non-existent innerPath wasn't appended: %s", innerPath ) );
|
log.warn( String.format( "Non-existent innerPath wasn't appended: %s", innerPath ) );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
InputStream mainStream = null;
|
InputStream mainStream = null;
|
||||||
try {
|
try {
|
||||||
mainStream = ftlP.getInputStream(innerPath);
|
mainStream = pack.getInputStream(innerPath);
|
||||||
InputStream mergedStream = ModUtilities.patchXMLFile( mainStream, zis, "windows-1252", globalPanic, ftlP.getName()+":"+innerPath, modFile.getName()+":"+parentPath+fileName );
|
InputStream mergedStream = ModUtilities.patchXMLFile( mainStream, zis, "windows-1252", globalPanic, pack.getName()+":"+innerPath, modFile.getName()+":"+parentPath+fileName );
|
||||||
mainStream.close();
|
mainStream.close();
|
||||||
ftlP.remove( innerPath );
|
pack.remove( innerPath );
|
||||||
ftlP.add( innerPath, mergedStream );
|
pack.add( innerPath, mergedStream );
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
try {if ( mainStream != null ) mainStream.close();}
|
try {if ( mainStream != null ) mainStream.close();}
|
||||||
catch ( IOException e ) {}
|
catch ( IOException e ) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !moddedItems.contains(innerPath) ) {
|
if ( !moddedItems.contains( innerPath ) ) {
|
||||||
moddedItems.add( innerPath );
|
moddedItems.add( innerPath );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -263,25 +296,25 @@ public class ModPatchThread extends Thread {
|
||||||
innerPath = parentPath + fileName.replaceAll( "[.](?:xml[.]rawappend|rawappend[.]xml)$", ".xml" );
|
innerPath = parentPath + fileName.replaceAll( "[.](?:xml[.]rawappend|rawappend[.]xml)$", ".xml" );
|
||||||
innerPath = checkCase( innerPath, knownPaths, knownPathsLower );
|
innerPath = checkCase( innerPath, knownPaths, knownPathsLower );
|
||||||
|
|
||||||
if ( !ftlP.contains( innerPath ) ) {
|
if ( !pack.contains( innerPath ) ) {
|
||||||
log.warn( String.format( "Non-existent innerPath wasn't raw appended: %s", innerPath ) );
|
log.warn( String.format( "Non-existent innerPath wasn't raw appended: %s", innerPath ) );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
log.warn( String.format( "Appending xml as raw text: %s", innerPath ) );
|
log.warn( String.format( "Appending xml as raw text: %s", innerPath ) );
|
||||||
InputStream mainStream = null;
|
InputStream mainStream = null;
|
||||||
try {
|
try {
|
||||||
mainStream = ftlP.getInputStream(innerPath);
|
mainStream = pack.getInputStream( innerPath );
|
||||||
InputStream mergedStream = ModUtilities.appendXMLFile( mainStream, zis, "windows-1252", ftlP.getName()+":"+innerPath, modFile.getName()+":"+parentPath+fileName );
|
InputStream mergedStream = ModUtilities.appendXMLFile( mainStream, zis, "windows-1252", pack.getName()+":"+innerPath, modFile.getName()+":"+parentPath+fileName );
|
||||||
mainStream.close();
|
mainStream.close();
|
||||||
ftlP.remove( innerPath );
|
pack.remove( innerPath );
|
||||||
ftlP.add( innerPath, mergedStream );
|
pack.add( innerPath, mergedStream );
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
try {if ( mainStream != null ) mainStream.close();}
|
try {if ( mainStream != null ) mainStream.close();}
|
||||||
catch ( IOException e ) {}
|
catch ( IOException e ) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !moddedItems.contains(innerPath) ) {
|
if ( !moddedItems.contains( innerPath ) ) {
|
||||||
moddedItems.add( innerPath );
|
moddedItems.add( innerPath );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -299,30 +332,30 @@ public class ModPatchThread extends Thread {
|
||||||
|
|
||||||
InputStream fixedStream = ModUtilities.encodeText( fixedText, "windows-1252", modFile.getName()+":"+parentPath+fileName+" (with new EOL)" );
|
InputStream fixedStream = ModUtilities.encodeText( fixedText, "windows-1252", modFile.getName()+":"+parentPath+fileName+" (with new EOL)" );
|
||||||
|
|
||||||
if ( !moddedItems.contains(innerPath) ) {
|
if ( !moddedItems.contains( innerPath ) ) {
|
||||||
moddedItems.add( innerPath );
|
moddedItems.add( innerPath );
|
||||||
} else {
|
} else {
|
||||||
log.warn( String.format( "Clobbering earlier mods: %s", innerPath ) );
|
log.warn( String.format( "Clobbering earlier mods: %s", innerPath ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ftlP.contains( innerPath ) )
|
if ( pack.contains( innerPath ) )
|
||||||
ftlP.remove( innerPath );
|
pack.remove( innerPath );
|
||||||
ftlP.add( innerPath, fixedStream );
|
pack.add( innerPath, fixedStream );
|
||||||
}
|
}
|
||||||
else if ( fileName.endsWith( ".xml" ) ) {
|
else if ( fileName.endsWith( ".xml" ) ) {
|
||||||
innerPath = checkCase( innerPath, knownPaths, knownPathsLower );
|
innerPath = checkCase( innerPath, knownPaths, knownPathsLower );
|
||||||
|
|
||||||
InputStream fixedStream = ModUtilities.rebuildXMLFile( zis, "windows-1252", modFile.getName()+":"+parentPath+fileName );
|
InputStream fixedStream = ModUtilities.rebuildXMLFile( zis, "windows-1252", modFile.getName()+":"+parentPath+fileName );
|
||||||
|
|
||||||
if ( !moddedItems.contains(innerPath) ) {
|
if ( !moddedItems.contains( innerPath ) ) {
|
||||||
moddedItems.add( innerPath );
|
moddedItems.add( innerPath );
|
||||||
} else {
|
} else {
|
||||||
log.warn( String.format( "Clobbering earlier mods: %s", innerPath ) );
|
log.warn( String.format( "Clobbering earlier mods: %s", innerPath ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ftlP.contains( innerPath ) )
|
if ( pack.contains( innerPath ) )
|
||||||
ftlP.remove( innerPath );
|
pack.remove( innerPath );
|
||||||
ftlP.add( innerPath, fixedStream );
|
pack.add( innerPath, fixedStream );
|
||||||
}
|
}
|
||||||
else if ( fileName.endsWith( ".txt" ) ) {
|
else if ( fileName.endsWith( ".txt" ) ) {
|
||||||
innerPath = checkCase( innerPath, knownPaths, knownPathsLower );
|
innerPath = checkCase( innerPath, knownPaths, knownPathsLower );
|
||||||
|
@ -334,28 +367,28 @@ public class ModPatchThread extends Thread {
|
||||||
|
|
||||||
InputStream fixedStream = ModUtilities.encodeText( fixedText, "windows-1252", modFile.getName()+":"+parentPath+fileName+" (with new EOL)" );
|
InputStream fixedStream = ModUtilities.encodeText( fixedText, "windows-1252", modFile.getName()+":"+parentPath+fileName+" (with new EOL)" );
|
||||||
|
|
||||||
if ( !moddedItems.contains(innerPath) ) {
|
if ( !moddedItems.contains( innerPath ) ) {
|
||||||
moddedItems.add( innerPath );
|
moddedItems.add( innerPath );
|
||||||
} else {
|
} else {
|
||||||
log.warn( String.format( "Clobbering earlier mods: %s", innerPath ) );
|
log.warn( String.format( "Clobbering earlier mods: %s", innerPath ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ftlP.contains( innerPath ) )
|
if ( pack.contains( innerPath ) )
|
||||||
ftlP.remove( innerPath );
|
pack.remove( innerPath );
|
||||||
ftlP.add( innerPath, fixedStream );
|
pack.add( innerPath, fixedStream );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
innerPath = checkCase( innerPath, knownPaths, knownPathsLower );
|
innerPath = checkCase( innerPath, knownPaths, knownPathsLower );
|
||||||
|
|
||||||
if ( !moddedItems.contains(innerPath) ) {
|
if ( !moddedItems.contains( innerPath ) ) {
|
||||||
moddedItems.add( innerPath );
|
moddedItems.add( innerPath );
|
||||||
} else {
|
} else {
|
||||||
log.warn( String.format( "Clobbering earlier mods: %s", innerPath ) );
|
log.warn( String.format( "Clobbering earlier mods: %s", innerPath ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ftlP.contains( innerPath ) )
|
if ( pack.contains( innerPath ) )
|
||||||
ftlP.remove( innerPath );
|
pack.remove( innerPath );
|
||||||
ftlP.add( innerPath, zis );
|
pack.add( innerPath, zis );
|
||||||
}
|
}
|
||||||
|
|
||||||
zis.closeEntry();
|
zis.closeEntry();
|
||||||
|
@ -378,16 +411,17 @@ public class ModPatchThread extends Thread {
|
||||||
observer.patchingProgress( progMilestone, progMax );
|
observer.patchingProgress( progMilestone, progMax );
|
||||||
|
|
||||||
// Prune 'removed' files from dats.
|
// Prune 'removed' files from dats.
|
||||||
for ( AbstractPack ftlP : new AbstractPack[]{dataP, resP} ) {
|
for ( AbstractPack pack : packContainer.getPacks() ) {
|
||||||
if ( ftlP instanceof FTLPack ) {
|
observer.patchingStatus( String.format( "Repacking \"%s\"...", pack.getName() ) );
|
||||||
observer.patchingStatus( String.format( "Repacking \"%s\"...", ftlP.getName() ) );
|
|
||||||
|
|
||||||
long bytesChanged = ((FTLPack)ftlP).repack().bytesChanged;
|
AbstractPack.RepackResult repackResult = pack.repack();
|
||||||
log.info( String.format( "Repacked \"%s\" (%d bytes affected)", ftlP.getName(), bytesChanged ) );
|
if ( repackResult != null ) {
|
||||||
|
long bytesChanged = repackResult.bytesChanged;
|
||||||
datsRepacked++;
|
log.info( String.format( "Repacked \"%s\" (%d bytes affected)", pack.getName(), bytesChanged ) );
|
||||||
observer.patchingProgress( progMilestone + progRepackMax/allDats.length*datsRepacked, progMax );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
datsRepacked++;
|
||||||
|
observer.patchingProgress( progMilestone + progRepackMax/backedUpDats.size()*datsRepacked, progMax );
|
||||||
}
|
}
|
||||||
progMilestone += progRepackMax;
|
progMilestone += progRepackMax;
|
||||||
observer.patchingProgress( progMilestone, progMax );
|
observer.patchingProgress( progMilestone, progMax );
|
||||||
|
@ -396,11 +430,12 @@ public class ModPatchThread extends Thread {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
try {if ( dataP != null ) dataP.close();}
|
if ( packContainer != null ) {
|
||||||
catch( Exception e ) {}
|
for ( AbstractPack pack : packContainer.getPacks() ) {
|
||||||
|
try {pack.close();}
|
||||||
try {if ( resP != null ) resP.close();}
|
catch( Exception e ) {}
|
||||||
catch( Exception e ) {}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,10 @@ package net.vhati.modmanager.ui;
|
||||||
|
|
||||||
import java.awt.Frame;
|
import java.awt.Frame;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.swing.JDialog;
|
import javax.swing.JDialog;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
|
@ -11,6 +13,7 @@ import javax.swing.SwingUtilities;
|
||||||
import net.vhati.ftldat.AbstractPack;
|
import net.vhati.ftldat.AbstractPack;
|
||||||
import net.vhati.ftldat.FolderPack;
|
import net.vhati.ftldat.FolderPack;
|
||||||
import net.vhati.ftldat.FTLPack;
|
import net.vhati.ftldat.FTLPack;
|
||||||
|
import net.vhati.ftldat.PkgPack;
|
||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
@ -22,24 +25,24 @@ public class DatExtractDialog extends ProgressDialog {
|
||||||
|
|
||||||
private boolean started = false;
|
private boolean started = false;
|
||||||
|
|
||||||
private File extractDir;
|
private File extractDir = null;
|
||||||
private File[] datFiles;
|
private File datsDir = null;
|
||||||
|
|
||||||
private DatExtractThread workerThread = null;
|
private DatExtractThread workerThread = null;
|
||||||
|
|
||||||
|
|
||||||
public DatExtractDialog( Frame owner, File extractDir, File[] datFiles ) {
|
public DatExtractDialog( Frame owner, File extractDir, File datsDir ) {
|
||||||
super( owner, false );
|
super( owner, false );
|
||||||
this.setTitle( "Extracting..." );
|
this.setTitle( "Extracting..." );
|
||||||
|
|
||||||
this.extractDir = extractDir;
|
this.extractDir = extractDir;
|
||||||
this.datFiles = datFiles;
|
this.datsDir = datsDir;
|
||||||
|
|
||||||
this.setSize( 400, 160 );
|
this.setSize( 400, 160 );
|
||||||
this.setMinimumSize( this.getPreferredSize() );
|
this.setMinimumSize( this.getPreferredSize() );
|
||||||
this.setLocationRelativeTo( owner );
|
this.setLocationRelativeTo( owner );
|
||||||
|
|
||||||
workerThread = new DatExtractThread( extractDir, datFiles );
|
workerThread = new DatExtractThread( extractDir, datsDir );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -79,59 +82,79 @@ public class DatExtractDialog extends ProgressDialog {
|
||||||
|
|
||||||
private class DatExtractThread extends Thread {
|
private class DatExtractThread extends Thread {
|
||||||
|
|
||||||
private File extractDir;
|
private File extractDir = null;
|
||||||
private File[] datFiles;
|
private File datsDir = null;
|
||||||
|
|
||||||
public DatExtractThread( File extractDir, File[] datFiles ) {
|
|
||||||
|
public DatExtractThread( File extractDir, File datsDir ) {
|
||||||
this.extractDir = extractDir;
|
this.extractDir = extractDir;
|
||||||
this.datFiles = datFiles;
|
this.datsDir = datsDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
AbstractPack srcP = null;
|
AbstractPack dstPack = null;
|
||||||
AbstractPack dstP = null;
|
List<AbstractPack> srcPacks = new ArrayList<AbstractPack>( 2 );
|
||||||
InputStream is = null;
|
InputStream is = null;
|
||||||
int progress = 0;
|
int progress = 0;
|
||||||
|
|
||||||
try {
|
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();
|
if ( !extractDir.exists() ) extractDir.mkdirs();
|
||||||
|
|
||||||
dstP = new FolderPack( extractDir );
|
dstPack = new FolderPack( extractDir );
|
||||||
|
|
||||||
for ( File datFile : datFiles ) {
|
for ( AbstractPack srcPack : srcPacks ) {
|
||||||
srcP = new FTLPack( datFile, "r" );
|
|
||||||
progress = 0;
|
progress = 0;
|
||||||
List<String> innerPaths = srcP.list();
|
List<String> innerPaths = srcPack.list();
|
||||||
setProgressLater( progress, innerPaths.size() );
|
setProgressLater( progress, innerPaths.size() );
|
||||||
|
|
||||||
for ( String innerPath : innerPaths ) {
|
for ( String innerPath : innerPaths ) {
|
||||||
setStatusTextLater( innerPath );
|
setStatusTextLater( innerPath );
|
||||||
if ( dstP.contains( innerPath ) ) {
|
if ( dstPack.contains( innerPath ) ) {
|
||||||
log.info( "While extracting resources, this file was overwritten: "+ innerPath );
|
log.info( "While extracting resources, this file was overwritten: "+ innerPath );
|
||||||
dstP.remove( innerPath );
|
dstPack.remove( innerPath );
|
||||||
}
|
}
|
||||||
is = srcP.getInputStream( innerPath );
|
is = srcPack.getInputStream( innerPath );
|
||||||
dstP.add( innerPath, is );
|
dstPack.add( innerPath, is );
|
||||||
setProgressLater( progress++ );
|
setProgressLater( progress++ );
|
||||||
}
|
}
|
||||||
srcP.close();
|
srcPack.close();
|
||||||
}
|
}
|
||||||
setTaskOutcomeLater( true, null );
|
setTaskOutcomeLater( true, null );
|
||||||
}
|
}
|
||||||
catch ( Exception e ) {
|
catch ( Exception e ) {
|
||||||
log.error( "Error extracting dats.", e );
|
log.error( "Error extracting dats", e );
|
||||||
setTaskOutcomeLater( false, e );
|
setTaskOutcomeLater( false, e );
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
try {if ( is != null ) is.close();}
|
try {if ( is != null ) is.close();}
|
||||||
catch ( IOException e ) {}
|
catch ( IOException e ) {}
|
||||||
|
|
||||||
try {if ( srcP != null ) srcP.close();}
|
try {if ( dstPack != null ) dstPack.close();}
|
||||||
catch ( IOException e ) {}
|
catch ( IOException e ) {}
|
||||||
|
|
||||||
try {if ( dstP != null ) dstP.close();}
|
for ( AbstractPack pack : srcPacks ) {
|
||||||
catch ( IOException e ) {}
|
try {pack.close();}
|
||||||
|
catch ( IOException ex ) {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,7 +60,6 @@ import net.vhati.modmanager.core.ModDB;
|
||||||
import net.vhati.modmanager.core.ModFileInfo;
|
import net.vhati.modmanager.core.ModFileInfo;
|
||||||
import net.vhati.modmanager.core.ModInfo;
|
import net.vhati.modmanager.core.ModInfo;
|
||||||
import net.vhati.modmanager.core.ModPatchThread;
|
import net.vhati.modmanager.core.ModPatchThread;
|
||||||
import net.vhati.modmanager.core.ModPatchThread.BackedUpDat;
|
|
||||||
import net.vhati.modmanager.core.ModsScanObserver;
|
import net.vhati.modmanager.core.ModsScanObserver;
|
||||||
import net.vhati.modmanager.core.ModsScanThread;
|
import net.vhati.modmanager.core.ModsScanThread;
|
||||||
import net.vhati.modmanager.core.ModUtilities;
|
import net.vhati.modmanager.core.ModUtilities;
|
||||||
|
@ -666,13 +665,6 @@ public class ManagerFrame extends JFrame implements ActionListener, ModsScanObse
|
||||||
|
|
||||||
File datsDir = new File( appConfig.getProperty( "ftl_dats_path" ) );
|
File datsDir = new File( appConfig.getProperty( "ftl_dats_path" ) );
|
||||||
|
|
||||||
BackedUpDat dataDat = new BackedUpDat();
|
|
||||||
dataDat.datFile = new File( datsDir, "data.dat" );
|
|
||||||
dataDat.bakFile = new File( backupDir, "data.dat.bak" );
|
|
||||||
BackedUpDat resDat = new BackedUpDat();
|
|
||||||
resDat.datFile = new File( datsDir, "resource.dat" );
|
|
||||||
resDat.bakFile = new File( backupDir, "resource.dat.bak" );
|
|
||||||
|
|
||||||
ModPatchDialog patchDlg = new ModPatchDialog( this, true );
|
ModPatchDialog patchDlg = new ModPatchDialog( this, true );
|
||||||
|
|
||||||
String neverRunFtl = appConfig.getProperty( "never_run_ftl", "false" );
|
String neverRunFtl = appConfig.getProperty( "never_run_ftl", "false" );
|
||||||
|
@ -705,7 +697,7 @@ public class ManagerFrame extends JFrame implements ActionListener, ModsScanObse
|
||||||
log.info( "" );
|
log.info( "" );
|
||||||
log.info( "Patching..." );
|
log.info( "Patching..." );
|
||||||
log.info( "" );
|
log.info( "" );
|
||||||
ModPatchThread patchThread = new ModPatchThread( modFiles, dataDat, resDat, false, patchDlg );
|
ModPatchThread patchThread = new ModPatchThread( modFiles, datsDir, backupDir, false, patchDlg );
|
||||||
patchThread.setDefaultUncaughtExceptionHandler( this );
|
patchThread.setDefaultUncaughtExceptionHandler( this );
|
||||||
patchThread.start();
|
patchThread.start();
|
||||||
|
|
||||||
|
@ -780,11 +772,8 @@ public class ManagerFrame extends JFrame implements ActionListener, ModsScanObse
|
||||||
File extractDir = extractChooser.getSelectedFile();
|
File extractDir = extractChooser.getSelectedFile();
|
||||||
|
|
||||||
File datsDir = new File( appConfig.getProperty( "ftl_dats_path" ) );
|
File datsDir = new File( appConfig.getProperty( "ftl_dats_path" ) );
|
||||||
File dataDatFile = new File( datsDir, "data.dat" );
|
|
||||||
File resDatFile = new File( datsDir, "resource.dat" );
|
|
||||||
File[] datFiles = new File[] {dataDatFile, resDatFile};
|
|
||||||
|
|
||||||
DatExtractDialog extractDlg = new DatExtractDialog( this, extractDir, datFiles );
|
DatExtractDialog extractDlg = new DatExtractDialog( this, extractDir, datsDir );
|
||||||
extractDlg.getWorkerThread().setDefaultUncaughtExceptionHandler( this );
|
extractDlg.getWorkerThread().setDefaultUncaughtExceptionHandler( this );
|
||||||
extractDlg.extract();
|
extractDlg.extract();
|
||||||
extractDlg.setVisible( true );
|
extractDlg.setVisible( true );
|
||||||
|
@ -792,9 +781,8 @@ public class ManagerFrame extends JFrame implements ActionListener, ModsScanObse
|
||||||
else if ( source == sandboxMenuItem ) {
|
else if ( source == sandboxMenuItem ) {
|
||||||
setStatusText( "" );
|
setStatusText( "" );
|
||||||
File datsDir = new File( appConfig.getProperty( "ftl_dats_path" ) );
|
File datsDir = new File( appConfig.getProperty( "ftl_dats_path" ) );
|
||||||
File dataDatFile = new File( datsDir, "data.dat" );
|
|
||||||
|
|
||||||
ModXMLSandbox sandboxFrame = new ModXMLSandbox( dataDatFile );
|
ModXMLSandbox sandboxFrame = new ModXMLSandbox( datsDir );
|
||||||
sandboxFrame.addWindowListener( nerfListener );
|
sandboxFrame.addWindowListener( nerfListener );
|
||||||
sandboxFrame.setSize( 800, 600 );
|
sandboxFrame.setSize( 800, 600 );
|
||||||
sandboxFrame.setLocationRelativeTo( null );
|
sandboxFrame.setLocationRelativeTo( null );
|
||||||
|
|
|
@ -13,6 +13,7 @@ import java.awt.event.KeyEvent;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
|
@ -54,7 +55,9 @@ import javax.swing.tree.TreePath;
|
||||||
import javax.swing.undo.CannotRedoException;
|
import javax.swing.undo.CannotRedoException;
|
||||||
import javax.swing.undo.UndoManager;
|
import javax.swing.undo.UndoManager;
|
||||||
|
|
||||||
|
import net.vhati.ftldat.AbstractPack;
|
||||||
import net.vhati.ftldat.FTLPack;
|
import net.vhati.ftldat.FTLPack;
|
||||||
|
import net.vhati.ftldat.PkgPack;
|
||||||
import net.vhati.modmanager.core.ModUtilities;
|
import net.vhati.modmanager.core.ModUtilities;
|
||||||
import net.vhati.modmanager.core.SloppyXMLOutputProcessor;
|
import net.vhati.modmanager.core.SloppyXMLOutputProcessor;
|
||||||
import net.vhati.modmanager.core.XMLPatcher;
|
import net.vhati.modmanager.core.XMLPatcher;
|
||||||
|
@ -72,7 +75,7 @@ public class ModXMLSandbox extends JFrame implements ActionListener {
|
||||||
private UndoManager undoManager = new UndoManager();
|
private UndoManager undoManager = new UndoManager();
|
||||||
private Document mainDoc = null;
|
private Document mainDoc = null;
|
||||||
|
|
||||||
private File dataDatFile;
|
private File datsDir;
|
||||||
|
|
||||||
private JTabbedPane areasPane;
|
private JTabbedPane areasPane;
|
||||||
private JScrollPane mainScroll;
|
private JScrollPane mainScroll;
|
||||||
|
@ -91,11 +94,11 @@ public class ModXMLSandbox extends JFrame implements ActionListener {
|
||||||
private JLabel statusLbl;
|
private JLabel statusLbl;
|
||||||
|
|
||||||
|
|
||||||
public ModXMLSandbox( File dataDatFile ) {
|
public ModXMLSandbox( File datsDir ) {
|
||||||
super( "Mod XML Sandbox" );
|
super( "Mod XML Sandbox" );
|
||||||
this.setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );
|
this.setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );
|
||||||
|
|
||||||
this.dataDatFile = dataDatFile;
|
this.datsDir = datsDir;
|
||||||
|
|
||||||
Font sandboxFont = new Font( "Monospaced", Font.PLAIN, 13 );
|
Font sandboxFont = new Font( "Monospaced", Font.PLAIN, 13 );
|
||||||
|
|
||||||
|
@ -319,17 +322,29 @@ public class ModXMLSandbox extends JFrame implements ActionListener {
|
||||||
private void open() {
|
private void open() {
|
||||||
messageArea.setText( "" );
|
messageArea.setText( "" );
|
||||||
|
|
||||||
FTLPack dataP = null;
|
AbstractPack pack = null;
|
||||||
InputStream is = null;
|
InputStream is = null;
|
||||||
try {
|
try {
|
||||||
dataP = new FTLPack( dataDatFile, "r" );
|
File ftlDatFile = new File( datsDir, "ftl.dat" );
|
||||||
List<String> innerPaths = dataP.list();
|
File dataDatFile = new File( datsDir, "data.dat" );
|
||||||
|
|
||||||
|
if ( ftlDatFile.exists() ) { // FTL 1.6.1.
|
||||||
|
pack = new PkgPack( ftlDatFile, "r" );
|
||||||
|
}
|
||||||
|
else if ( dataDatFile.exists() ) { // FTL 1.01-1.5.13.
|
||||||
|
pack = new FTLPack( dataDatFile, "r" );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new FileNotFoundException( String.format( "Could not find either \"%s\" or \"%s\"", ftlDatFile.getName(), dataDatFile.getName() ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> innerPaths = pack.list();
|
||||||
|
|
||||||
String innerPath = promptForInnerPath( innerPaths );
|
String innerPath = promptForInnerPath( innerPaths );
|
||||||
if ( innerPath == null ) return;
|
if ( innerPath == null ) return;
|
||||||
|
|
||||||
is = dataP.getInputStream( innerPath );
|
is = pack.getInputStream( innerPath );
|
||||||
String mainText = ModUtilities.decodeText( is, dataDatFile.getName()+":"+innerPath ).text;
|
String mainText = ModUtilities.decodeText( is, pack.getName()+":"+innerPath ).text;
|
||||||
is.close();
|
is.close();
|
||||||
|
|
||||||
mainText = mainText.replaceFirst( "<[?]xml [^>]*?[?]>", "" );
|
mainText = mainText.replaceFirst( "<[?]xml [^>]*?[?]>", "" );
|
||||||
|
@ -356,7 +371,7 @@ public class ModXMLSandbox extends JFrame implements ActionListener {
|
||||||
try {if ( is != null ) is.close();}
|
try {if ( is != null ) is.close();}
|
||||||
catch ( IOException f ) {}
|
catch ( IOException f ) {}
|
||||||
|
|
||||||
try {if ( dataP != null ) dataP.close();}
|
try {if ( pack != null ) pack.close();}
|
||||||
catch ( IOException f ) {}
|
catch ( IOException f ) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue