source: java/installer2/src/net/oni2/aeinstaller/backend/oni/management/Installer.java@ 1112

Last change on this file since 1112 was 1086, checked in by alloc, 7 years ago

AEI 2.29: Refs #126: Minor log output change

File size: 25.9 KB
Line 
1package net.oni2.aeinstaller.backend.oni.management;
2
3import java.io.File;
4import java.io.FileFilter;
5import java.io.FileNotFoundException;
6import java.io.FileOutputStream;
7import java.io.FilenameFilter;
8import java.io.IOException;
9import java.io.InputStream;
10import java.io.OutputStreamWriter;
11import java.io.PrintWriter;
12import java.io.UnsupportedEncodingException;
13import java.text.SimpleDateFormat;
14import java.util.Date;
15import java.util.HashSet;
16import java.util.List;
17import java.util.TreeMap;
18import java.util.TreeSet;
19import java.util.Vector;
20import java.util.regex.Pattern;
21
22import net.oni2.SettingsManager;
23import net.oni2.aeinstaller.AEInstaller2;
24import net.oni2.aeinstaller.backend.CaseInsensitiveFile;
25import net.oni2.aeinstaller.backend.Paths;
26import net.oni2.aeinstaller.backend.RuntimeOptions;
27import net.oni2.aeinstaller.backend.oni.OniSplit;
28import net.oni2.aeinstaller.backend.oni.PersistDat;
29import net.oni2.aeinstaller.backend.oni.XMLTools;
30import net.oni2.aeinstaller.backend.oni.management.tools.ToolFileIterator;
31import net.oni2.aeinstaller.backend.oni.management.tools.ToolFileIteratorEntry;
32import net.oni2.aeinstaller.backend.oni.management.tools.ToolInstallationList;
33import net.oni2.aeinstaller.backend.packages.EBSLInstallType;
34import net.oni2.aeinstaller.backend.packages.Package;
35import net.oni2.aeinstaller.backend.packages.PackageManager;
36import net.oni2.platformtools.PlatformInformation;
37import net.oni2.platformtools.PlatformInformation.Platform;
38import net.oni2.platformtools.applicationinvoker.ApplicationInvocationResult;
39
40import org.apache.commons.io.FileUtils;
41import org.apache.commons.io.filefilter.RegexFileFilter;
42import org.apache.commons.io.filefilter.TrueFileFilter;
43import org.javabuilders.swing.SwingJavaBuilder;
44
45import com.paour.NaturalOrderComparator;
46
47/**
48 * @author Christian Illy
49 */
50public 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 clearedFolders.clear();
329 if (!m.isCorePackage() && m.getBSLInstallType() == EBSLInstallType.NORMAL) {
330 handleModBsl (m, log, clearedFolders);
331 }
332 }
333
334 // Lastly overwrite / add files coming from non-core addons
335 log.println("\tNon-core, addon");
336 for (Package m : mods) {
337 if (!m.isCorePackage() && m.getBSLInstallType() == EBSLInstallType.ADDON) {
338 handleModBsl (m, log, null);
339 }
340 }
341
342
343
344 }
345
346 private static void handleModBsl(Package sourceMod, Logger log, HashSet<String> clearedFolders) throws IOException {
347 File bslFolder = CaseInsensitiveFile.getCaseInsensitiveFile(
348 sourceMod.getLocalPath(), "bsl");
349 if (bslFolder.exists()) {
350 if (sourceMod.hasSeparatePlatformDirs()) {
351 File bslCommonFolder = CaseInsensitiveFile
352 .getCaseInsensitiveFile(bslFolder, "common");
353 File bslMacFolder = CaseInsensitiveFile.getCaseInsensitiveFile(
354 bslFolder, "mac_only");
355 File bslWinFolder = CaseInsensitiveFile.getCaseInsensitiveFile(
356 bslFolder, "win_only");
357
358 if (bslCommonFolder.exists()) {
359 copyBsl(sourceMod, log, bslCommonFolder, sourceMod.getBSLInstallType() == EBSLInstallType.ADDON, clearedFolders);
360 }
361
362 if (bslWinFolder.exists() && (PlatformInformation.getPlatform() == Platform.WIN || PlatformInformation
363 .getPlatform() == Platform.LINUX)) {
364 copyBsl(sourceMod, log, bslWinFolder, sourceMod.getBSLInstallType() == EBSLInstallType.ADDON, clearedFolders);
365 }
366
367 if (bslMacFolder.exists() && PlatformInformation.getPlatform() == Platform.MACOS) {
368 copyBsl(sourceMod, log, bslMacFolder, sourceMod.getBSLInstallType() == EBSLInstallType.ADDON, clearedFolders);
369 }
370 } else {
371 copyBsl(sourceMod, log, bslFolder, sourceMod.getBSLInstallType() == EBSLInstallType.ADDON, clearedFolders);
372 }
373 }
374
375 }
376
377 private static void copyBsl(Package sourceMod, Logger log, File sourceModFolder, boolean overwriteFiles, HashSet<String> clearedFolders) throws IOException {
378 File targetBaseFolder = new File(Paths.getEditionGDF(), "IGMD");
379 if (!targetBaseFolder.exists())
380 targetBaseFolder.mkdir();
381
382 log.println("\t\tMod \"" + sourceMod.getName() + "\" (from " + sourceModFolder.getName() + ")");
383 for (File sourceLevelFolder : sourceModFolder.listFiles(dirFileFilter)) {
384 log.println("\t\t\t" + sourceLevelFolder.getName());
385
386 File targetLevelFolder = new File(targetBaseFolder, sourceLevelFolder.getName());
387
388 if ((CaseInsensitiveFile.getCaseInsensitiveFile(targetLevelFolder,
389 "ignore.txt").exists())) {
390 // Ignore feature: Don't apply any changes to the target level folder if it contains an "ignore.txt" file
391 log.println("\t\t\t\tSkipping level, target contains an \"ignore.txt\" file");
392 continue;
393 }
394
395 if (clearedFolders != null && targetLevelFolder.exists() && !clearedFolders.contains(targetLevelFolder.getName())) {
396 // We are in a clear-folders step and this target folder hasn't been cleared so far -> clear (aka delete) the target folder
397 log.println("\t\t\t\tClearing target, only the highest numbered mod that applies changes to a level will be used");
398 FileUtils.deleteDirectory(targetLevelFolder);
399 }
400
401 if (!targetLevelFolder.exists()) {
402 targetLevelFolder.mkdir();
403 if (clearedFolders != null) {
404 // Clear-folders step and the target folder did not exist (or was removed for clearing) -> this folder counts as cleared
405 clearedFolders.add(targetLevelFolder.getName());
406 }
407 }
408
409 for (File sourceBslFile : sourceLevelFolder.listFiles()) {
410 if (sourceBslFile.getName().toLowerCase().endsWith(".bsl")) {
411 File targetFile = new File(targetLevelFolder, sourceBslFile.getName());
412 if (overwriteFiles || !targetFile.exists()) {
413 // 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):
414 if (targetFile.exists()) {
415 log.println("\t\t\t\tOverwriting file from addon: \"" + sourceBslFile.getName() + "\"");
416 }
417 FileUtils.copyFile(sourceBslFile, targetFile);
418 } else {
419 // Non-addon mod, target already exists, skip file
420 log.println("\t\t\t\tSkipping file \"" + sourceBslFile.getName() + "\", target already exists");
421 }
422 }
423 }
424
425 }
426
427 }
428
429 /*
430 private static void copyBSL(Package sourceMod, boolean addon, Logger log) {
431 File targetBaseFolder = new File(Paths.getEditionGDF(), "IGMD");
432 if (!targetBaseFolder.exists())
433 targetBaseFolder.mkdir();
434
435 Vector<File> sources = new Vector<File>();
436 File bsl = CaseInsensitiveFile.getCaseInsensitiveFile(
437 sourceMod.getLocalPath(), "bsl");
438 if (sourceMod.hasSeparatePlatformDirs()) {
439 File bslCommon = CaseInsensitiveFile.getCaseInsensitiveFile(bsl,
440 "common");
441 File bslMac = CaseInsensitiveFile.getCaseInsensitiveFile(bsl,
442 "mac_only");
443 File bslWin = CaseInsensitiveFile.getCaseInsensitiveFile(bsl,
444 "win_only");
445 if (PlatformInformation.getPlatform() == Platform.MACOS
446 && bslMac.exists()) {
447 for (File f : bslMac.listFiles(dirFileFilter)) {
448 File targetBSL = new File(targetBaseFolder, f.getName());
449 if (addon || !targetBSL.exists())
450 sources.add(f);
451 }
452 }
453 if ((PlatformInformation.getPlatform() == Platform.WIN || PlatformInformation
454 .getPlatform() == Platform.LINUX) && bslWin.exists()) {
455 for (File f : bslWin.listFiles(dirFileFilter)) {
456 File targetBSL = new File(targetBaseFolder, f.getName());
457 if (addon || !targetBSL.exists())
458 sources.add(f);
459 }
460 }
461 if (bslCommon.exists()) {
462 for (File f : bslCommon.listFiles(dirFileFilter)) {
463 File targetBSL = new File(targetBaseFolder, f.getName());
464 if (addon || !targetBSL.exists())
465 sources.add(f);
466 }
467 }
468 } else {
469 for (File f : bsl.listFiles(dirFileFilter)) {
470 File targetBSL = new File(targetBaseFolder, f.getName());
471 if (addon || !targetBSL.exists())
472 sources.add(f);
473 }
474 }
475
476 log.println("\tMod \"" + sourceMod.getName() + "\"");
477 for (File f : sources) {
478 log.println("\t\t" + f.getName());
479 File targetPath = new File(targetBaseFolder, f.getName());
480 if (!targetPath.exists())
481 targetPath.mkdir();
482 if (!(CaseInsensitiveFile.getCaseInsensitiveFile(targetPath,
483 "ignore.txt").exists())) {
484 for (File fbsl : f.listFiles()) {
485 if (fbsl.getName().toLowerCase().endsWith(".bsl")) {
486 File targetFile = new File(targetPath, fbsl.getName());
487 if (addon || !targetFile.exists()) {
488 try {
489 FileUtils.copyFile(fbsl, targetFile);
490 } catch (IOException e) {
491 e.printStackTrace();
492 }
493 }
494 }
495 }
496 }
497 }
498 }
499 */
500
501 private static void applyPatches(
502 TreeMap<String, Vector<File>> oniLevelFolders,
503 List<File> patchFolders, InstallProgressListener listener,
504 Logger log) {
505 log.println();
506 log.println("Applying XML patches");
507 listener.installProgressUpdate(0, 1, AEInstaller2.globalBundle.getString("modInstaller.applyXmlPatches"));
508
509 long startMS = new Date().getTime();
510
511 String tmpFolderName = "installrun_temp-"
512 + new SimpleDateFormat("yyyy_MM_dd-HH_mm_ss")
513 .format(new Date());
514 File tmpFolder = new File(Paths.getTempPath(), tmpFolderName);
515 tmpFolder.mkdir();
516
517 TreeMap<String, Vector<File>> patches = new TreeMap<String, Vector<File>>(
518 new NaturalOrderComparator());
519 for (File patchFolder : patchFolders) {
520 for (File levelFolder : patchFolder.listFiles(dirFileFilter)) {
521 String lvlName = levelFolder.getName().toLowerCase();
522 for (File f : FileUtils.listFiles(levelFolder,
523 new String[] { "oni-patch" }, true)) {
524 if (!patches.containsKey(lvlName))
525 patches.put(lvlName, new Vector<File>());
526 patches.get(lvlName).add(f);
527 }
528 }
529 }
530
531 for (String level : patches.keySet()) {
532 File levelFolder = new File(tmpFolder, level);
533 levelFolder.mkdir();
534
535 log.println("\t\tPatches for " + level);
536
537 log.println("\t\t\tSource files/folders:");
538 for (File srcFolder : oniLevelFolders.get(level)) {
539 log.println("\t\t\t\t" + srcFolder.getPath());
540 }
541
542 // Get files to be patched from vanilla.dat
543 Vector<String> exportPatterns = new Vector<String>();
544 for (File patch : patches.get(level)) {
545 String patternWildcard = patch.getName();
546 patternWildcard = patternWildcard.substring(0,
547 patternWildcard.indexOf(".oni-patch"));
548 patternWildcard = patternWildcard.replace('-', '*');
549 exportPatterns.add(patternWildcard);
550 }
551 for (File srcFolder : oniLevelFolders.get(level)) {
552 if (srcFolder.isFile()) {
553 if (srcFolder.getPath().toLowerCase().contains("vanilla")) {
554 // Extract from .dat
555 ApplicationInvocationResult res = OniSplit.export(
556 levelFolder, srcFolder, exportPatterns);
557 log.logAppOutput(res, true);
558 }
559 }
560 }
561
562 // Get files to be patched from packages
563 for (File patch : patches.get(level)) {
564 String patternWildcard = patch.getName();
565 patternWildcard = patternWildcard.substring(0,
566 patternWildcard.indexOf(".oni-patch"));
567 patternWildcard = patternWildcard.replace('-', '*');
568 Vector<String> patterns = new Vector<String>();
569 patterns.add(patternWildcard);
570 patternWildcard = patternWildcard + ".oni";
571 final Pattern patternRegex = Pattern.compile(
572 patternWildcard.replaceAll("\\*", ".\\*"),
573 Pattern.CASE_INSENSITIVE);
574
575 for (File srcFolder : oniLevelFolders.get(level)) {
576 if (srcFolder.isFile()) {
577 if (!srcFolder.getPath().toLowerCase()
578 .contains("vanilla")) {
579 // Extract from .dat
580 ApplicationInvocationResult res = OniSplit.export(
581 levelFolder, srcFolder, patterns);
582 log.logAppOutput(res, true);
583 }
584 } else {
585 // Copy from folder with overwrite
586 for (File f : FileUtils.listFiles(srcFolder,
587 new RegexFileFilter(patternRegex),
588 TrueFileFilter.TRUE)) {
589 try {
590 FileUtils.copyFileToDirectory(f, levelFolder);
591 } catch (IOException e) {
592 e.printStackTrace();
593 }
594 }
595 }
596 }
597 }
598
599 // Extract files to XML
600 File levelFolderXML = new File(levelFolder, "xml");
601 Vector<File> files = new Vector<File>();
602 files.add(new File(levelFolder, "*.oni"));
603 ApplicationInvocationResult res = OniSplit.convertOniToXML(
604 levelFolderXML, files);
605 log.logAppOutput(res, true);
606
607 // Create masterpatch file (containing calls to all individual
608 // patches)
609 File masterpatch = new File(levelFolderXML, "masterpatch.txt");
610 PrintWriter masterpatchWriter = null;
611 try {
612 masterpatchWriter = new PrintWriter(new OutputStreamWriter(
613 new FileOutputStream(masterpatch), "UTF-8"));
614 } catch (FileNotFoundException e) {
615 e.printStackTrace();
616 } catch (UnsupportedEncodingException e) {
617 e.printStackTrace();
618 }
619 for (File patch : patches.get(level)) {
620 String patternWildcard = patch.getName();
621 patternWildcard = patternWildcard.substring(0,
622 patternWildcard.indexOf(".oni-patch"));
623 patternWildcard = patternWildcard + ".xml";
624 patternWildcard = patternWildcard.replace('-', '*');
625 File xmlFilePath = new File(levelFolderXML, patternWildcard);
626 masterpatchWriter.println(String.format("\"%s\" \"%s\"",
627 patch.getPath(), xmlFilePath.getPath()));
628 }
629 masterpatchWriter.close();
630 // Apply patches through masterpatch in levelFolderXML
631 res = XMLTools.patch(masterpatch);
632 log.logAppOutput(res, true);
633
634 // Create .oni files from XML
635 files.clear();
636 files.add(new File(levelFolderXML, "*.xml"));
637 res = OniSplit.convertXMLtoOni(levelFolder, files);
638 log.logAppOutput(res, true);
639
640 if (!RuntimeOptions.isDebug()) {
641 // Remove XML folder as import will only require .oni's
642 try {
643 FileUtils.deleteDirectory(levelFolderXML);
644 } catch (IOException e) {
645 e.printStackTrace();
646 }
647 }
648
649 oniLevelFolders.get(level).add(levelFolder);
650 }
651
652 log.println("Applying XML patches took "
653 + (new Date().getTime() - startMS) + " ms");
654 }
655
656 private static void combineBinaryFiles(
657 TreeMap<String, Vector<File>> oniLevelFolders,
658 TreeSet<String> levelsUpdated, InstallProgressListener listener,
659 Logger log) {
660 long startMS = new Date().getTime();
661
662 int totalSteps = oniLevelFolders.size() + 1;
663 int stepsDone = 0;
664
665 log.println();
666 log.println("Importing levels");
667 for (String l : oniLevelFolders.keySet()) {
668 log.println("\tLevel " + l);
669 listener.installProgressUpdate(stepsDone, totalSteps,
670 AEInstaller2.globalBundle.getString("modInstaller.buildingLevelN").replaceAll("%1", l.toString()));
671
672 if ((levelsUpdated == null)
673 || levelsUpdated.contains(l.toLowerCase())) {
674 ApplicationInvocationResult res = OniSplit.packLevel(
675 oniLevelFolders.get(l), new File(Paths.getEditionGDF(),
676 sanitizeLevelName(l) + ".dat"));
677 log.logAppOutput(res, true);
678 } else {
679 log.println("\t\tLevel not affected by new mod selection");
680 log.println();
681 }
682
683 stepsDone++;
684 }
685
686 log.println("Importing levels took " + (new Date().getTime() - startMS)
687 + " ms");
688 log.println();
689 }
690
691 private static void copyVideos(Logger log) {
692 log.println();
693 if (SettingsManager.getInstance().get("copyintro", false)) {
694 File src = new File(Paths.getVanillaGDF(), "intro.bik");
695 File target = new File(Paths.getEditionGDF(), "intro.bik");
696 log.println("Copying intro");
697 if (src.exists() && !target.exists()) {
698 try {
699 FileUtils.copyFileToDirectory(src, Paths.getEditionGDF());
700 } catch (IOException e) {
701 e.printStackTrace();
702 }
703 }
704 } else {
705 log.println("NOT copying intro");
706 }
707 if (SettingsManager.getInstance().get("copyoutro", true)) {
708 File src = new File(Paths.getVanillaGDF(), "outro.bik");
709 File target = new File(Paths.getEditionGDF(), "outro.bik");
710 log.println("Copying outro");
711 if (src.exists() && !target.exists()) {
712 try {
713 FileUtils.copyFileToDirectory(src, Paths.getEditionGDF());
714 } catch (IOException e) {
715 e.printStackTrace();
716 }
717 }
718 } else {
719 log.println("NOT copying outro");
720 }
721 }
722
723 private static void copyPlainFiles(final Logger log, TreeSet<Package> mods, InstallProgressListener listener) {
724 listener.installProgressUpdate(97, 100, AEInstaller2.globalBundle.getString("modInstaller.copyPlainFiles"));
725 log.println();
726 log.println("Copying plain files from mods");
727
728 for (Package p : mods) {
729 ToolFileIterator.iteratePlatformToolFiles(p,
730 new ToolFileIteratorEntry() {
731 @Override
732 public void toolFile(File source, File target, boolean isDir) {
733 copyPlainFile(source, target, log);
734 }
735 });
736 }
737 }
738
739 private static void copyPlainFile(File src, File target, Logger log) {
740 try {
741 if (src.getAbsolutePath().toLowerCase().contains("gamedatafolder")) {
742 File targetFile = CaseInsensitiveFile.getCaseInsensitiveFile(
743 target.getParentFile(), target.getName());
744
745 // Case mismatch?
746 if (!targetFile.getName().equals(src.getName()))
747 targetFile.delete();
748
749 FileUtils.copyFile(src, target);
750 } else {
751 log.printlnFmt("Not copying \"%s\": Not within GameDataFolder", src.getPath());
752 }
753 } catch (IOException e) {
754 e.printStackTrace();
755 }
756 }
757
758
759 private static void unlockLevels(TreeSet<Integer> unlockLevels, Logger log) {
760 File dat = new File(Paths.getEditionBasePath(), "persist.dat");
761 log.println();
762 log.println("Unlocking levels: " + unlockLevels.toString());
763 if (!dat.exists()) {
764 InputStream is = AEInstaller2.class
765 .getResourceAsStream("/net/oni2/aeinstaller/resources/persist.dat");
766 try {
767 FileUtils.copyInputStreamToFile(is, dat);
768 } catch (IOException e) {
769 e.printStackTrace();
770 }
771 }
772 PersistDat save = new PersistDat(dat);
773 HashSet<Integer> currentlyUnlocked = save.getUnlockedLevels();
774 currentlyUnlocked.addAll(unlockLevels);
775 save.setUnlockedLevels(currentlyUnlocked);
776 save.close();
777 }
778
779 private static String sanitizeLevelName(String ln) {
780 int ind = ln.indexOf("_");
781 String res = ln.substring(0, ind + 1);
782 res += ln.substring(ind + 1, ind + 2).toUpperCase();
783 res += ln.substring(ind + 2);
784 return res;
785 }
786
787}
Note: See TracBrowser for help on using the repository browser.