ViewVC Help
View File | Revision Log | View Changeset | Root Listing
root/Oni2/java/installer2/src/net/oni2/aeinstaller/backend/oni/management/Installer.java
Revision: 1082
Committed: Sat Oct 21 12:12:34 2017 UTC (7 years, 11 months ago) by alloc
Content type: text/x-java
File size: 26491 byte(s)
Log Message:
AEI 2.28, fixes #126

File Contents

# Content
1 package net.oni2.aeinstaller.backend.oni.management;
2
3 import java.io.File;
4 import java.io.FileFilter;
5 import java.io.FileNotFoundException;
6 import java.io.FileOutputStream;
7 import java.io.FilenameFilter;
8 import java.io.IOException;
9 import java.io.InputStream;
10 import java.io.OutputStreamWriter;
11 import java.io.PrintWriter;
12 import java.io.UnsupportedEncodingException;
13 import java.text.SimpleDateFormat;
14 import java.util.Date;
15 import java.util.HashSet;
16 import java.util.List;
17 import java.util.TreeMap;
18 import java.util.TreeSet;
19 import java.util.Vector;
20 import java.util.regex.Pattern;
21
22 import net.oni2.SettingsManager;
23 import net.oni2.aeinstaller.AEInstaller2;
24 import net.oni2.aeinstaller.backend.CaseInsensitiveFile;
25 import net.oni2.aeinstaller.backend.Paths;
26 import net.oni2.aeinstaller.backend.RuntimeOptions;
27 import net.oni2.aeinstaller.backend.oni.OniSplit;
28 import net.oni2.aeinstaller.backend.oni.PersistDat;
29 import net.oni2.aeinstaller.backend.oni.XMLTools;
30 import net.oni2.aeinstaller.backend.oni.management.tools.ToolFileIterator;
31 import net.oni2.aeinstaller.backend.oni.management.tools.ToolFileIteratorEntry;
32 import net.oni2.aeinstaller.backend.oni.management.tools.ToolInstallationList;
33 import net.oni2.aeinstaller.backend.packages.EBSLInstallType;
34 import net.oni2.aeinstaller.backend.packages.Package;
35 import net.oni2.aeinstaller.backend.packages.PackageManager;
36 import net.oni2.platformtools.PlatformInformation;
37 import net.oni2.platformtools.PlatformInformation.Platform;
38 import net.oni2.platformtools.applicationinvoker.ApplicationInvocationResult;
39
40 import org.apache.commons.io.FileUtils;
41 import org.apache.commons.io.filefilter.RegexFileFilter;
42 import org.apache.commons.io.filefilter.TrueFileFilter;
43 import org.javabuilders.swing.SwingJavaBuilder;
44
45 import com.paour.NaturalOrderComparator;
46
47 /**
48 * @author Christian Illy
49 */
50 public class Installer {
51 private static FileFilter dirFileFilter = new FileFilter() {
52 @Override
53 public boolean accept(File pathname) {
54 return pathname.isDirectory();
55 }
56 };
57
58 /**
59 * Verify that the Edition is within a subfolder to vanilla Oni
60 * (..../Oni/Edition/AEInstaller)
61 *
62 * @return true if GDF can be found in the parent's parent-path
63 */
64 public static boolean verifyRunningDirectory() {
65 return Paths.getVanillaGDF().exists()
66 && Paths.getVanillaGDF().isDirectory();
67 }
68
69 /**
70 * @return Is Edition Core initialized
71 */
72 public static boolean isEditionInitialized() {
73 return Paths.getVanillaOnisPath().exists();
74 }
75
76 /**
77 * Install the given set of mods
78 *
79 * @param mods
80 * Mods to install
81 * @param listener
82 * Listener for install progress updates
83 */
84 public static void install(TreeSet<Package> mods,
85 InstallProgressListener listener) {
86 File logFile = new File(Paths.getInstallerPath(), "Installation.log");
87 Logger log = null;
88 try {
89 log = new Logger(logFile);
90 } catch (FileNotFoundException e) {
91 e.printStackTrace();
92 }
93 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
94 Date start = new Date();
95 log.println("Installation of mods started at " + sdf.format(start));
96
97 log.println();
98 log.println("AEI2 version: "
99 + SwingJavaBuilder.getConfig().getResource("appversion"));
100
101 ToolInstallationList til = ToolInstallationList.getInstance();
102 log.println("Installed tools:");
103 for (Package t : PackageManager.getInstance().getInstalledTools()) {
104 log.println(String.format(" - %s (%s)", t.getName(), t.getVersion())
105 + (til.isModified(t.getPackageNumber()) ? " (! LOCALLY MODIFIED !)"
106 : ""));
107 }
108 log.println("Core mods:");
109 for (Package m : mods) {
110 if (m.isCorePackage()) {
111 log.println(String.format(" - %s (%s)", m.getName(), m.getVersion()));
112 }
113 }
114 log.println("Selected mods:");
115 for (Package m : mods) {
116 if (!m.isCorePackage()) {
117 log.println(String.format(" - %s (%s)", m.getName(), m.getVersion()));
118 }
119 }
120 log.println();
121
122 HashSet<String> levelsAffectedBefore = null;
123 if (ModInstallationList.getInstance().isLoadedFromFile()) {
124 levelsAffectedBefore = ModInstallationList.getInstance()
125 .getAffectedLevels();
126 }
127 HashSet<String> levelsAffectedNow = new HashSet<String>();
128
129 File IGMD = new File(Paths.getEditionGDF(), "IGMD");
130 if (IGMD.exists()) {
131 for (File f : IGMD.listFiles(new FileFilter() {
132 @Override
133 public boolean accept(File pathname) {
134 return pathname.isDirectory();
135 }
136 })) {
137 File ignore = CaseInsensitiveFile.getCaseInsensitiveFile(f,
138 "ignore.txt");
139 if (!ignore.exists()) {
140 try {
141 FileUtils.deleteDirectory(f);
142 } catch (IOException e) {
143 e.printStackTrace();
144 }
145 }
146 }
147 }
148
149 TreeSet<Integer> unlockLevels = new TreeSet<Integer>();
150
151 Vector<File> foldersOni = new Vector<File>();
152 foldersOni.add(Paths.getVanillaOnisPath());
153
154 Vector<File> foldersPatches = new Vector<File>();
155
156 for (Package m : mods) {
157 for (int lev : m.getUnlockLevels())
158 unlockLevels.add(lev);
159
160 File oni = CaseInsensitiveFile.getCaseInsensitiveFile(
161 m.getLocalPath(), "oni");
162 if (oni.exists()) {
163 if (m.hasSeparatePlatformDirs()) {
164 File oniCommon = CaseInsensitiveFile
165 .getCaseInsensitiveFile(oni, "common");
166 File oniMac = CaseInsensitiveFile.getCaseInsensitiveFile(
167 oni, "mac_only");
168 File oniWin = CaseInsensitiveFile.getCaseInsensitiveFile(
169 oni, "win_only");
170 if (oniCommon.exists())
171 foldersOni.add(oniCommon);
172 if (PlatformInformation.getPlatform() == Platform.MACOS
173 && oniMac.exists())
174 foldersOni.add(oniMac);
175 else if (oniWin.exists())
176 foldersOni.add(oniWin);
177 } else {
178 foldersOni.add(oni);
179 }
180 }
181
182 File patches = CaseInsensitiveFile.getCaseInsensitiveFile(
183 m.getLocalPath(), "patches");
184 if (patches.exists()) {
185 if (m.hasSeparatePlatformDirs()) {
186 File patchesCommon = CaseInsensitiveFile
187 .getCaseInsensitiveFile(patches, "common");
188 File patchesMac = CaseInsensitiveFile
189 .getCaseInsensitiveFile(patches, "mac_only");
190 File patchesWin = CaseInsensitiveFile
191 .getCaseInsensitiveFile(patches, "win_only");
192 if (patchesCommon.exists())
193 foldersPatches.add(patchesCommon);
194 if (PlatformInformation.getPlatform() == Platform.MACOS
195 && patchesMac.exists())
196 foldersPatches.add(patchesMac);
197 else if (patchesWin.exists())
198 foldersPatches.add(patchesWin);
199 } else {
200 foldersPatches.add(patches);
201 }
202 }
203 }
204
205 TreeMap<String, Vector<File>> levels = new TreeMap<String, Vector<File>>(
206 new NaturalOrderComparator());
207 log.println("Building sources list");
208 for (File path : foldersOni) {
209 log.println("\tFolder " + path.getPath());
210 for (File levelF : path.listFiles()) {
211 boolean isSecondaryFile = false;
212 log.println("\t\tFolder/file " + levelF.getPath());
213 String fn = levelF.getName().toLowerCase();
214 String levelN = null;
215 if (levelF.isDirectory()) {
216 levelN = fn;
217 levelsAffectedNow.add(fn.toLowerCase());
218 } else if (fn.endsWith(".dat")) {
219 levelN = fn.substring(0, fn.lastIndexOf('.')).toLowerCase();
220 } else if (fn.endsWith(".raw") || fn.endsWith(".sep")) {
221 isSecondaryFile = true;
222 }
223 if (levelN != null) {
224 log.println("\t\t\tAdded for level " + levelN);
225 if (!levels.containsKey(levelN))
226 levels.put(levelN, new Vector<File>());
227 levels.get(levelN).add(levelF);
228 } else if (!isSecondaryFile) {
229 if (fn.equalsIgnoreCase(".DS_Store")) {
230 // Ignore OSX bullshit
231 } else {
232 log.println("\t\t\tNot a level file!?");
233 }
234 }
235 }
236 }
237
238 Paths.getEditionGDF().mkdirs();
239 for (File f : Paths.getEditionGDF().listFiles(new FilenameFilter() {
240 public boolean accept(File arg0, String arg1) {
241 String s = arg1.toLowerCase();
242 return s.endsWith(".dat")
243 || s.endsWith(".raw")
244 || s.endsWith(".sep")
245 || (s.equals("intro.bik") && !SettingsManager
246 .getInstance().get("copyintro", false))
247 || (s.equals("outro.bik") && !SettingsManager
248 .getInstance().get("copyoutro", false));
249 }
250 })) {
251 String l = f.getName().toLowerCase();
252 l = l.substring(0, l.length() - 4);
253 if ((levelsAffectedBefore == null)
254 || levelsAffectedBefore.contains(l)
255 || levelsAffectedNow.contains(l))
256 f.delete();
257 }
258
259 applyPatches(levels, foldersPatches, listener, log);
260
261 TreeSet<String> levelsAffectedBoth = null;
262 if (levelsAffectedBefore != null) {
263 levelsAffectedBoth = new TreeSet<String>();
264 levelsAffectedBoth.addAll(levelsAffectedBefore);
265 levelsAffectedBoth.addAll(levelsAffectedNow);
266 }
267
268 combineBinaryFiles(levels, levelsAffectedBoth, listener, log);
269
270 try {
271 combineBSLFolders(mods, listener, log);
272 } catch (IOException e) {
273 log.println("Failed installing BSL files, see aei-output.log for stacktrace");
274 e.printStackTrace();
275 }
276
277 copyPlainFiles (log, mods, listener);
278
279 copyVideos(log);
280
281 if (unlockLevels.size() > 0) {
282 unlockLevels(unlockLevels, log);
283 }
284
285 ModInstallationList mil = ModInstallationList.getInstance();
286 mil.setAffectedLevels(levelsAffectedNow);
287 TreeSet<Integer> modsInstalled = new TreeSet<Integer>();
288 for (Package p : mods) {
289 modsInstalled.add(p.getPackageNumber());
290 }
291 mil.setInstalledMods(modsInstalled);
292 mil.saveList();
293
294 log.println();
295 Date end = new Date();
296 log.println("Installation ended at " + sdf.format(end));
297 log.println("Process took "
298 + ((end.getTime() - start.getTime()) / 1000) + " seconds");
299 log.close();
300 }
301
302 private static void combineBSLFolders(TreeSet<Package> mods,
303 InstallProgressListener listener, Logger log) throws IOException {
304 listener.installProgressUpdate(95, 100, AEInstaller2.globalBundle.getString("modInstaller.installBsl"));
305 log.println();
306 log.println("Installing BSL files");
307
308 // First install core non-addon mods
309 log.println("\tCore, non-addon");
310 for (Package m : mods) {
311 if (m.isCorePackage() && m.getBSLInstallType() == EBSLInstallType.NORMAL) {
312 handleModBsl (m, log, null);
313 }
314 }
315
316 // Now overwrite / add files coming from core addons
317 log.println("\tCore, addon");
318 for (Package m : mods) {
319 if (m.isCorePackage() && m.getBSLInstallType() == EBSLInstallType.ADDON) {
320 handleModBsl (m, log, null);
321 }
322 }
323
324 // Install non-core non-addon mods (levels affected here are first cleaned up)
325 log.println("\tNon-core, non-addon");
326 HashSet<String> clearedFolders = new HashSet<String>();
327 for (Package m : mods) {
328 if (!m.isCorePackage() && m.getBSLInstallType() == EBSLInstallType.NORMAL) {
329 handleModBsl (m, log, clearedFolders);
330 }
331 }
332
333 // Lastly overwrite / add files coming from non-core addons
334 log.println("\tNon-core, addon");
335 for (Package m : mods) {
336 if (!m.isCorePackage() && m.getBSLInstallType() == EBSLInstallType.ADDON) {
337 handleModBsl (m, log, null);
338 }
339 }
340
341
342
343 }
344
345 private static void handleModBsl(Package sourceMod, Logger log, HashSet<String> clearedFolders) throws IOException {
346 File bslFolder = CaseInsensitiveFile.getCaseInsensitiveFile(
347 sourceMod.getLocalPath(), "bsl");
348 if (bslFolder.exists()) {
349 if (sourceMod.hasSeparatePlatformDirs()) {
350 File bslCommonFolder = CaseInsensitiveFile
351 .getCaseInsensitiveFile(bslFolder, "common");
352 File bslMacFolder = CaseInsensitiveFile.getCaseInsensitiveFile(
353 bslFolder, "mac_only");
354 File bslWinFolder = CaseInsensitiveFile.getCaseInsensitiveFile(
355 bslFolder, "win_only");
356
357 if (bslCommonFolder.exists()) {
358 copyBsl(sourceMod, log, bslCommonFolder, sourceMod.getBSLInstallType() == EBSLInstallType.ADDON, clearedFolders);
359 }
360
361 if (bslWinFolder.exists() && (PlatformInformation.getPlatform() == Platform.WIN || PlatformInformation
362 .getPlatform() == Platform.LINUX)) {
363 copyBsl(sourceMod, log, bslCommonFolder, sourceMod.getBSLInstallType() == EBSLInstallType.ADDON, clearedFolders);
364 }
365
366 if (bslMacFolder.exists() && PlatformInformation.getPlatform() == Platform.MACOS) {
367 copyBsl(sourceMod, log, bslCommonFolder, sourceMod.getBSLInstallType() == EBSLInstallType.ADDON, clearedFolders);
368 }
369 } else {
370 copyBsl(sourceMod, log, bslFolder, sourceMod.getBSLInstallType() == EBSLInstallType.ADDON, clearedFolders);
371 }
372 }
373
374 }
375
376 private static void copyBsl(Package sourceMod, Logger log, File sourceModFolder, boolean overwriteFiles, HashSet<String> clearedFolders) throws IOException {
377 File targetBaseFolder = new File(Paths.getEditionGDF(), "IGMD");
378 if (!targetBaseFolder.exists())
379 targetBaseFolder.mkdir();
380
381 log.println("\t\tMod \"" + sourceMod.getName() + "\"");
382 for (File sourceLevelFolder : sourceModFolder.listFiles(dirFileFilter)) {
383 log.println("\t\t\t" + sourceLevelFolder.getName() + " (from " + sourceModFolder.getName() + ")");
384
385 File targetLevelFolder = new File(targetBaseFolder, sourceLevelFolder.getName());
386
387 if (!(CaseInsensitiveFile.getCaseInsensitiveFile(targetLevelFolder,
388 "ignore.txt").exists())) {
389 // Ignore feature: Don't apply any changes to the target level folder if it contains an "ignore.txt" file
390 log.println("\t\t\t\tSkipping level, target contains an \"ignore.txt\" file");
391 continue;
392 }
393
394 if (clearedFolders != null && targetLevelFolder.exists() && !clearedFolders.contains(targetLevelFolder.getName())) {
395 // We are in a clear-folders step and this target folder hasn't been cleared so far -> clear (aka delete) the target folder
396 log.println("\t\t\t\tClearing target, first non-core mod that applies changes to this level");
397 FileUtils.deleteDirectory(targetLevelFolder);
398 }
399
400 if (!targetLevelFolder.exists()) {
401 targetLevelFolder.mkdir();
402 if (clearedFolders != null) {
403 // Clear-folders step and the target folder did not exist (or was removed for clearing) -> this folder counts as cleared
404 clearedFolders.add(targetLevelFolder.getName());
405 }
406 }
407
408 for (File sourceBslFile : sourceLevelFolder.listFiles()) {
409 if (sourceBslFile.getName().toLowerCase().endsWith(".bsl")) {
410 File targetFile = new File(targetLevelFolder, sourceBslFile.getName());
411 if (overwriteFiles || !targetFile.exists()) {
412 // Copy every BSL file from source to target if it either does not yet exist in target or we're currently applying addons (thus overwriting files):
413 if (targetFile.exists()) {
414 log.println("\t\t\t\tOverwriting file from addon: \"" + sourceBslFile.getName() + "\"");
415 }
416 FileUtils.copyFile(sourceBslFile, targetFile);
417 } else {
418 // Non-addon mod, target already exists, skip file
419 log.println("\t\t\t\tSkipping file \"" + sourceBslFile.getName() + "\", target already exists");
420 }
421 }
422 }
423
424 }
425
426 }
427
428 /*
429 private static void copyBSL(Package sourceMod, boolean addon, Logger log) {
430 File targetBaseFolder = new File(Paths.getEditionGDF(), "IGMD");
431 if (!targetBaseFolder.exists())
432 targetBaseFolder.mkdir();
433
434 Vector<File> sources = new Vector<File>();
435 File bsl = CaseInsensitiveFile.getCaseInsensitiveFile(
436 sourceMod.getLocalPath(), "bsl");
437 if (sourceMod.hasSeparatePlatformDirs()) {
438 File bslCommon = CaseInsensitiveFile.getCaseInsensitiveFile(bsl,
439 "common");
440 File bslMac = CaseInsensitiveFile.getCaseInsensitiveFile(bsl,
441 "mac_only");
442 File bslWin = CaseInsensitiveFile.getCaseInsensitiveFile(bsl,
443 "win_only");
444 if (PlatformInformation.getPlatform() == Platform.MACOS
445 && bslMac.exists()) {
446 for (File f : bslMac.listFiles(dirFileFilter)) {
447 File targetBSL = new File(targetBaseFolder, f.getName());
448 if (addon || !targetBSL.exists())
449 sources.add(f);
450 }
451 }
452 if ((PlatformInformation.getPlatform() == Platform.WIN || PlatformInformation
453 .getPlatform() == Platform.LINUX) && bslWin.exists()) {
454 for (File f : bslWin.listFiles(dirFileFilter)) {
455 File targetBSL = new File(targetBaseFolder, f.getName());
456 if (addon || !targetBSL.exists())
457 sources.add(f);
458 }
459 }
460 if (bslCommon.exists()) {
461 for (File f : bslCommon.listFiles(dirFileFilter)) {
462 File targetBSL = new File(targetBaseFolder, f.getName());
463 if (addon || !targetBSL.exists())
464 sources.add(f);
465 }
466 }
467 } else {
468 for (File f : bsl.listFiles(dirFileFilter)) {
469 File targetBSL = new File(targetBaseFolder, f.getName());
470 if (addon || !targetBSL.exists())
471 sources.add(f);
472 }
473 }
474
475 log.println("\tMod \"" + sourceMod.getName() + "\"");
476 for (File f : sources) {
477 log.println("\t\t" + f.getName());
478 File targetPath = new File(targetBaseFolder, f.getName());
479 if (!targetPath.exists())
480 targetPath.mkdir();
481 if (!(CaseInsensitiveFile.getCaseInsensitiveFile(targetPath,
482 "ignore.txt").exists())) {
483 for (File fbsl : f.listFiles()) {
484 if (fbsl.getName().toLowerCase().endsWith(".bsl")) {
485 File targetFile = new File(targetPath, fbsl.getName());
486 if (addon || !targetFile.exists()) {
487 try {
488 FileUtils.copyFile(fbsl, targetFile);
489 } catch (IOException e) {
490 e.printStackTrace();
491 }
492 }
493 }
494 }
495 }
496 }
497 }
498 */
499
500 private static void applyPatches(
501 TreeMap<String, Vector<File>> oniLevelFolders,
502 List<File> patchFolders, InstallProgressListener listener,
503 Logger log) {
504 log.println();
505 log.println("Applying XML patches");
506 listener.installProgressUpdate(0, 1, AEInstaller2.globalBundle.getString("modInstaller.applyXmlPatches"));
507
508 long startMS = new Date().getTime();
509
510 String tmpFolderName = "installrun_temp-"
511 + new SimpleDateFormat("yyyy_MM_dd-HH_mm_ss")
512 .format(new Date());
513 File tmpFolder = new File(Paths.getTempPath(), tmpFolderName);
514 tmpFolder.mkdir();
515
516 TreeMap<String, Vector<File>> patches = new TreeMap<String, Vector<File>>(
517 new NaturalOrderComparator());
518 for (File patchFolder : patchFolders) {
519 for (File levelFolder : patchFolder.listFiles(dirFileFilter)) {
520 String lvlName = levelFolder.getName().toLowerCase();
521 for (File f : FileUtils.listFiles(levelFolder,
522 new String[] { "oni-patch" }, true)) {
523 if (!patches.containsKey(lvlName))
524 patches.put(lvlName, new Vector<File>());
525 patches.get(lvlName).add(f);
526 }
527 }
528 }
529
530 for (String level : patches.keySet()) {
531 File levelFolder = new File(tmpFolder, level);
532 levelFolder.mkdir();
533
534 log.println("\t\tPatches for " + level);
535
536 log.println("\t\t\tSource files/folders:");
537 for (File srcFolder : oniLevelFolders.get(level)) {
538 log.println("\t\t\t\t" + srcFolder.getPath());
539 }
540
541 // Get files to be patched from vanilla.dat
542 Vector<String> exportPatterns = new Vector<String>();
543 for (File patch : patches.get(level)) {
544 String patternWildcard = patch.getName();
545 patternWildcard = patternWildcard.substring(0,
546 patternWildcard.indexOf(".oni-patch"));
547 patternWildcard = patternWildcard.replace('-', '*');
548 exportPatterns.add(patternWildcard);
549 }
550 for (File srcFolder : oniLevelFolders.get(level)) {
551 if (srcFolder.isFile()) {
552 if (srcFolder.getPath().toLowerCase().contains("vanilla")) {
553 // Extract from .dat
554 ApplicationInvocationResult res = OniSplit.export(
555 levelFolder, srcFolder, exportPatterns);
556 log.logAppOutput(res, true);
557 }
558 }
559 }
560
561 // Get files to be patched from packages
562 for (File patch : patches.get(level)) {
563 String patternWildcard = patch.getName();
564 patternWildcard = patternWildcard.substring(0,
565 patternWildcard.indexOf(".oni-patch"));
566 patternWildcard = patternWildcard.replace('-', '*');
567 Vector<String> patterns = new Vector<String>();
568 patterns.add(patternWildcard);
569 patternWildcard = patternWildcard + ".oni";
570 final Pattern patternRegex = Pattern.compile(
571 patternWildcard.replaceAll("\\*", ".\\*"),
572 Pattern.CASE_INSENSITIVE);
573
574 for (File srcFolder : oniLevelFolders.get(level)) {
575 if (srcFolder.isFile()) {
576 if (!srcFolder.getPath().toLowerCase()
577 .contains("vanilla")) {
578 // Extract from .dat
579 ApplicationInvocationResult res = OniSplit.export(
580 levelFolder, srcFolder, patterns);
581 log.logAppOutput(res, true);
582 }
583 } else {
584 // Copy from folder with overwrite
585 for (File f : FileUtils.listFiles(srcFolder,
586 new RegexFileFilter(patternRegex),
587 TrueFileFilter.TRUE)) {
588 try {
589 FileUtils.copyFileToDirectory(f, levelFolder);
590 } catch (IOException e) {
591 e.printStackTrace();
592 }
593 }
594 }
595 }
596 }
597
598 // Extract files to XML
599 File levelFolderXML = new File(levelFolder, "xml");
600 Vector<File> files = new Vector<File>();
601 files.add(new File(levelFolder, "*.oni"));
602 ApplicationInvocationResult res = OniSplit.convertOniToXML(
603 levelFolderXML, files);
604 log.logAppOutput(res, true);
605
606 // Create masterpatch file (containing calls to all individual
607 // patches)
608 File masterpatch = new File(levelFolderXML, "masterpatch.txt");
609 PrintWriter masterpatchWriter = null;
610 try {
611 masterpatchWriter = new PrintWriter(new OutputStreamWriter(
612 new FileOutputStream(masterpatch), "UTF-8"));
613 } catch (FileNotFoundException e) {
614 e.printStackTrace();
615 } catch (UnsupportedEncodingException e) {
616 e.printStackTrace();
617 }
618 for (File patch : patches.get(level)) {
619 String patternWildcard = patch.getName();
620 patternWildcard = patternWildcard.substring(0,
621 patternWildcard.indexOf(".oni-patch"));
622 patternWildcard = patternWildcard + ".xml";
623 patternWildcard = patternWildcard.replace('-', '*');
624 File xmlFilePath = new File(levelFolderXML, patternWildcard);
625 masterpatchWriter.println(String.format("\"%s\" \"%s\"",
626 patch.getPath(), xmlFilePath.getPath()));
627 }
628 masterpatchWriter.close();
629 // Apply patches through masterpatch in levelFolderXML
630 res = XMLTools.patch(masterpatch);
631 log.logAppOutput(res, true);
632
633 // Create .oni files from XML
634 files.clear();
635 files.add(new File(levelFolderXML, "*.xml"));
636 res = OniSplit.convertXMLtoOni(levelFolder, files);
637 log.logAppOutput(res, true);
638
639 if (!RuntimeOptions.isDebug()) {
640 // Remove XML folder as import will only require .oni's
641 try {
642 FileUtils.deleteDirectory(levelFolderXML);
643 } catch (IOException e) {
644 e.printStackTrace();
645 }
646 }
647
648 oniLevelFolders.get(level).add(levelFolder);
649 }
650
651 log.println("Applying XML patches took "
652 + (new Date().getTime() - startMS) + " ms");
653 }
654
655 private static void combineBinaryFiles(
656 TreeMap<String, Vector<File>> oniLevelFolders,
657 TreeSet<String> levelsUpdated, InstallProgressListener listener,
658 Logger log) {
659 long startMS = new Date().getTime();
660
661 int totalSteps = oniLevelFolders.size() + 1;
662 int stepsDone = 0;
663
664 log.println();
665 log.println("Importing levels");
666 for (String l : oniLevelFolders.keySet()) {
667 log.println("\tLevel " + l);
668 listener.installProgressUpdate(stepsDone, totalSteps,
669 AEInstaller2.globalBundle.getString("modInstaller.buildingLevelN").replaceAll("%1", l.toString()));
670
671 if ((levelsUpdated == null)
672 || levelsUpdated.contains(l.toLowerCase())) {
673 ApplicationInvocationResult res = OniSplit.packLevel(
674 oniLevelFolders.get(l), new File(Paths.getEditionGDF(),
675 sanitizeLevelName(l) + ".dat"));
676 log.logAppOutput(res, true);
677 } else {
678 log.println("\t\tLevel not affected by new mod selection");
679 log.println();
680 }
681
682 stepsDone++;
683 }
684
685 log.println("Importing levels took " + (new Date().getTime() - startMS)
686 + " ms");
687 log.println();
688 }
689
690 private static void copyVideos(Logger log) {
691 log.println();
692 if (SettingsManager.getInstance().get("copyintro", false)) {
693 File src = new File(Paths.getVanillaGDF(), "intro.bik");
694 File target = new File(Paths.getEditionGDF(), "intro.bik");
695 log.println("Copying intro");
696 if (src.exists() && !target.exists()) {
697 try {
698 FileUtils.copyFileToDirectory(src, Paths.getEditionGDF());
699 } catch (IOException e) {
700 e.printStackTrace();
701 }
702 }
703 } else {
704 log.println("NOT copying intro");
705 }
706 if (SettingsManager.getInstance().get("copyoutro", true)) {
707 File src = new File(Paths.getVanillaGDF(), "outro.bik");
708 File target = new File(Paths.getEditionGDF(), "outro.bik");
709 log.println("Copying outro");
710 if (src.exists() && !target.exists()) {
711 try {
712 FileUtils.copyFileToDirectory(src, Paths.getEditionGDF());
713 } catch (IOException e) {
714 e.printStackTrace();
715 }
716 }
717 } else {
718 log.println("NOT copying outro");
719 }
720 }
721
722 private static void copyPlainFiles(final Logger log, TreeSet<Package> mods, InstallProgressListener listener) {
723 listener.installProgressUpdate(97, 100, AEInstaller2.globalBundle.getString("modInstaller.copyPlainFiles"));
724 log.println();
725 log.println("Copying plain files from mods");
726
727 for (Package p : mods) {
728 ToolFileIterator.iteratePlatformToolFiles(p,
729 new ToolFileIteratorEntry() {
730 @Override
731 public void toolFile(File source, File target, boolean isDir) {
732 copyPlainFile(source, target, log);
733 }
734 });
735 }
736 }
737
738 private static void copyPlainFile(File src, File target, Logger log) {
739 try {
740 if (src.getAbsolutePath().toLowerCase().contains("gamedatafolder")) {
741 File targetFile = CaseInsensitiveFile.getCaseInsensitiveFile(
742 target.getParentFile(), target.getName());
743
744 // Case mismatch?
745 if (!targetFile.getName().equals(src.getName()))
746 targetFile.delete();
747
748 FileUtils.copyFile(src, target);
749 } else {
750 log.printlnFmt("Not copying \"%s\": Not within GameDataFolder", src.getPath());
751 }
752 } catch (IOException e) {
753 e.printStackTrace();
754 }
755 }
756
757
758 private static void unlockLevels(TreeSet<Integer> unlockLevels, Logger log) {
759 File dat = new File(Paths.getEditionBasePath(), "persist.dat");
760 log.println();
761 log.println("Unlocking levels: " + unlockLevels.toString());
762 if (!dat.exists()) {
763 InputStream is = AEInstaller2.class
764 .getResourceAsStream("/net/oni2/aeinstaller/resources/persist.dat");
765 try {
766 FileUtils.copyInputStreamToFile(is, dat);
767 } catch (IOException e) {
768 e.printStackTrace();
769 }
770 }
771 PersistDat save = new PersistDat(dat);
772 HashSet<Integer> currentlyUnlocked = save.getUnlockedLevels();
773 currentlyUnlocked.addAll(unlockLevels);
774 save.setUnlockedLevels(currentlyUnlocked);
775 save.close();
776 }
777
778 private static String sanitizeLevelName(String ln) {
779 int ind = ln.indexOf("_");
780 String res = ln.substring(0, ind + 1);
781 res += ln.substring(ind + 1, ind + 2).toUpperCase();
782 res += ln.substring(ind + 2);
783 return res;
784 }
785
786 }