Index: java/installer2/src/net/oni2/aeinstaller/AEInstaller.properties
===================================================================
--- java/installer2/src/net/oni2/aeinstaller/AEInstaller.properties	(revision 1081)
+++ java/installer2/src/net/oni2/aeinstaller/AEInstaller.properties	(revision 1082)
@@ -1,2 +1,2 @@
 appname=AE Installer 2
-appversion=.27
+appversion=.28
Index: java/installer2/src/net/oni2/aeinstaller/backend/oni/management/Installer.java
===================================================================
--- java/installer2/src/net/oni2/aeinstaller/backend/oni/management/Installer.java	(revision 1081)
+++ java/installer2/src/net/oni2/aeinstaller/backend/oni/management/Installer.java	(revision 1082)
@@ -13,5 +13,4 @@
 import java.text.SimpleDateFormat;
 import java.util.Date;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -268,5 +267,11 @@
 
 		combineBinaryFiles(levels, levelsAffectedBoth, listener, log);
-		combineBSLFolders(mods, listener, log);
+		
+		try {
+			combineBSLFolders(mods, listener, log);
+		} catch (IOException e) {
+			log.println("Failed installing BSL files, see aei-output.log for stacktrace");
+			e.printStackTrace();
+		}
 
 		copyPlainFiles (log, mods, listener);
