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

Last change on this file since 1018 was 1016, checked in by alloc, 10 years ago

Should support plain files in normal mod packages, but only copies those within GDF. (Refs #89)

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