public MetaCMM(string metaFile) { var lines = File.ReadAllLines(metaFile); int i = 0; foreach (var line in lines) { switch (i) { case 0: ModName = line; break; case 1: Version = line; break; case 2: InstalledBy = line; break; case 3: InstallerInstanceGUID = line; break; default: // MetaCMM Extended if (line.StartsWith(PrefixOptionsSelectedOnInstall)) { var parsedline = line.Substring(PrefixOptionsSelectedOnInstall.Length); OptionsSelectedAtInstallTime.ReplaceAll(StringStructParser.GetSemicolonSplitList(parsedline)); } else if (line.StartsWith(PrefixIncompatibleDLC)) { var parsedline = line.Substring(PrefixIncompatibleDLC.Length); IncompatibleDLC.ReplaceAll(StringStructParser.GetSemicolonSplitList(parsedline)); } break; } i++; } }
public MetaCMM(string metaFile) { var lines = Utilities.WriteSafeReadAllLines(metaFile).ToList(); int i = 0; foreach (var line in lines) { switch (i) { case 0: ModName = line; break; case 1: Version = line; break; case 2: InstalledBy = line; break; case 3: InstallerInstanceGUID = line; break; default: if (line.StartsWith(ControllerCompatMetaPrefix)) { var parsedline = line.Substring(ControllerCompatMetaPrefix.Length); ME3ControllerModCompatBuiltAgainst.ReplaceAll(StringStructParser.GetSemicolonSplitList(parsedline)); } break; } i++; } }
public AlternateDLC(string alternateDLCText, mod.Mod modForValidating, ModJob job) { var properties = StringStructParser.GetCommaSplitValues(alternateDLCText); //todo: if statements to check these. if (properties.TryGetValue(@"FriendlyName", out string friendlyName)) { FriendlyName = friendlyName; } if (modForValidating.ModDescTargetVersion >= 6 && string.IsNullOrWhiteSpace(FriendlyName)) { //Cannot be null. Log.Error(@"Alternate DLC does not specify FriendlyName. Mods targeting moddesc >= 6.0 require FriendlyName"); ValidAlternate = false; LoadFailedReason = M3L.GetString(M3L.string_validation_altdlc_oneAltDlcMissingFriendlyNameCmm6); return; } if (!Enum.TryParse(properties[@"Condition"], out Condition)) { Log.Error($@"Alternate DLC specifies unknown/unsupported condition: {properties[@"Condition"]}"); //do not localize ValidAlternate = false; var condition = properties[@"Condition"]; LoadFailedReason = $@"{M3L.GetString(M3L.string_validation_altdlc_unknownCondition)} {condition}"; return; } if (!Enum.TryParse(properties[@"ModOperation"], out Operation)) { Log.Error($@"Alternate DLC specifies unknown/unsupported operation: {properties[@"ModOperation"]}"); //do not localize ValidAlternate = false; var operation = properties[@"ModOperation"]; LoadFailedReason = $@"{M3L.GetString(M3L.string_validation_altdlc_unknownOperation)} {operation}"; return; } if (properties.TryGetValue(@"Description", out string description)) { Description = description; } if (modForValidating.ModDescTargetVersion >= 6 && string.IsNullOrWhiteSpace(Description)) { //Cannot be null. Log.Error($@"Alternate DLC {FriendlyName} cannot have empty Description or missing Description descriptor as it targets cmmver >= 6"); ValidAlternate = false; LoadFailedReason = M3L.GetString(M3L.string_interp_validation_altdlc_cmmver6RequiresDescription, FriendlyName); return; } //OP_NOTHING can have conditions if (properties.TryGetValue(@"ConditionalDLC", out string conditionalDlc)) { var conditionalList = StringStructParser.GetSemicolonSplitList(conditionalDlc); foreach (var dlc in conditionalList) { if (Condition == AltDLCCondition.COND_MANUAL) { if (modForValidating.ModDescTargetVersion >= 6.3) { // On 6.3 trigger failure on this mod to help ensure users design mod properly Log.Error($@"{modForValidating.ModName} has Alternate DLC {friendlyName} that has a value for ConditionalDLC on Condition COND_MANUAL. COND_MANUAL does not use ConditionalDLC, use DLCRequirements instead."); ValidAlternate = false; LoadFailedReason = M3L.GetString(M3L.string_interp_validation_altdlc_condManualWithConditionalDLC, friendlyName); return; } else { Log.Warning($@"{modForValidating.ModName} has AlternateDLC {friendlyName} that has a value for ConditionalDLC on Condition COND_MANUAL. COND_MANUAL does not use ConditionalDLC, use DLCRequirements instead. On mods targetting moddesc 6.3 and above, this will trigger a load failure for a mod."); } break; } else if (Condition == AltDLCCondition.COND_SPECIFIC_DLC_SETUP) { //check +/- if (!dlc.StartsWith(@"-") && !dlc.StartsWith(@"+")) { Log.Error($@"An item in Alternate DLC's ({FriendlyName}) ConditionalDLC doesn't start with + or -. When using the condition {Condition}, you must precede DLC names with + or -. Bad value: {dlc}"); LoadFailedReason = M3L.GetString(M3L.string_interp_validation_altdlc_specificDlcSetupMissingPlusMinus, FriendlyName, Condition, dlc); return; } var prefix = dlc.Substring(0, 1); var realname = dlc.Substring(1); //official headers if (Enum.TryParse(realname, out ModJob.JobHeader header) && ModJob.GetHeadersToDLCNamesMap(modForValidating.Game).TryGetValue(header, out var foldername)) { ConditionalDLC.Add(prefix + foldername); continue; } //dlc mods if (!realname.StartsWith(@"DLC_")) { Log.Error($@"An item in Alternate DLC's ({FriendlyName}) ConditionalDLC doesn't start with DLC_ or is not official header (after the +/- required by {Condition}). Bad value: {dlc}"); LoadFailedReason = M3L.GetString(M3L.string_interp_validation_altdlc_specificDlcSetupInvalidDlcName, FriendlyName, Condition, dlc); return; } else { ConditionalDLC.Add(prefix + realname); } } else { if (Enum.TryParse(dlc, out ModJob.JobHeader header) && ModJob.GetHeadersToDLCNamesMap(modForValidating.Game).TryGetValue(header, out var foldername)) { ConditionalDLC.Add(foldername); continue; } if (!dlc.StartsWith(@"DLC_")) { Log.Error($@"An item in Alternate DLC's ({FriendlyName}) ConditionalDLC doesn't start with DLC_ or is not official header"); LoadFailedReason = M3L.GetString(M3L.string_interp_validation_altdlc_conditionalDLCInvalidValue, FriendlyName); return; } else { ConditionalDLC.Add(dlc); } } } } if (Operation != AltDLCOperation.OP_NOTHING) { int multilistid = -1; if (Operation == AltDLCOperation.OP_ADD_MULTILISTFILES_TO_CUSTOMDLC) { if (properties.TryGetValue(@"MultiListRootPath", out var rootpath)) { MultiListRootPath = rootpath.TrimStart('\\', '/').Replace('/', '\\'); } else { Log.Error($@"Alternate DLC ({FriendlyName}) specifies operation OP_ADD_MULTILISTFILES_TO_CUSTOMDLC but does not specify the required item MultiListRootPath."); ValidAlternate = false; LoadFailedReason = M3L.GetString(M3L.string_interp_altdlc_multilistMissingMultiListRootPath, FriendlyName); return; } if (properties.TryGetValue(@"MultiListId", out string multilistidstr) && int.TryParse(multilistidstr, out multilistid)) { if (job.MultiLists.TryGetValue(multilistid, out var ml)) { MultiListId = multilistid; MultiListSourceFiles = ml.Select(x => x.TrimStart('\\', '/')).ToArray(); } else { Log.Error($@"Alternate DLC ({FriendlyName}) Multilist ID does not exist as part of the {job.Header} task: multilist" + multilistid); ValidAlternate = false; var id = @"multilist" + multilistid; LoadFailedReason = M3L.GetString(M3L.string_interp_altdlc_multilistMissingMultiListX, FriendlyName, job.Header, id); return; } } else { Log.Error($@"Alternate DLC ({FriendlyName}) specifies operation OP_ADD_MULTILISTFILES_TO_CUSTOMDLC but does not specify the MultiListId attribute, or it could not be parsed to an integer."); ValidAlternate = false; LoadFailedReason = M3L.GetString(M3L.string_interp_altdlc_multilistIdNotIntegerOrMissing, FriendlyName); return; } } else { if (properties.TryGetValue(@"ModAltDLC", out string altDLCFolder)) { AlternateDLCFolder = altDLCFolder.Replace('/', '\\'); } else { Log.Error(@"Alternate DLC does not specify ModAltDLC but is required"); ValidAlternate = false; LoadFailedReason = M3L.GetString(M3L.string_interp_validation_altdlc_missingModAltDLC, FriendlyName); return; } } if (properties.TryGetValue(@"ModDestDLC", out string destDLCFolder)) { DestinationDLCFolder = destDLCFolder.Replace('/', '\\'); } else { Log.Error(@"Alternate DLC does not specify ModDestDLC but is required"); ValidAlternate = false; LoadFailedReason = M3L.GetString(M3L.string_interp_validation_altdlc_missingModDestDLC, FriendlyName); return; } //todo: Validate target in mod folder //Validation if (string.IsNullOrWhiteSpace(AlternateDLCFolder) && MultiListRootPath == null) { Log.Error($@"Alternate DLC directory (ModAltDLC) not specified for {FriendlyName}"); LoadFailedReason = M3L.GetString(M3L.string_interp_validation_altdlc_sourceDirectoryNotSpecifiedForModAltDLC, FriendlyName); return; } if (string.IsNullOrWhiteSpace(DestinationDLCFolder)) { Log.Error($@"Destination DLC directory (ModDestDLC) not specified for {FriendlyName}"); LoadFailedReason = M3L.GetString(M3L.string_interp_validation_altdlc_destinationDirectoryNotSpecifiedForModDestDLC, FriendlyName); return; } if (AlternateDLCFolder != null) { AlternateDLCFolder = AlternateDLCFolder.TrimStart('\\', '/').Replace('/', '\\'); //Check ModAltDLC directory exists var localAltDlcDir = FilesystemInterposer.PathCombine(modForValidating.IsInArchive, modForValidating.ModPath, AlternateDLCFolder); if (!FilesystemInterposer.DirectoryExists(localAltDlcDir, modForValidating.Archive)) { Log.Error($@"Alternate DLC directory (ModAltDLC) does not exist: {AlternateDLCFolder}"); LoadFailedReason = M3L.GetString(M3L.string_interp_validation_altdlc_sourceDirectoryDoesntExist, FriendlyName, AlternateDLCFolder); return; } } else if (MultiListRootPath != null) { foreach (var multif in MultiListSourceFiles) { var path = FilesystemInterposer.PathCombine(modForValidating.IsInArchive, modForValidating.ModPath, MultiListRootPath, multif); if (!FilesystemInterposer.FileExists(path, modForValidating.Archive)) { Log.Error($@"Alternate DLC ({FriendlyName}) specifies a multilist (index {multilistid}) that contains file that does not exist: {multif}"); LoadFailedReason = M3L.GetString(M3L.string_interp_altdlc_multilistMissingFileInMultilist, FriendlyName, multilistid, multif); return; } } } // Validate multilist dlc } var dlcReqs = properties.TryGetValue(@"DLCRequirements", out string _dlcReqs) ? _dlcReqs.Split(';') : null; if (dlcReqs != null) { var reqList = new List <string>(); foreach (var originalReq in dlcReqs) { var testreq = originalReq; string prefix = ""; if (modForValidating.ModDescTargetVersion >= 6.3) { if (testreq.StartsWith("-") || testreq.StartsWith("+")) { prefix = testreq[0].ToString(); } testreq = testreq.TrimStart('-', '+'); } //official headers if (Enum.TryParse(testreq, out ModJob.JobHeader header) && ModJob.GetHeadersToDLCNamesMap(modForValidating.Game).TryGetValue(header, out var foldername)) { reqList.Add(prefix + foldername); continue; } //dlc mods if (!testreq.StartsWith(@"DLC_")) { Log.Error($@"An item in Alternate DLC's ({FriendlyName}) DLCRequirements doesn't start with DLC_ or is not official header. Bad value: {originalReq}"); LoadFailedReason = M3L.GetString(M3L.string_interp_validation_altdlc_dlcRequirementInvalid, FriendlyName, originalReq); return; } else { reqList.Add(originalReq); } } DLCRequirementsForManual = reqList.ToArray(); } if (Condition == AltDLCCondition.COND_SPECIFIC_SIZED_FILES) { var requiredFilePaths = properties.TryGetValue(@"RequiredFileRelativePaths", out string _requiredFilePaths) ? _requiredFilePaths.Split(';').ToList() : new List <string>(); var requiredFileSizes = properties.TryGetValue(@"RequiredFileSizes", out string _requiredFileSizes) ? _requiredFileSizes.Split(';').ToList() : new List <string>(); if (requiredFilePaths.Count() != requiredFileSizes.Count()) { Log.Error($@"Alternate DLC {FriendlyName} uses COND_SPECIFIC_SIZED_FILES but the amount of items in the RequiredFileRelativePaths and RequiredFileSizes lists are not equal"); ValidAlternate = false; LoadFailedReason = M3L.GetString(M3L.string_interp_validation_altdlc_specificSizedFilesMismatchedParams, FriendlyName); return; } for (int i = 0; i < requiredFilePaths.Count(); i++) { var reqFile = requiredFilePaths[i]; var reqSizeStr = requiredFileSizes[i]; if (reqFile.Contains(@"..")) { Log.Error($@"Alternate DLC {FriendlyName} RequiredFileRelativePaths item {reqFile} is invalid: Values cannot contain '..' for security reasons"); ValidAlternate = false; LoadFailedReason = M3L.GetString(M3L.string_interp_validation_altdlc_specificSizedFilesContainsIllegalPattern, FriendlyName, reqFile); return; } reqFile = reqFile.Replace('/', '\\').TrimStart('\\'); //standardize if (long.TryParse(reqSizeStr, out var reqSize) && reqSize >= 0) { RequiredSpecificFiles[reqFile] = reqSize; } else { Log.Error($@"Alternate DLC {FriendlyName} RequiredFileSizes item {reqFile} is invalid: {reqSizeStr}. Values must be greater than or equal to zero."); ValidAlternate = false; LoadFailedReason = M3L.GetString(M3L.string_interp_validation_altdlc_specificSizedFileMustBeLargerThanZero, FriendlyName, reqFile, reqSizeStr); return; } } if (!RequiredSpecificFiles.Any()) { Log.Error($@"Alternate DLC {FriendlyName} is invalid: COND_SPECIFIC_SIZED_FILES is specified as the condition but there are no values in RequiredFileRelativePaths/RequiredFileSizes"); ValidAlternate = false; LoadFailedReason = M3L.GetString(M3L.string_interp_validation_altdlc_specificSizedFilesMissingRequiredParams, FriendlyName); return; } } if (!ReadImageAssetOptions(modForValidating, properties)) { return; // Failed in super call } ReadAutoApplicableText(properties); if (modForValidating.ModDescTargetVersion >= 6.0) { GroupName = properties.TryGetValue(@"OptionGroup", out string groupName) ? groupName : null; } if (Condition == AltDLCCondition.COND_MANUAL && properties.TryGetValue(@"CheckedByDefault", out string checkedByDefault) && bool.TryParse(checkedByDefault, out bool cbd)) { CheckedByDefault = cbd; } if (Condition != AltDLCCondition.COND_MANUAL && Condition != AltDLCCondition.COND_SPECIFIC_SIZED_FILES && Condition != AltDLCCondition.INVALID_CONDITION) { //ensure conditional dlc list has at least one item. if (ConditionalDLC.Count == 0) { Log.Error($@"Alternate DLC {FriendlyName} cannot have empty or missing Conditional DLC list, as it does not use COND_MANUAL or COND_SPECIFIC_SIZED_FILES."); ValidAlternate = false; LoadFailedReason = M3L.GetString(M3L.string_interp_altdlc_emptyConditionalDLCList, FriendlyName); return; } } CLog.Information($@"AlternateDLC loaded and validated: {FriendlyName}", Settings.LogModStartup); ValidAlternate = true; }
public AlternateFile(string alternateFileText, ModJob associatedJob, Mod modForValidating) { var properties = StringStructParser.GetCommaSplitValues(alternateFileText); if (properties.TryGetValue(@"FriendlyName", out string friendlyName)) { FriendlyName = friendlyName; } if (modForValidating.ModDescTargetVersion >= 6 && string.IsNullOrWhiteSpace(FriendlyName)) { //Cannot be null. Log.Error(@"Alternate File does not specify FriendlyName. Mods targeting moddesc >= 6.0 cannot have empty FriendlyName"); ValidAlternate = false; LoadFailedReason = M3L.GetString(M3L.string_validation_altfile_oneAltDlcMissingFriendlyNameCmm6); return; } if (!Enum.TryParse(properties[@"Condition"], out Condition)) { Log.Error($@"Alternate File specifies unknown/unsupported condition: {properties[@"Condition"]}"); //do not localize ValidAlternate = false; LoadFailedReason = $@"{M3L.GetString(M3L.string_validation_altfile_unknownCondition)} {properties[@"Condition"]}"; return; } if (properties.TryGetValue(@"ConditionalDLC", out string conditionalDlc)) { var conditionalList = StringStructParser.GetSemicolonSplitList(conditionalDlc); foreach (var dlc in conditionalList) { //if (modForValidating.Game == Mod.MEGame.ME3) //{ if (Enum.TryParse(dlc, out ModJob.JobHeader header) && ModJob.GetHeadersToDLCNamesMap(modForValidating.Game).TryGetValue(header, out var foldername)) { ConditionalDLC.Add(foldername); continue; } //} if (!dlc.StartsWith(@"DLC_")) { Log.Error(@"An item in Alternate Files's ConditionalDLC doesn't start with DLC_"); LoadFailedReason = M3L.GetString(M3L.string_validation_altfile_conditionalDLCInvalidValue, FriendlyName); return; } else { ConditionalDLC.Add(dlc); } } } if (!Enum.TryParse(properties[@"ModOperation"], out Operation)) { Log.Error(@"Alternate File specifies unknown/unsupported operation: " + properties[@"ModOperation"]); ValidAlternate = false; LoadFailedReason = $@"{M3L.GetString(M3L.string_validation_altfile_unknownOperation)} { properties[@"ModOperation"]}"; return; } if (properties.TryGetValue(@"Description", out string description)) { Description = description; } if (modForValidating.ModDescTargetVersion >= 6 && string.IsNullOrWhiteSpace(Description)) { //Cannot be null. Log.Error($@"Alternate File {FriendlyName} with mod targeting moddesc >= 6.0 cannot have empty Description or missing description"); ValidAlternate = false; LoadFailedReason = M3L.GetString(M3L.string_interp_validation_altfile_cmmver6RequiresDescription, FriendlyName); return; } if (Operation != AltFileOperation.OP_NOTHING) { if (properties.TryGetValue(@"ModFile", out string modfile)) { ModFile = modfile.TrimStart('\\', '/').Replace('/', '\\'); } else { Log.Error($@"Alternate file in-mod target (ModFile) required but not specified. This value is required for all Alternate files. Friendlyname: {FriendlyName}"); ValidAlternate = false; LoadFailedReason = M3L.GetString(M3L.string_interp_validation_altfile_noModFileDeclared, FriendlyName); return; } if (associatedJob.Header == ModJob.JobHeader.CUSTOMDLC) { var modFilePath = FilesystemInterposer.PathCombine(modForValidating.IsInArchive, modForValidating.ModPath, ModFile); var pathSplit = ModFile.Split('\\'); if (pathSplit.Length > 0) { var dlcName = pathSplit[0]; var jobKey = associatedJob.CustomDLCFolderMapping.FirstOrDefault(x => x.Value.Equals(dlcName, StringComparison.InvariantCultureIgnoreCase)); if (jobKey.Key != null) { //if (associatedJob.CustomDLCFolderMapping.TryGetValue(ModFile, out var sourceFile)) //{ //} } else { Log.Error($@"Alternate file {FriendlyName} in-mod target (ModFile) does not appear to target a DLC target this mod will (always) install: {ModFile}"); ValidAlternate = false; LoadFailedReason = "Dummy placeholder"; //LoadFailedReason = M3L.GetString(M3L.string_interp_validation_altfile_couldNotFindModFile, FriendlyName, ModFile); return; } } } else { if (!associatedJob.FilesToInstall.TryGetValue(ModFile, out var sourceFile)) { Log.Error($@"Alternate file {FriendlyName} in-mod target (ModFile) specified but does not exist in job: {ModFile}"); ValidAlternate = false; LoadFailedReason = M3L.GetString(M3L.string_interp_validation_altfile_couldNotFindModFile, FriendlyName, ModFile); return; } } //todo: implement multimap if (properties.TryGetValue(@"MultiMappingFile", out string multifilemapping)) { MultiMappingFile = multifilemapping.TrimStart('\\', '/'); } if (properties.TryGetValue(@"AltFile", out string altfile)) { AltFile = altfile; } else if (AltFile == null && properties.TryGetValue(@"ModAltFile", out string maltfile)) { AltFile = maltfile; } properties.TryGetValue(@"SubstituteFile", out SubstituteFile); //Only used in 4.5. In 5.0 and above this became AltFile. //workaround for 4.5 if (modForValidating.ModDescTargetVersion == 4.5 && Operation == AltFileOperation.OP_SUBSTITUTE && SubstituteFile != null) { AltFile = SubstituteFile; } if (!string.IsNullOrEmpty(AltFile)) { AltFile = AltFile.Replace('/', '\\'); //Standardize paths } //This needs reworked from java's hack implementation //Need to identify mods using substitution features if (Operation == AltFileOperation.OP_INSTALL || Operation == AltFileOperation.OP_SUBSTITUTE) { if (MultiMappingFile == null) { //Validate file var altPath = FilesystemInterposer.PathCombine(modForValidating.IsInArchive, modForValidating.ModPath, AltFile); var altFileSourceExists = FilesystemInterposer.FileExists(altPath, modForValidating.Archive); if (!altFileSourceExists) { Log.Error(@"Alternate file source (AltFile) does not exist: " + AltFile); ValidAlternate = false; LoadFailedReason = M3L.GetString(M3L.string_interp_validation_altfile_specifiedAltFileDoesntExist, Operation.ToString(), AltFile); return; } //Ensure it is not part of DLC directory itself. var modFile = FilesystemInterposer.PathCombine(modForValidating.IsInArchive, modForValidating.ModPath, ModFile); //Todo } else { //Multimapping, Todo } } } ApplicableAutoText = properties.TryGetValue(@"ApplicableAutoText", out string applicableText) ? applicableText : M3L.GetString(M3L.string_autoApplied); NotApplicableAutoText = properties.TryGetValue(@"NotApplicableAutoText", out string notApplicableText) ? notApplicableText : M3L.GetString(M3L.string_notApplicable); if (modForValidating.ModDescTargetVersion >= 6.0) { GroupName = properties.TryGetValue(@"OptionGroup", out string groupName) ? groupName : null; } if (Condition == AltFileCondition.COND_MANUAL && properties.TryGetValue(@"CheckedByDefault", out string checkedByDefault) && bool.TryParse(checkedByDefault, out bool cbd)) { CheckedByDefault = cbd; } CLog.Information($@"Alternate file loaded and validated: {FriendlyName}", Settings.LogModStartup); ValidAlternate = true; }
public AlternateDLC(string alternateDLCText, Mod modForValidating) { var properties = StringStructParser.GetCommaSplitValues(alternateDLCText); //todo: if statements to check these. if (properties.TryGetValue(@"FriendlyName", out string friendlyName)) { FriendlyName = friendlyName; } if (modForValidating.ModDescTargetVersion >= 6 && string.IsNullOrWhiteSpace(FriendlyName)) { //Cannot be null. Log.Error(@"Alternate DLC does not specify FriendlyName. Mods targeting moddesc >= 6.0 require FriendlyName"); ValidAlternate = false; LoadFailedReason = M3L.GetString(M3L.string_validation_altdlc_oneAltDlcMissingFriendlyNameCmm6); return; } if (!Enum.TryParse(properties[@"Condition"], out Condition)) { Log.Error($@"Alternate DLC specifies unknown/unsupported condition: {properties[@"Condition"]}"); //do not localize ValidAlternate = false; LoadFailedReason = M3L.GetString(M3L.string_validation_altdlc_unknownCondition) + properties[@"Condition"]; return; } if (!Enum.TryParse(properties[@"ModOperation"], out Operation)) { Log.Error($@"Alternate DLC specifies unknown/unsupported operation: {properties[@"ModOperation"]}"); //do not localize ValidAlternate = false; LoadFailedReason = M3L.GetString(M3L.string_validation_altdlc_unknownOperation) + properties[@"ModOperation"]; return; } if (properties.TryGetValue(@"Description", out string description)) { Description = description; } if (modForValidating.ModDescTargetVersion >= 6 && string.IsNullOrWhiteSpace(Description)) { //Cannot be null. Log.Error($@"Alternate DLC {FriendlyName} cannot have empty Description or missing description as it targets cmmver >= 6"); ValidAlternate = false; LoadFailedReason = M3L.GetString(M3L.string_interp_validation_altdlc_cmmver6RequiresDescription, FriendlyName); return; } if (Operation != AltDLCOperation.OP_NOTHING) { if (properties.TryGetValue(@"ModAltDLC", out string altDLCFolder)) { AlternateDLCFolder = altDLCFolder.Replace('/', '\\'); } else { Log.Error(@"Alternate DLC does not specify ModAltDLC but is required"); ValidAlternate = false; LoadFailedReason = M3L.GetString(M3L.string_interp_validation_altdlc_missingModAltDLC, FriendlyName); return; } if (properties.TryGetValue(@"ModDestDLC", out string destDLCFolder)) { DestinationDLCFolder = destDLCFolder.Replace('/', '\\'); } else { Log.Error(@"Alternate DLC does not specify ModDestDLC but is required"); ValidAlternate = false; LoadFailedReason = M3L.GetString(M3L.string_interp_validation_altdlc_missingModDestDLC, FriendlyName); return; } //todo: Validate target in mod folder if (properties.TryGetValue(@"ConditionalDLC", out string conditionalDlc)) { var conditionalList = StringStructParser.GetSemicolonSplitList(conditionalDlc); foreach (var dlc in conditionalList) { //if (modForValidating.Game == Mod.MEGame.ME3) //{ if (Enum.TryParse(dlc, out ModJob.JobHeader header) && ModJob.GetHeadersToDLCNamesMap(modForValidating.Game).TryGetValue(header, out var foldername)) { ConditionalDLC.Add(foldername); continue; } //} if (!dlc.StartsWith(@"DLC_")) { Log.Error($@"An item in Alternate DLC's ({FriendlyName}) ConditionalDLC doesn't start with DLC_ or is not official header"); LoadFailedReason = M3L.GetString(M3L.string_interp_validation_altdlc_conditionalDLCInvalidValue, FriendlyName); return; } else { ConditionalDLC.Add(dlc); } } } //Validation if (string.IsNullOrWhiteSpace(AlternateDLCFolder)) { Log.Error($@"Alternate DLC directory (ModAltDLC) not specified for { FriendlyName}"); LoadFailedReason = M3L.GetString(M3L.string_interp_validation_altdlc_sourceDirectoryNotSpecifiedForModAltDLC, FriendlyName); return; } if (string.IsNullOrWhiteSpace(DestinationDLCFolder)) { Log.Error($@"Destination DLC directory (ModDestDLC) not specified for {FriendlyName}"); LoadFailedReason = M3L.GetString(M3L.string_interp_validation_altdlc_destinationDirectoryNotSpecifiedForModDestDLC, FriendlyName); return; } AlternateDLCFolder = AlternateDLCFolder.TrimStart('\\', '/').Replace('/', '\\'); //Check ModAltDLC directory exists var localAltDlcDir = FilesystemInterposer.PathCombine(modForValidating.IsInArchive, modForValidating.ModPath, AlternateDLCFolder); if (!FilesystemInterposer.DirectoryExists(localAltDlcDir, modForValidating.Archive)) { Log.Error($@"Alternate DLC directory (ModAltDLC) does not exist: {AlternateDLCFolder}"); LoadFailedReason = M3L.GetString(M3L.string_interp_validation_altdlc_sourceDirectoryDoesntExist, FriendlyName, AlternateDLCFolder); return; } } ApplicableAutoText = properties.TryGetValue(@"ApplicableAutoText", out string applicableText) ? applicableText : M3L.GetString(M3L.string_autoApplied); NotApplicableAutoText = properties.TryGetValue(@"NotApplicableAutoText", out string notApplicableText) ? notApplicableText : M3L.GetString(M3L.string_notApplicable); if (modForValidating.ModDescTargetVersion >= 6.0) { GroupName = properties.TryGetValue(@"OptionGroup", out string groupName) ? groupName : null; } if (Condition == AltDLCCondition.COND_MANUAL && properties.TryGetValue(@"CheckedByDefault", out string checkedByDefault) && bool.TryParse(checkedByDefault, out bool cbd)) { CheckedByDefault = cbd; } CLog.Information($@"AlternateDLC loaded and validated: {FriendlyName}", Settings.LogModStartup); ValidAlternate = true; }
public static string ConvertAlternatesToALOTManifestMod(string inputText) { var conditionalStructs = StringStructParser.GetParenthesisSplitValues(inputText); var redirects = new List <extractionredirect>(); XElement root = new XElement("root"); foreach (var cstruct in conditionalStructs) { XElement element = new XElement("extractionredirect"); root.Add(element); var parsed = StringStructParser.GetCommaSplitValues(cstruct); var redirect = new extractionredirect(); if (parsed.TryGetValue("ModAltDLC", out var arp)) { element.SetAttributeValue("archiverootpath", arp.Replace('/', '\\')); } if (parsed.TryGetValue("ModDestDLC", out var rdd)) { element.SetAttributeValue("relativedestinationdirectory", @"BIOGame\DLC\" + rdd.Replace('/', '\\')); } if (parsed.TryGetValue("ConditionalDLC", out var ord)) { element.SetAttributeValue("optionalrequireddlc", string.Join(';', StringStructParser.GetSemicolonSplitList(ord))); } if (parsed.TryGetValue("RequiredFileRelativePaths", out var orf)) { element.SetAttributeValue("optionalrequiredfiles", string.Join(';', StringStructParser.GetSemicolonSplitList(orf).Select(x => x.Replace('/', '\\')))); } if (parsed.TryGetValue("RequiredFileSizes", out var orfs)) { element.SetAttributeValue("optionalrequiredfilessizes", string.Join(';', StringStructParser.GetSemicolonSplitList(orfs).Select(x => long.Parse(x)))); } if (parsed.TryGetValue("FriendlyName", out var ln)) { element.SetAttributeValue("loggingname", ln); } redirects.Add(redirect); //just for later convenience if i refactor this } return(root.ToString()); }
public AlternateFile(string alternateFileText, Mod modForValidating) { var properties = StringStructParser.GetCommaSplitValues(alternateFileText); if (properties.TryGetValue("FriendlyName", out string friendlyName)) { FriendlyName = friendlyName; } if (modForValidating.ModDescTargetVersion >= 6 && string.IsNullOrWhiteSpace(FriendlyName)) { //Cannot be null. Log.Error($"Alternate File does not specify FriendlyName. Mods targeting moddesc >= 6.0 cannot have empty FriendlyName"); ValidAlternate = false; LoadFailedReason = $"At least one specified Alternate File does not specify a FriendlyName, which is required for mods targeting cmmver >= 6.0."; return; } if (!Enum.TryParse(properties["Condition"], out Condition)) { Log.Error("Alternate File specifies unknown/unsupported condition: " + properties["Condition"]); ValidAlternate = false; LoadFailedReason = "Alternate File specifies unknown/unsupported condition: " + properties["Condition"]; return; } if (properties.TryGetValue("ConditionalDLC", out string conditionalDlc)) { var conditionalList = StringStructParser.GetSemicolonSplitList(conditionalDlc); foreach (var dlc in conditionalList) { //if (modForValidating.Game == Mod.MEGame.ME3) //{ if (Enum.TryParse(dlc, out ModJob.JobHeader header) && ModJob.GetHeadersToDLCNamesMap(modForValidating.Game).TryGetValue(header, out var foldername)) { ConditionalDLC.Add(foldername); continue; } //} if (!dlc.StartsWith("DLC_")) { Log.Error("An item in Alternate Files's ConditionalDLC doesn't start with DLC_"); LoadFailedReason = $"Alternate File ({FriendlyName}) specifies conditional DLC but no values match the allowed headers or start with DLC_."; return; } else { ConditionalDLC.Add(dlc); } } } if (!Enum.TryParse(properties["ModOperation"], out Operation)) { Log.Error("Alternate File specifies unknown/unsupported operation: " + properties["ModOperation"]); ValidAlternate = false; LoadFailedReason = "Alternate File specifies unknown/unsupported operation: " + properties["ModOperation"]; return; } if (properties.TryGetValue("Description", out string description)) { Description = description; } if (modForValidating.ModDescTargetVersion >= 6 && string.IsNullOrWhiteSpace(Description)) { //Cannot be null. Log.Error($"Alternate File {FriendlyName} with mod targeting moddesc >= 6.0 cannot have empty Description or missing description"); ValidAlternate = false; LoadFailedReason = $"Alternate File {FriendlyName} does not specify a Description, which is required for mods targeting cmmver >= 6.0."; return; } if (properties.TryGetValue("ModFile", out string modfile)) { ModFile = modfile.TrimStart('\\', '/'); } else { Log.Error("Alternate file in-mod target (ModFile) required but not specified. This value is required for all Alternate files"); ValidAlternate = false; LoadFailedReason = $"Alternate file {FriendlyName} does not declare ModFile but it is required for all Alternate Files."; return; } if (properties.TryGetValue("MultiMappingFile", out string multifilemapping)) { MultiMappingFile = multifilemapping.TrimStart('\\', '/'); } if (properties.TryGetValue("AltFile", out string altfile)) { AltFile = altfile; } else if (AltFile == null && properties.TryGetValue("ModAltFile", out string maltfile)) { AltFile = maltfile; } properties.TryGetValue("SubstituteFile", out SubstituteFile); //Only used in 4.5. In 5.0 and above this became AltFile. //workaround for 4.5 if (modForValidating.ModDescTargetVersion == 4.5 && Operation == AltFileOperation.OP_SUBSTITUTE && SubstituteFile != null) { AltFile = SubstituteFile; } if (!string.IsNullOrEmpty(AltFile)) { AltFile = AltFile.Replace('/', '\\'); //Standardize paths } //This needs reworked from java's hack implementation //Need to identify mods using substitution features if (Operation == AltFileOperation.OP_INSTALL || Operation == AltFileOperation.OP_SUBSTITUTE) { if (MultiMappingFile == null) { //Validate file var altPath = FilesystemInterposer.PathCombine(modForValidating.IsInArchive, modForValidating.ModPath, AltFile); var altFileSourceExists = FilesystemInterposer.FileExists(altPath, modForValidating.Archive); if (!altFileSourceExists) { Log.Error("Alternate file source (AltFile) does not exist: " + AltFile); ValidAlternate = false; LoadFailedReason = $"Alternate file is specified with operation {Operation}, but required file doesn't exist: {AltFile}"; return; } //Ensure it is not part of DLC directory itself. var modFile = FilesystemInterposer.PathCombine(modForValidating.IsInArchive, modForValidating.ModPath, ModFile); //Todo } else { //Multimapping, Todo } } if (properties.TryGetValue("ApplicableAutoText", out string applicableText)) { ApplicableAutoText = applicableText; } else { ApplicableAutoText = "Auto Applied"; } if (properties.TryGetValue("NotApplicableAutoText", out string notApplicableText)) { NotApplicableAutoText = notApplicableText; } else { NotApplicableAutoText = "Not applicable"; } if (Condition == AltFileCondition.COND_MANUAL && properties.TryGetValue("CheckedByDefault", out string checkedByDefault) && bool.TryParse(checkedByDefault, out bool cbd)) { CheckedByDefault = cbd; } CLog.Information($"Alternate file loaded and validated: {FriendlyName}", Settings.LogModStartup); ValidAlternate = true; }
public AlternateDLC(string alternateDLCText, Mod modForValidating, ModJob job) { var properties = StringStructParser.GetCommaSplitValues(alternateDLCText); //todo: if statements to check these. if (properties.TryGetValue(@"FriendlyName", out string friendlyName)) { FriendlyName = friendlyName; } if (modForValidating.ModDescTargetVersion >= 6 && string.IsNullOrWhiteSpace(FriendlyName)) { //Cannot be null. Log.Error(@"Alternate DLC does not specify FriendlyName. Mods targeting moddesc >= 6.0 require FriendlyName"); ValidAlternate = false; LoadFailedReason = M3L.GetString(M3L.string_validation_altdlc_oneAltDlcMissingFriendlyNameCmm6); return; } if (!Enum.TryParse(properties[@"Condition"], out Condition)) { Log.Error($@"Alternate DLC specifies unknown/unsupported condition: {properties[@"Condition"]}"); //do not localize ValidAlternate = false; var condition = properties[@"Condition"]; LoadFailedReason = $@"{M3L.GetString(M3L.string_validation_altdlc_unknownCondition)} {condition}"; return; } if (!Enum.TryParse(properties[@"ModOperation"], out Operation)) { Log.Error($@"Alternate DLC specifies unknown/unsupported operation: {properties[@"ModOperation"]}"); //do not localize ValidAlternate = false; var operation = properties[@"ModOperation"]; LoadFailedReason = $@"{M3L.GetString(M3L.string_validation_altdlc_unknownOperation)} {operation}"; return; } if (properties.TryGetValue(@"Description", out string description)) { Description = description; } if (modForValidating.ModDescTargetVersion >= 6 && string.IsNullOrWhiteSpace(Description)) { //Cannot be null. Log.Error($@"Alternate DLC {FriendlyName} cannot have empty Description or missing description as it targets cmmver >= 6"); ValidAlternate = false; LoadFailedReason = M3L.GetString(M3L.string_interp_validation_altdlc_cmmver6RequiresDescription, FriendlyName); return; } //OP_NOTHING can have conditions if (properties.TryGetValue(@"ConditionalDLC", out string conditionalDlc)) { var conditionalList = StringStructParser.GetSemicolonSplitList(conditionalDlc); foreach (var dlc in conditionalList) { //if (modForValidating.Game == Mod.MEGame.ME3) //{ //} if (Condition == AltDLCCondition.COND_SPECIFIC_DLC_SETUP) { //check +/- if (!dlc.StartsWith(@"-") && !dlc.StartsWith(@"+")) { Log.Error($@"An item in Alternate DLC's ({FriendlyName}) ConditionalDLC doesn't start with + or -. When using the condition {Condition}, you must precede DLC names with + or -. Bad value: {dlc}"); LoadFailedReason = $"An item in Alternate DLC's ({FriendlyName}) ConditionalDLC doesn't start with + or -. When using the condition {Condition}, you must precede DLC names with + or -. Bad value: {dlc}"; return; } var prefix = dlc.Substring(0, 1); var realname = dlc.Substring(1); //official headers if (Enum.TryParse(realname, out ModJob.JobHeader header) && ModJob.GetHeadersToDLCNamesMap(modForValidating.Game).TryGetValue(header, out var foldername)) { ConditionalDLC.Add(prefix + foldername); continue; } //dlc mods if (!realname.StartsWith(@"DLC_")) { Log.Error($@"An item in Alternate DLC's ({FriendlyName}) ConditionalDLC doesn't start with DLC_ or is not official header (after the +/- required by {Condition}). Bad value: {dlc}"); LoadFailedReason = $"An item in Alternate DLC's ({FriendlyName}) ConditionalDLC doesn't start with DLC_ or is not official header (after the +/- required by {Condition}). Bad value: {dlc}"; return; } else { ConditionalDLC.Add(prefix + realname); } } else { if (Enum.TryParse(dlc, out ModJob.JobHeader header) && ModJob.GetHeadersToDLCNamesMap(modForValidating.Game).TryGetValue(header, out var foldername)) { ConditionalDLC.Add(foldername); continue; } if (!dlc.StartsWith(@"DLC_")) { Log.Error($@"An item in Alternate DLC's ({FriendlyName}) ConditionalDLC doesn't start with DLC_ or is not official header"); LoadFailedReason = M3L.GetString(M3L.string_interp_validation_altdlc_conditionalDLCInvalidValue, FriendlyName); return; } else { ConditionalDLC.Add(dlc); } } } } if (Operation != AltDLCOperation.OP_NOTHING) { int multilistid = -1; if (Operation == AltDLCOperation.OP_ADD_MULTILISTFILES_TO_CUSTOMDLC) { if (properties.TryGetValue(@"MultiListRootPath", out var rootpath)) { MultiListRootPath = rootpath.TrimStart('\\', '/').Replace('/', '\\'); } else { Log.Error($@"Alternate DLC ({FriendlyName}) specifies operation OP_ADD_MULTILISTFILES_TO_CUSTOMDLC but does not specify the required item MultiListRootPath."); ValidAlternate = false; LoadFailedReason = M3L.GetString(M3L.string_interp_altdlc_multilistMissingMultiListRootPath, FriendlyName); return; } if (properties.TryGetValue(@"MultiListId", out string multilistidstr) && int.TryParse(multilistidstr, out multilistid)) { if (job.MultiLists.TryGetValue(multilistid, out var ml)) { MultiListSourceFiles = ml; } else { Log.Error($@"Alternate DLC ({FriendlyName}) Multilist ID does not exist as part of the task: multilist" + multilistid); ValidAlternate = false; var id = @"multilist" + multilistid; LoadFailedReason = M3L.GetString(M3L.string_interp_altdlc_multilistMissingMultiListX, FriendlyName, id); return; } } else { Log.Error($@"Alternate DLC ({FriendlyName}) specifies operation OP_ADD_MULTILISTFILES_TO_CUSTOMDLC but does not specify the MultiListId attribute, or it could not be parsed to an integer."); ValidAlternate = false; LoadFailedReason = M3L.GetString(M3L.string_interp_altdlc_multilistIdNotIntegerOrMissing, FriendlyName); return; } } else { if (properties.TryGetValue(@"ModAltDLC", out string altDLCFolder)) { AlternateDLCFolder = altDLCFolder.Replace('/', '\\'); } else { Log.Error(@"Alternate DLC does not specify ModAltDLC but is required"); ValidAlternate = false; LoadFailedReason = M3L.GetString(M3L.string_interp_validation_altdlc_missingModAltDLC, FriendlyName); return; } } if (properties.TryGetValue(@"ModDestDLC", out string destDLCFolder)) { DestinationDLCFolder = destDLCFolder.Replace('/', '\\'); } else { Log.Error(@"Alternate DLC does not specify ModDestDLC but is required"); ValidAlternate = false; LoadFailedReason = M3L.GetString(M3L.string_interp_validation_altdlc_missingModDestDLC, FriendlyName); return; } //todo: Validate target in mod folder //Validation if (string.IsNullOrWhiteSpace(AlternateDLCFolder) && MultiListRootPath == null) { Log.Error($@"Alternate DLC directory (ModAltDLC) not specified for { FriendlyName}"); LoadFailedReason = M3L.GetString(M3L.string_interp_validation_altdlc_sourceDirectoryNotSpecifiedForModAltDLC, FriendlyName); return; } if (string.IsNullOrWhiteSpace(DestinationDLCFolder)) { Log.Error($@"Destination DLC directory (ModDestDLC) not specified for {FriendlyName}"); LoadFailedReason = M3L.GetString(M3L.string_interp_validation_altdlc_destinationDirectoryNotSpecifiedForModDestDLC, FriendlyName); return; } if (AlternateDLCFolder != null) { AlternateDLCFolder = AlternateDLCFolder.TrimStart('\\', '/').Replace('/', '\\'); //Check ModAltDLC directory exists var localAltDlcDir = FilesystemInterposer.PathCombine(modForValidating.IsInArchive, modForValidating.ModPath, AlternateDLCFolder); if (!FilesystemInterposer.DirectoryExists(localAltDlcDir, modForValidating.Archive)) { Log.Error($@"Alternate DLC directory (ModAltDLC) does not exist: {AlternateDLCFolder}"); LoadFailedReason = M3L.GetString(M3L.string_interp_validation_altdlc_sourceDirectoryDoesntExist, FriendlyName, AlternateDLCFolder); return; } } else if (MultiListRootPath != null) { foreach (var multif in MultiListSourceFiles) { var path = FilesystemInterposer.PathCombine(modForValidating.IsInArchive, modForValidating.ModPath, MultiListRootPath, multif); if (!FilesystemInterposer.FileExists(path, modForValidating.Archive)) { Log.Error($@"Alternate DLC ({FriendlyName}) specifies a multilist (index {multilistid}) that contains file that does not exist: {multif}"); LoadFailedReason = M3L.GetString(M3L.string_interp_altdlc_multilistMissingFileInMultilist, FriendlyName, multilistid, multif); return; } } } } DLCRequirementsForManual = properties.TryGetValue(@"DLCRequirements", out string dlcReqs) ? dlcReqs.Split(';') : null; if (Condition == AltDLCCondition.COND_SPECIFIC_SIZED_FILES) { var requiredFilePaths = properties.TryGetValue(@"RequiredFileRelativePaths", out string _requiredFilePaths) ? _requiredFilePaths.Split(';').ToList() : new List <string>(); var requiredFileSizes = properties.TryGetValue(@"RequiredFileSizes", out string _requiredFileSizes) ? _requiredFileSizes.Split(';').ToList() : new List <string>(); if (requiredFilePaths.Count() != requiredFileSizes.Count()) { Log.Error($@"Alternate DLC {FriendlyName} uses COND_SPECIFIC_SIZED_FILES but the amount of items in the RequiredFileRelativePaths and RequiredFileSizes lists are not equal"); ValidAlternate = false; LoadFailedReason = $"Alternate DLC {FriendlyName} uses COND_SPECIFIC_SIZED_FILES but the amount of items in the RequiredFileRelativePaths and RequiredFileSizes lists are not equal"; return; } for (int i = 0; i < requiredFilePaths.Count(); i++) { var reqFile = requiredFilePaths[i]; var reqSizeStr = requiredFileSizes[i]; if (reqFile.Contains(@"..")) { Log.Error($@"Alternate DLC {FriendlyName} RequiredFileRelativePaths item {reqFile} is invalid: Values cannot contain '..' for security reasons"); ValidAlternate = false; LoadFailedReason = $"Alternate DLC {FriendlyName} RequiredFileRelativePaths item {reqFile} is invalid: Values cannot contain '..' for security reasons"; return; } if (long.TryParse(reqSizeStr, out var reqSize) && reqSize >= 0) { RequiredSpecificFiles[reqFile] = reqSize; } else { Log.Error($@"Alternate DLC {FriendlyName} RequiredFileSizes item {reqFile} is invalid: {reqSizeStr}. Values must be greater than or equal to zero."); ValidAlternate = false; LoadFailedReason = $"Alternate DLC {FriendlyName} RequiredFileSizes item {reqFile} is invalid: {reqSizeStr}. Values must be greater than or equal to zero."; return; } } if (!RequiredSpecificFiles.Any()) { Log.Error($@"Alternate DLC {FriendlyName} is invalid: COND_SPECIFIC_SIZED_FILES is specified as the condition but there are no values in RequiredFileRelativePaths/RequiredFileSizes"); ValidAlternate = false; LoadFailedReason = $"Alternate DLC {FriendlyName} is invalid: COND_SPECIFIC_SIZED_FILES is specified as the condition but there are no values in RequiredFileRelativePaths/RequiredFileSizes"; return; } } ApplicableAutoText = properties.TryGetValue(@"ApplicableAutoText", out string applicableText) ? applicableText : M3L.GetString(M3L.string_autoApplied); NotApplicableAutoText = properties.TryGetValue(@"NotApplicableAutoText", out string notApplicableText) ? notApplicableText : M3L.GetString(M3L.string_notApplicable); if (modForValidating.ModDescTargetVersion >= 6.0) { GroupName = properties.TryGetValue(@"OptionGroup", out string groupName) ? groupName : null; //TODO: FORCE OPTIONGROUP TO HAVE ONE ITEM CHECKEDBYDFEAULT. HAVE TO CHECK AT HIGHER LEVEL IN PARSER } if (Condition == AltDLCCondition.COND_MANUAL && properties.TryGetValue(@"CheckedByDefault", out string checkedByDefault) && bool.TryParse(checkedByDefault, out bool cbd)) { CheckedByDefault = cbd; } if (Condition != AltDLCCondition.COND_MANUAL && Condition != AltDLCCondition.INVALID_CONDITION) { //ensure conditional dlc list has at least one item. if (ConditionalDLC.Count == 0) { Log.Error($@"Alternate DLC {FriendlyName} cannot have empty or missing Conditional DLC list, as it does not use COND_MANUAL."); ValidAlternate = false; LoadFailedReason = M3L.GetString(M3L.string_interp_altdlc_emptyConditionalDLCList, FriendlyName); return; } } CLog.Information($@"AlternateDLC loaded and validated: {FriendlyName}", Settings.LogModStartup); ValidAlternate = true; }
public AlternateDLC(string alternateDLCText, Mod modForValidating) { var properties = StringStructParser.GetCommaSplitValues(alternateDLCText); //todo: if statements to check these. if (properties.TryGetValue("FriendlyName", out string friendlyName)) { FriendlyName = friendlyName; } if (modForValidating.ModDescTargetVersion >= 6 && string.IsNullOrWhiteSpace(FriendlyName)) { //Cannot be null. Log.Error($"Alternate DLC does not specify FriendlyName. Mods targeting moddesc >= 6.0 require FriendlyName"); ValidAlternate = false; LoadFailedReason = $"At least one specified Alternate DLC does not specify a FriendlyName, which is required for mods targeting cmmver >= 6.0."; return; } if (!Enum.TryParse(properties["Condition"], out Condition)) { Log.Error("Alternate DLC specifies unknown/unsupported condition: " + properties["Condition"]); ValidAlternate = false; LoadFailedReason = "Alternate DLC specifies unknown/unsupported condition: " + properties["Condition"]; return; } if (!Enum.TryParse(properties["ModOperation"], out Operation)) { Log.Error("Alternate DLC specifies unknown/unsupported operation: " + properties["ModOperation"]); ValidAlternate = false; LoadFailedReason = "Alternate DLC specifies unknown/unsupported operation: " + properties["ModOperation"]; return; } if (properties.TryGetValue("Description", out string description)) { Description = description; } if (modForValidating.ModDescTargetVersion >= 6 && string.IsNullOrWhiteSpace(Description)) { //Cannot be null. Log.Error($"Alternate DLC {FriendlyName} cannot have empty Description or missing description as it targets cmmver >= 6"); ValidAlternate = false; LoadFailedReason = $"Alternate DLC {FriendlyName} does not specify a Description, which is required for mods targeting cmmver >= 6.0."; return; } if (properties.TryGetValue("ModAltDLC", out string altDLCFolder)) { AlternateDLCFolder = altDLCFolder.Replace('/', '\\'); } else { Log.Error("Alternate DLC does not specify ModAltDLC but is required"); ValidAlternate = false; LoadFailedReason = $"Alternate DLC {FriendlyName} does not declare ModAltDLC but it is required for all Alternate DLC."; return; } if (properties.TryGetValue("ModDestDLC", out string destDLCFolder)) { DestinationDLCFolder = destDLCFolder.Replace('/', '\\'); } else { Log.Error("Alternate DLC does not specify ModDestDLC but is required"); ValidAlternate = false; LoadFailedReason = $"Alternate DLC {FriendlyName} does not declare ModDestDLC but it is required for all Alternate DLC."; return; } //todo: Validate target in mod folder if (properties.TryGetValue("ConditionalDLC", out string conditionalDlc)) { var conditionalList = StringStructParser.GetSemicolonSplitList(conditionalDlc); foreach (var dlc in conditionalList) { //if (modForValidating.Game == Mod.MEGame.ME3) //{ if (Enum.TryParse(dlc, out ModJob.JobHeader header) && ModJob.GetHeadersToDLCNamesMap(modForValidating.Game).TryGetValue(header, out var foldername)) { ConditionalDLC.Add(foldername); continue; } //} if (!dlc.StartsWith("DLC_")) { Log.Error("An item in Alternate DLC's ConditionalDLC doesn't start with DLC_"); LoadFailedReason = $"Alternate DLC ({FriendlyName}) specifies conditional DLC but no values match the allowed headers or start with DLC_."; return; } else { ConditionalDLC.Add(dlc); } } } if (properties.TryGetValue("ApplicableAutoText", out string applicableText)) { ApplicableAutoText = applicableText; } else { ApplicableAutoText = "Auto Applied"; } if (properties.TryGetValue("NotApplicableAutoText", out string notApplicableText)) { NotApplicableAutoText = notApplicableText; } else { NotApplicableAutoText = "Not applicable"; } if (Condition == AltDLCCondition.COND_MANUAL && properties.TryGetValue("CheckedByDefault", out string checkedByDefault) && bool.TryParse(checkedByDefault, out bool cbd)) { CheckedByDefault = cbd; } //Validation if (string.IsNullOrWhiteSpace(AlternateDLCFolder)) { Log.Error("Alternate DLC directory (ModAltDLC) not specified"); LoadFailedReason = $"Alternate DLC for AltDLC ({FriendlyName}) is specified, but source directory (ModAltDLC) was not specified."; return; } if (string.IsNullOrWhiteSpace(DestinationDLCFolder)) { Log.Error("Destination DLC directory (ModDestDLC) not specified"); LoadFailedReason = $"Destination DLC for AltDLC ({FriendlyName}) is specified, but source directory (ModDestDLC) was not specified."; return; } AlternateDLCFolder = AlternateDLCFolder.TrimStart('\\', '/').Replace('/', '\\'); //Check ModAltDLC directory exists var localAltDlcDir = FilesystemInterposer.PathCombine(modForValidating.IsInArchive, modForValidating.ModPath, AlternateDLCFolder); if (!FilesystemInterposer.DirectoryExists(localAltDlcDir, modForValidating.Archive)) { Log.Error("Alternate DLC directory (ModAltDLC) does not exist: " + AlternateDLCFolder); LoadFailedReason = $"Alternate DLC ({FriendlyName}) is specified, but source for alternate DLC directory does not exist: {AlternateDLCFolder}"; return; } CLog.Information($"AlternateDLC loaded and validated: {FriendlyName}", Settings.LogModStartup); ValidAlternate = true; }