@@ -296,46 +301,130 @@
 
 	private static void combineBSLFolders(TreeSet<Package> mods,
-			InstallProgressListener listener, Logger log) {
+			InstallProgressListener listener, Logger log) throws IOException {
 		listener.installProgressUpdate(95, 100, AEInstaller2.globalBundle.getString("modInstaller.installBsl"));
 		log.println();
 		log.println("Installing BSL files");
-
-		HashMap<EBSLInstallType, Vector<Package>> modsToInclude = new HashMap<EBSLInstallType, Vector<Package>>();
-		modsToInclude.put(EBSLInstallType.NORMAL, new Vector<Package>());
-		modsToInclude.put(EBSLInstallType.ADDON, new Vector<Package>());
-
-		for (Package m : mods.descendingSet()) {
-			File bsl = CaseInsensitiveFile.getCaseInsensitiveFile(
-					m.getLocalPath(), "bsl");
-			if (bsl.exists()) {
-				if (m.hasSeparatePlatformDirs()) {
-					File bslCommon = CaseInsensitiveFile
-							.getCaseInsensitiveFile(bsl, "common");
-					File bslMac = CaseInsensitiveFile.getCaseInsensitiveFile(
-							bsl, "mac_only");
-					File bslWin = CaseInsensitiveFile.getCaseInsensitiveFile(
-							bsl, "win_only");
-					if ((PlatformInformation.getPlatform() == Platform.MACOS && bslMac
-							.exists())
-							|| ((PlatformInformation.getPlatform() == Platform.WIN || PlatformInformation
-									.getPlatform() == Platform.LINUX) && bslWin
-									.exists()) || bslCommon.exists()) {
-						modsToInclude.get(m.getBSLInstallType()).add(m);
+		
+		// First install core non-addon mods
+		log.println("\tCore, non-addon");
+		for (Package m : mods) {
+			if (m.isCorePackage() && m.getBSLInstallType() == EBSLInstallType.NORMAL) {
+				handleModBsl (m, log, null);
+			}
+		}
+		
+		// Now overwrite / add files coming from core addons
+		log.println("\tCore, addon");
+		for (Package m : mods) {
+			if (m.isCorePackage() && m.getBSLInstallType() == EBSLInstallType.ADDON) {
+				handleModBsl (m, log, null);
+			}
+		}
+		
+		// Install non-core non-addon mods (levels affected here are first cleaned up)
+		log.println("\tNon-core, non-addon");
+		HashSet<String> clearedFolders = new HashSet<String>();
+		for (Package m : mods) {
+			if (!m.isCorePackage() && m.getBSLInstallType() == EBSLInstallType.NORMAL) {
+				handleModBsl (m, log, clearedFolders);
+			}
+		}
+		
+		// Lastly overwrite / add files coming from non-core addons
+		log.println("\tNon-core, addon");
+		for (Package m : mods) {
+			if (!m.isCorePackage() && m.getBSLInstallType() == EBSLInstallType.ADDON) {
+				handleModBsl (m, log, null);
+			}
+		}
+		
+		
+
+	}
+	
+	private static void handleModBsl(Package sourceMod, Logger log, HashSet<String> clearedFolders) throws IOException {
+		File bslFolder = CaseInsensitiveFile.getCaseInsensitiveFile(
+				sourceMod.getLocalPath(), "bsl");
+		if (bslFolder.exists()) {
+			if (sourceMod.hasSeparatePlatformDirs()) {
+				File bslCommonFolder = CaseInsensitiveFile
+						.getCaseInsensitiveFile(bslFolder, "common");
+				File bslMacFolder = CaseInsensitiveFile.getCaseInsensitiveFile(
+						bslFolder, "mac_only");
+				File bslWinFolder = CaseInsensitiveFile.getCaseInsensitiveFile(
+						bslFolder, "win_only");
+				
+				if (bslCommonFolder.exists()) {
+					copyBsl(sourceMod, log, bslCommonFolder, sourceMod.getBSLInstallType() == EBSLInstallType.ADDON, clearedFolders);
+				}
+				
+				if (bslWinFolder.exists() && (PlatformInformation.getPlatform() == Platform.WIN || PlatformInformation
+						.getPlatform() == Platform.LINUX)) {
+					copyBsl(sourceMod, log, bslCommonFolder, sourceMod.getBSLInstallType() == EBSLInstallType.ADDON, clearedFolders);
+				}
+				
+				if (bslMacFolder.exists() && PlatformInformation.getPlatform() == Platform.MACOS) {
+					copyBsl(sourceMod, log, bslCommonFolder, sourceMod.getBSLInstallType() == EBSLInstallType.ADDON, clearedFolders);
+				}
+			} else {
+				copyBsl(sourceMod, log, bslFolder, sourceMod.getBSLInstallType() == EBSLInstallType.ADDON, clearedFolders);
+			}
+		}
+		
+	}
+	
+	private static void copyBsl(Package sourceMod, Logger log, File sourceModFolder, boolean overwriteFiles, HashSet<String> clearedFolders) throws IOException {
+		File targetBaseFolder = new File(Paths.getEditionGDF(), "IGMD");
+		if (!targetBaseFolder.exists())
+			targetBaseFolder.mkdir();
+
+		log.println("\t\tMod \"" + sourceMod.getName() + "\"");
+		for (File sourceLevelFolder : sourceModFolder.listFiles(dirFileFilter)) {
+			log.println("\t\t\t" + sourceLevelFolder.getName() + " (from " + sourceModFolder.getName() + ")");
+
+			File targetLevelFolder = new File(targetBaseFolder, sourceLevelFolder.getName());
+			
+			if (!(CaseInsensitiveFile.getCaseInsensitiveFile(targetLevelFolder,
+					"ignore.txt").exists())) {
+				// Ignore feature: Don't apply any changes to the target level folder if it contains an "ignore.txt" file
+				log.println("\t\t\t\tSkipping level, target contains an \"ignore.txt\" file");
+				continue;
+			}
+
+			if (clearedFolders != null && targetLevelFolder.exists() && !clearedFolders.contains(targetLevelFolder.getName())) {
+				// We are in a clear-folders step and this target folder hasn't been cleared so far -> clear (aka delete) the target folder
+				log.println("\t\t\t\tClearing target, first non-core mod that applies changes to this level");
+				FileUtils.deleteDirectory(targetLevelFolder);
+			}
+			
+			if (!targetLevelFolder.exists()) {
+				targetLevelFolder.mkdir();
+				if (clearedFolders != null) {
+					// Clear-folders step and the target folder did not exist (or was removed for clearing) -> this folder counts as cleared
+					clearedFolders.add(targetLevelFolder.getName());
+				}
+			}
+			
+			for (File sourceBslFile : sourceLevelFolder.listFiles()) {
+				if (sourceBslFile.getName().toLowerCase().endsWith(".bsl")) {
+					File targetFile = new File(targetLevelFolder, sourceBslFile.getName());
+					if (overwriteFiles || !targetFile.exists()) {
+						// 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):
+						if (targetFile.exists()) {
+							log.println("\t\t\t\tOverwriting file from addon: \"" + sourceBslFile.getName() + "\"");
+						}
+						FileUtils.copyFile(sourceBslFile, targetFile);
+					} else {
+						// Non-addon mod, target already exists, skip file
+						log.println("\t\t\t\tSkipping file \"" + sourceBslFile.getName() + "\", target already exists");
 					}
-				} else {
-					modsToInclude.get(m.getBSLInstallType()).add(m);
-				}
-			}
-		}
-
-		for (Package m : modsToInclude.get(EBSLInstallType.NORMAL)) {
-			copyBSL(m, false, log);
-		}
-		Vector<Package> addons = modsToInclude.get(EBSLInstallType.ADDON);
-		for (int i = addons.size() - 1; i >= 0; i--) {
-			copyBSL(addons.get(i), true, log);
-		}
-	}
-
+				}
+			}
+
+		}
+
+	}
+
+	/*
 	private static void copyBSL(Package sourceMod, boolean addon, Logger log) {
 		File targetBaseFolder = new File(Paths.getEditionGDF(), "IGMD");
@@ -407,4 +496,5 @@
 		}
 	}
+	*/
 
 	private static void applyPatches(
