public static bool RandomizeWeapons(RandomizationOption option) { var me2rbioweapon = CoalescedHandler.GetIniFile("BIOWeapon.ini"); // We must manually fetch game files cause MERFS will return the ini from the dlc mod instead. ME2Coalesced me2basegamecoalesced = new ME2Coalesced(MERFileSystem.GetSpecificFile(@"BioGame\Config\PC\Cooked\Coalesced.ini")); MERLog.Information("Randomizing basegame weapon ini"); var bioweapon = me2basegamecoalesced.Inis.FirstOrDefault(x => Path.GetFileName(x.Key) == "BIOWeapon.ini").Value; RandomizeWeaponIni(bioweapon, me2rbioweapon); var weaponInis = Directory.GetFiles(MEDirectories.GetDLCPath(MERFileSystem.Game), "BIOWeapon.ini", SearchOption.AllDirectories).ToList(); foreach (var wi in weaponInis) { if (wi.Contains($"DLC_MOD_{MERFileSystem.Game}Randomizer")) { continue; // Skip randomizer folders } MERLog.Information($@"Randomizing weapon ini {wi}"); //Log.Information("Randomizing weapons in ini: " + wi); var dlcWeapIni = DuplicatingIni.LoadIni(wi); RandomizeWeaponIni(dlcWeapIni, me2rbioweapon); //if (!MERFileSystem.UsingDLCModFS) //{ // Log.Information("Writing DLC BioWeapon: " + wi); // File.WriteAllText(wi, dlcWeapIni.ToString()); //} } return(true); }
public override void LoadCurrentValue(DuplicatingIni configIni) { var entry = configIni.GetValue(SectionName, PropertyName); int index = -1; bool indexFound = false; if (entry != null) { foreach (IniPropertyEnumValue enumval in Choices) { index++; if (enumval.IniValue.Equals(entry.Value, StringComparison.InvariantCultureIgnoreCase)) { indexFound = true; break; } } if (!indexFound) { //user has their own item IniPropertyEnumValue useritem = new IniPropertyEnumValue(); useritem.FriendlyName = useritem.IniValue = entry.Value; Choices.Add(useritem); CurrentSelectedIndex = Choices.Count - 1; } else { CurrentSelectedIndex = index; } } }
/// <summary> /// Decodes a .par file to it's ini contents /// </summary> /// <param name="parEncryptedFile"></param> /// <returns></returns> public static DuplicatingIni DecodePAR(byte[] parEncryptedFile) { int PARFileKeyPosition = 0; byte[] PARFileContentToProcess; char[] PARFileXORedContent = new char[parEncryptedFile.Length]; byte[] PARFileKeyByteArray = Encoding.UTF8.GetBytes(parEncKey); if (parEncryptedFile[0] != 0x2A || //Magic? CRC? parEncryptedFile[1] != 0x02 || parEncryptedFile[2] != 0x11 || parEncryptedFile[3] != 0x3C) { PARFileContentToProcess = parEncryptedFile.Skip(4).ToArray(); } else { PARFileContentToProcess = parEncryptedFile; } for (int i = 0; i < PARFileContentToProcess.Length; i++) { PARFileXORedContent[i] = (char)(PARFileContentToProcess[i] ^ PARFileKeyByteArray[PARFileKeyPosition]); PARFileKeyPosition = ((PARFileKeyPosition + 1) % PARFileKeyByteArray.Length); } var decPar = new string(PARFileXORedContent); return(DuplicatingIni.ParseIni(decPar)); }
private static void SetupM3InNXMHandler(string nxmIniPath) { DuplicatingIni ini = DuplicatingIni.LoadIni(nxmIniPath); var handlers = ini.GetOrAddSection("handlers"); var numCurrentHandlersStr = handlers.GetValue("size")?.Value; int.TryParse(numCurrentHandlersStr, out var numCurrentHandlers); // Find if M3 has been registered for me/me2/me3 bool updated = false; for (int i = 1; i <= numCurrentHandlers; i++) { var games = handlers.GetValue($@"{i}\games"); if (games == null) { // ??? // Is ini configured incorrectly? Log.Warning(@"NXMHandler ini appears to be configured incorrectly"); } else { if (games.Value == "other") { Log.Information(@"Updating 'other' in nxmhandler"); // We need to update this one handlers.SetSingleEntry($@"{i}\executable", App.ExecutableLocation.Replace("\\", "\\\\")); handlers.SetSingleEntry($@"{i}\arguments", "--nxmlink"); updated = true; } } } if (!updated) { // Add ours Log.Warning(@"Adding section 'other' in nxmhandler"); numCurrentHandlers++; handlers.SetSingleEntry($@"size", numCurrentHandlers); handlers.SetSingleEntry($@"{numCurrentHandlers}\games", "other"); handlers.SetSingleEntry($@"{numCurrentHandlers}\executable", App.ExecutableLocation.Replace("\\", "\\\\")); handlers.SetSingleEntry($@"{numCurrentHandlers}\arguments", "--nxmlink"); } File.WriteAllText(nxmIniPath, ini.ToString()); Log.Information(@"Finished configuring nxmhandler"); // Register nxm protocol }
public virtual void LoadCurrentValue(DuplicatingIni configIni) { var entry = configIni.GetValue(SectionName, PropertyName); if (entry != null) { var val = entry.Value; if (val.Contains(@";")) { val = val.Substring(0, val.IndexOf(';')).Trim(); } CurrentValue = val; } }
private void SetME1ConsoleKeybinds(string consoleKeyStr, string typeKeyStr, bool wipeTypeKey = false) { var iniFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), @"BioWare", @"Mass Effect", @"Config", @"BIOInput.ini"); if (File.Exists(iniFile)) { var ini = DuplicatingIni.LoadIni(iniFile); SetIniBasedKeybinds(ini, consoleKeyStr, typeKeyStr, wipeTypeKey); var wasReadOnly = Utilities.ClearReadOnly(iniFile); File.WriteAllText(iniFile, ini.ToString()); if (wasReadOnly) { Utilities.SetReadOnly(iniFile); } } }
public static int GetMountPriority(string dlcDirectory, MEGame game) { if (game == MEGame.ME1) { int idx = 1 + ME1Directory.OfficialDLC.IndexOf(Path.GetFileName(dlcDirectory)); if (idx > 0) { return(idx); } //is mod string autoLoadPath = Path.Combine(dlcDirectory, "AutoLoad.ini"); var dlcAutoload = DuplicatingIni.LoadIni(autoLoadPath); return(Convert.ToInt32(dlcAutoload["ME1DLCMOUNT"]["ModMount"].Value)); // Should we try catch this to avoid hitting an exception on malformed mods? Like DLC_xMeow } return(MountFile.GetMountPriority(GetMountDLCFromDLCDir(dlcDirectory, game))); }
private void saveData() { var saveMap = new Dictionary <string, List <IniPropertyMaster> >(); saveMap[@"BioEngine.ini"] = BioEngineEntries.ToList(); saveMap[@"BioGame.ini"] = BioGameEntries.ToList(); saveMap[@"BioParty.ini"] = BioPartyEntries.ToList(); string configFileFolder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + @"\BioWare\Mass Effect\Config"; foreach (var kp in saveMap) { string configFileBeingUpdated = Path.Combine(configFileFolder, kp.Key); if (File.Exists(configFileBeingUpdated)) { Log.Information(@"MEIM: Saving ini file: " + configFileBeingUpdated); //unset readonly File.SetAttributes(configFileBeingUpdated, File.GetAttributes(configFileBeingUpdated) & ~FileAttributes.ReadOnly); DuplicatingIni ini = DuplicatingIni.LoadIni(configFileBeingUpdated); foreach (IniPropertyMaster prop in kp.Value) { string validation = prop.Validate(@"CurrentValue"); if (validation == null) { var itemToUpdate = ini.GetValue(prop.SectionName, prop.PropertyName); if (itemToUpdate != null) { itemToUpdate.Value = prop.ValueToWrite; } else { Log.Error($@"Could not find property to update in ini! [{prop.SectionName}] {prop.PropertyName}"); } } else { Log.Error($@"Could not save property {prop.FriendlyPropertyName} because {validation}"); M3L.ShowDialog(this, M3L.GetString(M3L.string_interp_propertyNotSaved, prop.FriendlyPropertyName, validation), M3L.GetString(M3L.string_errorSavingProperties), MessageBoxButton.OK, MessageBoxImage.Error); } } Analytics.TrackEvent(@"Saved game config in MEIM"); File.WriteAllText(configFileBeingUpdated, ini.ToString()); ShowMessage(M3L.GetString(M3L.string_saved)); } } }
private void LoadME1Keys() { if (mainwindow.InstallationTargets.Where(x => x.Selectable).Any()) { var iniFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), @"BioWare", @"Mass Effect", @"Config", @"BIOInput.ini"); if (File.Exists(iniFile)) { var ini = DuplicatingIni.LoadIni(iniFile); var engineConsole = ini.Sections.FirstOrDefault(x => x.Header == @"Engine.Console"); if (engineConsole != null) { var consoleKey = engineConsole.Entries.FirstOrDefault(x => x.Key == @"ConsoleKey"); if (consoleKey == null) { ME1FullConsoleKeyText = M3L.GetString(M3L.string_fullConsoleNotBoundToAKey); } else { ME1FullConsoleKeyText = M3L.GetString(M3L.string_interp_fullConsoleBoundToX, consoleKey.Value); } var typeKey = engineConsole.Entries.FirstOrDefault(x => x.Key == @"TypeKey"); if (typeKey == null) { ME1MiniConsoleKeyText = M3L.GetString(M3L.string_miniConsoleNotBoundToAKey); } else { ME1MiniConsoleKeyText = M3L.GetString(M3L.string_interp_miniConsoleBoundToX, typeKey.Value); } } } else { HasME1Install = false; ME1FullConsoleKeyText = M3L.GetString(M3L.string_bioInputiniFileIsMissing); ME1MiniConsoleKeyText = M3L.GetString(M3L.string_runGameToGenerateFile); } } else { HasME1Install = false; ME1FullConsoleKeyText = M3L.GetString(M3L.string_noInstallsOfGameManagedByModManager); ME1MiniConsoleKeyText = ""; } }
public ME2Coalesced(string file) { Inputfile = file; using FileStream fs = new FileStream(file, FileMode.Open); int unknownInt = fs.ReadInt32(); if (unknownInt != 0x1E) { throw new Exception("First 4 bytes were not 0x1E (was " + unknownInt.ToString("X8") + ").This does not appear to be a Coalesced file."); } while (fs.Position < fs.Length) { long pos = fs.Position; string filename = fs.ReadUnrealString(); string contents = fs.ReadUnrealString(); Inis[filename] = DuplicatingIni.ParseIni(contents); } }
public override void LoadCurrentValue(DuplicatingIni configIni) { base.LoadCurrentValue(configIni); try { if (CurrentValue != "") { CurrentSelectedBoolIndex = bool.Parse(CurrentValue) ? 0 : 1; } else { CurrentSelectedBoolIndex = bool.Parse(OriginalValue) ? 0 : 1; } } catch (Exception) { //error parsing current value Notes = @"Error parsing current bool value: " + CurrentValue; CurrentSelectedBoolIndex = bool.Parse(OriginalValue) ? 0 : 1; } }
private static void SetIniBasedKeybinds(DuplicatingIni bioinput, string consoleKeyStr, string typeKeyStr, bool wipeTypeKey = false) { var engineConsole = bioinput.Sections.FirstOrDefault(x => x.Header == @"Engine.Console"); if (engineConsole != null) { if (consoleKeyStr != null) { var consoleKey = engineConsole.Entries.FirstOrDefault(x => x.Key == @"ConsoleKey"); if (consoleKey != null) { consoleKey.Value = consoleKeyStr; } else { engineConsole.Entries.Add(new DuplicatingIni.IniEntry(@"ConsoleKey=" + typeKeyStr)); } } var typeKey = engineConsole.Entries.FirstOrDefault(x => x.Key == @"TypeKey"); if (wipeTypeKey && typeKey != null) { engineConsole.Entries.Remove(typeKey); } if (typeKeyStr != null) { if (typeKey != null) { typeKey.Value = typeKeyStr; } else { //Create Typekey engineConsole.Entries.Add(new DuplicatingIni.IniEntry(@"TypeKey=" + typeKeyStr)); } } } }
private static void RandomizeWeaponIni(DuplicatingIni vanillaFile, DuplicatingIni randomizerIni) { foreach (var section in vanillaFile.Sections) { var sectionsplit = section.Header.Split('.').ToList(); if (sectionsplit.Count > 1) { var objectname = sectionsplit[1]; if (objectname.StartsWith("SFXWeapon_") || objectname.StartsWith("SFXHeavyWeapon_")) { //We can randomize this section of the ini. Debug.WriteLine($"Randomizing weapon {objectname}"); var outSection = randomizerIni.GetOrAddSection(section.Header); foreach (var entry in section.Entries) { if (KeysToNotRandomize.Contains(entry.Key, StringComparer.InvariantCultureIgnoreCase)) { continue; // Do not touch this key } if (entry.HasValue) { // if (entry.Key == "Damage") Debugger.Break(); string value = entry.Value; //range check if (value.StartsWith("(")) { value = value.Substring(0, value.IndexOf(')') + 1); //trim off trash on end (like ; comment ) var p = StringStructParser.GetCommaSplitValues(value); if (p.Count == 2) { try { bool isInt = false; float x = 0; float y = 0; bool isZeroed = false; if (int.TryParse(p["X"].TrimEnd('f'), out var intX) && int.TryParse(p["Y"].TrimEnd('f'), out var intY)) { //integers if (intX < 0 && intY < 0) { Debug.WriteLine($" BELOW ZERO INT: {entry.Key} for {objectname}: {entry.RawText}"); } bool validValue = false; for (int i = 0; i < 10; i++) { bool isMaxMin = intX > intY; //bool isMinMax = intY < intX; isZeroed = intX == 0 && intY == 0; if (isZeroed) { validValue = true; break; } ; //skip bool isSame = intX == intY; bool belowzeroInt = intX < 0 || intY < 0; bool abovezeroInt = intX > 0 || intY > 0; int Max = isMaxMin ? intX : intY; int Min = isMaxMin ? intY : intX; int range = Max - Min; if (range == 0) { range = Max; } if (range == 0) { Debug.WriteLine("Range still 0"); } int rangeExtension = range / 2; //50% int newMin = Math.Max(0, ThreadSafeRandom.Next(Min - rangeExtension, Min + rangeExtension)); int newMax = ThreadSafeRandom.Next(Max - rangeExtension, Max + rangeExtension); intX = isMaxMin ? newMax : newMin; intY = isMaxMin ? newMin : newMax; //might need to check zeros //if (entry.Key.Contains("MagSize")) Debugger.Break(); if (intX != 0 || intY != 0) { x = intX; y = intY; if (isSame) { x = intY; } if (!belowzeroInt && (x <= 0 || y <= 0)) { continue; //not valid. Redo this loop } if (abovezeroInt && (x <= 0 || y <= 0)) { continue; //not valid. Redo this loop } validValue = true; break; //break loop } } if (!validValue) { Debug.WriteLine($"Failed rerolls: {entry.Key} for {objectname}: {entry.RawText}"); } } else { //if (section.Header.Contains("SFXWeapon_GethShotgun")) Debugger.Break(); //floats //Fix error in bioware's coalesced file if (p["X"] == "0.65.0f") { p["X"] = "0.65f"; } float floatx = float.Parse(p["X"].TrimEnd('f')); float floaty = float.Parse(p["Y"].TrimEnd('f')); bool belowzeroFloat = false; if (floatx < 0 || floaty < 0) { Debug.WriteLine($" BELOW ZERO FLOAT: {entry.Key} for {objectname}: {entry.RawText}"); belowzeroFloat = true; } bool isMaxMin = floatx > floaty; bool isMinMax = floatx < floaty; bool isSame = floatx == floaty; isZeroed = floatx == 0 && floaty == 0; if (isZeroed) { continue; } ; //skip float Max = isMaxMin ? floatx : floaty; float Min = isMaxMin ? floaty : floatx; float range = Max - Min; if (range == 0) { range = 0.1f * Max; } float rangeExtension = range * .5f; //50% if (ThreadSafeRandom.Next(10) == 0) { rangeExtension = range * 15f; // Extreme } float newMin = Math.Max(0, ThreadSafeRandom.NextFloat(Min - rangeExtension, Min + rangeExtension)); float newMax = ThreadSafeRandom.NextFloat(Max - rangeExtension, Max + rangeExtension); if (!belowzeroFloat) { //ensure they don't fall below 0 if (newMin < 0) { newMin = Math.Max(newMin, Min / 2); } if (newMax < 0) { newMax = Math.Max(newMax, Max / 2); } //i have no idea what i'm doing } floatx = isMaxMin ? newMax : newMin; floaty = isMaxMin ? newMin : newMax; //might need to check zeros x = floatx; y = floaty; if (isSame) { x = y; } } if (isZeroed) { continue; //skip } // Write out the new value outSection.SetSingleEntry(entry.Key, $"(X={x},Y={y})"); } catch (Exception e) { Log.Error($"Cannot randomize weapon stat {objectname} {entry.Key}: {e.Message}"); } } } else { //Debug.WriteLine(entry.Key); var initialValue = entry.Value.ToString(); var isInt = int.TryParse(entry.Value, out var valueInt); var isFloat = float.TryParse(entry.Value, out var valueFloat); switch (entry.Key) { case "BurstRounds": { var burstMax = valueInt * 2; entry.Value = (ThreadSafeRandom.Next(burstMax) + 1).ToString(); } break; case "RateOfFireAI": case "DamageAI": { entry.Value = ThreadSafeRandom.NextFloat(.1, 2).ToString(CultureInfo.InvariantCulture); } break; case "RecoilInterpSpeed": case "RecoilFadeSpeed": case "RecoilZoomFadeSpeed": case "RecoilYawScale": case "RecoilYawFrequency": case "RecoilYawNoise": case "DamageHench": case "BurstRefireTime": case "ZoomAccFirePenalty": case "ZoomAccFireInterpSpeed": case "FirstHitDamage": case "SecondHitDamage": case "ThirdHitDamage": { entry.Value = ThreadSafeRandom.NextFloat(valueFloat / 2, valueFloat * 1.5).ToString(CultureInfo.InvariantCulture); } break; case "bIsAutomatic": { var curValue = bool.Parse(entry.Value); entry.Value = ThreadSafeRandom.Next(5) == 0 ? (!curValue).ToString() : entry.Value.ToString(); } break; case "MinRefireTime": { entry.Value = ThreadSafeRandom.NextFloat(0.01, 1).ToString(); } break; case "AccFirePenalty": case "AccFireInterpSpeed": { entry.Value = ThreadSafeRandom.NextFloat(0, valueFloat * 1.75).ToString(CultureInfo.InvariantCulture); } break; case "AmmoPerShot": { if (ThreadSafeRandom.Next(10) == 0) { entry.Value = "2"; } // Otherwise do not change } break; case "AIBurstRefireTimeMin": entry.Value = ThreadSafeRandom.NextFloat(0, 2).ToString(CultureInfo.InvariantCulture); break; case "AIBurstRefireTimeMax": entry.Value = ThreadSafeRandom.NextFloat(1, 5).ToString(CultureInfo.InvariantCulture); break; case "MaxSpareAmmo": entry.Value = ThreadSafeRandom.Next(valueInt / 10, valueInt * 2).ToString(CultureInfo.InvariantCulture); break; default: Debug.WriteLine($"Undone key: {entry.Key}"); break; } if (entry.Value != initialValue) { outSection.SetSingleEntry(entry.Key, entry.Value); } } } } // whats this do? //if (section.Entries.All(x => x.Key != "Damage")) //{ // float X = ThreadSafeRandom.NextFloat(2, 7); // float Y = ThreadSafeRandom.NextFloat(2, 7); // section.Entries.Add(new DuplicatingIni.IniEntry($"Damage=(X={X},Y={Y})")); //} } } } }
public static void BuildBioPGlobal(GameTarget target) { M3MergeDLC.RemoveMergeDLC(target); var loadedFiles = MELoadedFiles.GetFilesLoadedInGame(target.Game, gameRootOverride: target.TargetPath); //var mergeFiles = loadedFiles.Where(x => // x.Key.StartsWith(@"BioH_") && x.Key.Contains(@"_DLC_MOD_") && x.Key.EndsWith(@".pcc") && !x.Key.Contains(@"_LOC_") && !x.Key.Contains(@"_Explore.")); Log.Information($@"SQMMERGE: Building BioP_Global"); var appearanceInfo = new CaseInsensitiveDictionary <List <SquadmateInfoSingle> >(); int appearanceId = 255; // starting int currentConditional = STARTING_OUTFIT_CONDITIONAL; // Scan squadmate merge files var sqmSupercedances = M3Directories.GetFileSupercedances(target, new[] { @".sqm" }); if (sqmSupercedances.TryGetValue(SQUADMATE_MERGE_MANIFEST_FILE, out var infoList)) { infoList.Reverse(); foreach (var dlc in infoList) { Log.Information($@"SQMMERGE: Processing {dlc}"); var jsonFile = Path.Combine(M3Directories.GetDLCPath(target), dlc, target.Game.CookedDirName(), SQUADMATE_MERGE_MANIFEST_FILE); var infoPackage = JsonConvert.DeserializeObject <SquadmateMergeInfo>(File.ReadAllText(jsonFile)); if (!infoPackage.Validate(dlc, target, loadedFiles)) { continue; // skip this } // Enumerate all outfits listed for a single squadmate foreach (var outfit in infoPackage.Outfits) { List <SquadmateInfoSingle> list; // See if we already have an outfit list for this squadmate, maybe from another mod... if (!appearanceInfo.TryGetValue(outfit.HenchName, out list)) { list = new List <SquadmateInfoSingle>(); appearanceInfo[outfit.HenchName] = list; } outfit.ConditionalIndex = currentConditional++; // This is always incremented, so it might appear out of order in game files depending on how mod order is processed, that should be okay though. outfit.AppearanceId = appearanceId++; // may need adjusted outfit.DLCName = dlc; list.Add(outfit); Log.Information($@"SQMMERGE: ConditionalIndex for {outfit.HenchName} appearanceid {outfit.AppearanceId}: {outfit.ConditionalIndex}"); } } } if (appearanceInfo.Any()) { var biopGlobal = MEPackageHandler.OpenMEPackage(loadedFiles[@"BioP_Global.pcc"]); var lsk = biopGlobal.Exports.FirstOrDefault(x => x.ClassName == @"LevelStreamingKismet"); var persistentLevel = biopGlobal.FindExport(@"TheWorld.PersistentLevel"); // Clone LevelStreamingKismets foreach (var sqm in appearanceInfo.Values) { foreach (var outfit in sqm) { var fName = outfit.HenchPackage; var newLSK = EntryCloner.CloneEntry(lsk); newLSK.WriteProperty(new NameProperty(fName, @"PackageName")); if (target.Game.IsGame3()) { // Game 3 has _Explore files too fName += @"_Explore"; newLSK = EntryCloner.CloneEntry(lsk); newLSK.WriteProperty(new NameProperty(fName, @"PackageName")); } } } // Update BioWorldInfo // Doesn't have consistent number so we can't find it by instanced full path var bioWorldInfo = biopGlobal.Exports.FirstOrDefault(x => x.ClassName == @"BioWorldInfo"); var props = bioWorldInfo.GetProperties(); // Update Plot Streaming var plotStreaming = props.GetProp <ArrayProperty <StructProperty> >(@"PlotStreaming"); foreach (var sqm in appearanceInfo.Values) { foreach (var outfit in sqm) { // find item to add to buildPlotElementObject(plotStreaming, outfit, target.Game, false); if (target.Game.IsGame3()) { buildPlotElementObject(plotStreaming, outfit, target.Game, true); } } } // Update StreamingLevels var streamingLevels = props.GetProp <ArrayProperty <ObjectProperty> >(@"StreamingLevels"); streamingLevels.ReplaceAll(biopGlobal.Exports.Where(x => x.ClassName == @"LevelStreamingKismet").Select(x => new ObjectProperty(x))); bioWorldInfo.WriteProperties(props); M3MergeDLC.GenerateMergeDLC(target, Guid.NewGuid()); // Save BioP_Global into DLC var cookedDir = Path.Combine(M3Directories.GetDLCPath(target), M3MergeDLC.MERGE_DLC_FOLDERNAME, target.Game.CookedDirName()); var outP = Path.Combine(cookedDir, @"BioP_Global.pcc"); biopGlobal.Save(outP); // Generate conditionals file if (target.Game.IsGame3()) { CNDFile cnd = new CNDFile(); cnd.ConditionalEntries = new List <CNDFile.ConditionalEntry>(); foreach (var sqm in appearanceInfo.Values) { foreach (var outfit in sqm) { var scText = $@"(plot.ints[{GetSquadmateOutfitInt(outfit.HenchName, target.Game)}] == i{outfit.MemberAppearanceValue})"; var compiled = ME3ConditionalsCompiler.Compile(scText); cnd.ConditionalEntries.Add(new CNDFile.ConditionalEntry() { Data = compiled, ID = outfit.ConditionalIndex }); } } cnd.ToFile(Path.Combine(cookedDir, $@"Conditionals{M3MergeDLC.MERGE_DLC_FOLDERNAME}.cnd")); } else if (target.Game.IsGame2()) { var startupF = Path.Combine(cookedDir, $@"Startup_{M3MergeDLC.MERGE_DLC_FOLDERNAME}.pcc"); var startup = MEPackageHandler.OpenMEPackageFromStream(Utilities.GetResourceStream( $@"MassEffectModManagerCore.modmanager.mergedlc.{target.Game}.Startup_{M3MergeDLC.MERGE_DLC_FOLDERNAME}.pcc")); var conditionalClass = startup.FindExport($@"PlotManager{M3MergeDLC.MERGE_DLC_FOLDERNAME}.BioAutoConditionals"); // Add Conditional Functions FileLib fl = new FileLib(startup); bool initialized = fl.Initialize(new RelativePackageCache() { RootPath = M3Directories.GetBioGamePath(target) }); if (!initialized) { throw new Exception( $@"FileLib for script update could not initialize, cannot install conditionals"); } var funcToClone = startup.FindExport($@"PlotManager{M3MergeDLC.MERGE_DLC_FOLDERNAME}.BioAutoConditionals.TemplateFunction"); foreach (var sqm in appearanceInfo.Values) { foreach (var outfit in sqm) { var func = EntryCloner.CloneEntry(funcToClone); func.ObjectName = $@"F{outfit.ConditionalIndex}"; func.indexValue = 0; var scText = new StreamReader(Utilities.GetResourceStream( $@"MassEffectModManagerCore.modmanager.squadmates.{target.Game}.HasOutfitOnConditional.txt")) .ReadToEnd(); scText = scText.Replace(@"%CONDITIONALNUM%", outfit.ConditionalIndex.ToString()); scText = scText.Replace(@"%SQUADMATEOUTFITPLOTINT%", outfit.AppearanceId.ToString()); scText = scText.Replace(@"%OUTFITINDEX%", outfit.MemberAppearanceValue.ToString()); (_, MessageLog log) = UnrealScriptCompiler.CompileFunction(func, scText, fl); if (log.AllErrors.Any()) { Log.Error($@"Error compiling function {func.InstancedFullPath}:"); foreach (var l in log.AllErrors) { Log.Error(l.Message); } throw new Exception(M3L.GetString(M3L.string_interp_errorCompilingConditionalFunction, func, string.Join('\n', log.AllErrors.Select(x => x.Message)))); } } } // Relink the conditionals chain UClass uc = ObjectBinary.From <UClass>(conditionalClass); uc.UpdateLocalFunctions(); uc.UpdateChildrenChain(); conditionalClass.WriteBinary(uc); startup.Save(startupF); } // Add startup package, member appearances if (target.Game.IsGame2()) { var bioEngine = Path.Combine(cookedDir, @"BIOEngine.ini"); var ini = DuplicatingIni.LoadIni(bioEngine); var startupSection = ini.GetOrAddSection(@"Engine.StartupPackages"); startupSection.Entries.Add(new DuplicatingIni.IniEntry(@"+DLCStartupPackage", $@"Startup_{M3MergeDLC.MERGE_DLC_FOLDERNAME}")); startupSection.Entries.Add(new DuplicatingIni.IniEntry(@"+Package", $@"PlotManager{M3MergeDLC.MERGE_DLC_FOLDERNAME}")); ini.WriteToFile(bioEngine); } else if (target.Game.IsGame3()) { var mergeCoalFile = Path.Combine(M3Directories.GetDLCPath(target), M3MergeDLC.MERGE_DLC_FOLDERNAME, target.Game.CookedDirName(), $@"Default_{M3MergeDLC.MERGE_DLC_FOLDERNAME}.bin"); var mergeCoal = CoalescedConverter.DecompileGame3ToMemory(new MemoryStream(File.ReadAllBytes(mergeCoalFile))); // Member appearances var bioUiDoc = XDocument.Parse(mergeCoal[@"BIOUI.xml"]); foreach (var sqm in appearanceInfo.Values) { foreach (var outfit in sqm) { var entry = new Game3CoalescedValueEntry() { Section = @"sfxgame.sfxguidata_teamselect", Name = @"selectappearances", Type = 3, Value = StringStructParser.BuildCommaSeparatedSplitValueList(outfit.ToPropertyDictionary(), @"AvailableImage", @"HighlightImage", @"DeadImage", @"SilhouetteImage") }; Game3CoalescedHelper.AddArrayEntry(bioUiDoc, entry); } } mergeCoal[@"BIOUI.xml"] = bioUiDoc.ToString(); // Dynamic load mapping var bioEngineDoc = XDocument.Parse(mergeCoal[@"BIOEngine.xml"]); foreach (var sqm in appearanceInfo.Values) { foreach (var outfit in sqm) { // // * <Section name="sfxgame.sfxengine"> // <Property name="dynamicloadmapping"> // <Value type="3">(ObjectName="BIOG_GesturesConfigDLC.RuntimeData",SeekFreePackageName="GesturesConfigDLC")</Value> var entry = new Game3CoalescedValueEntry() { Section = @"sfxgame.sfxengine", Name = @"dynamicloadmapping", Type = 3 }; entry.Values.Add($"(ObjectName=\"{outfit.AvailableImage}\",SeekFreePackageName=\"SFXHenchImages_{outfit.DLCName}\")"); // do not localize entry.Values.Add($"(ObjectName=\"{outfit.HighlightImage}\",SeekFreePackageName=\"SFXHenchImages_{outfit.DLCName}\")"); // do not localize Game3CoalescedHelper.AddArrayEntry(bioEngineDoc, entry); } } mergeCoal[@"BIOEngine.xml"] = bioEngineDoc.ToString(); CoalescedConverter.CompileFromMemory(mergeCoal).WriteToFile(mergeCoalFile); } } }
public override void LoadCurrentValue(DuplicatingIni configIni) { base.LoadCurrentValue(configIni); CurrentValue = CurrentValue.TrimEnd('f'); CurrentValue = CurrentValue.Contains(".") ? CurrentValue.TrimEnd('0').TrimEnd('.') : CurrentValue; }
public ME1IniModder() { Analytics.TrackEvent(@"Launched MEIM"); DataContext = this; InitializeComponent(); string configFileFolder = Environment.GetFolderPath(Environment.SpecialFolder.Personal) + @"\BioWare\Mass Effect\Config"; if (Directory.Exists(configFileFolder)) { Dictionary <string, ObservableCollectionExtended <IniPropertyMaster> > loadingMap = new Dictionary <string, ObservableCollectionExtended <IniPropertyMaster> >(); loadingMap[@"BioEngine.xml"] = BioEngineEntries; loadingMap[@"BioGame.xml"] = BioGameEntries; loadingMap[@"BioParty.xml"] = BioPartyEntries; foreach (var kp in loadingMap) { XElement rootElement = XElement.Parse(GetPropertyMap(kp.Key)); var linqlist = (from e in rootElement.Elements(@"Section") select new IniSection { SectionName = (string)e.Attribute(@"name"), BoolProperties = e.Elements(@"boolproperty").Select(f => new IniPropertyBool { CanAutoReset = f.Attribute(@"canautoreset") != null ? (bool)f.Attribute(@"canautoreset") : true, PropertyName = (string)f.Attribute(@"propertyname"), FriendlyPropertyName = (string)f.Attribute(@"friendlyname"), Notes = (string)f.Attribute(@"notes"), OriginalValue = f.Value }).ToList(), IntProperties = e.Elements(@"intproperty").Select(f => new IniPropertyInt { CanAutoReset = f.Attribute(@"canautoreset") != null ? (bool)f.Attribute(@"canautoreset") : true, PropertyName = (string)f.Attribute(@"propertyname"), FriendlyPropertyName = (string)f.Attribute(@"friendlyname"), Notes = (string)f.Attribute(@"notes"), OriginalValue = f.Value }).ToList(), FloatProperties = e.Elements(@"floatproperty").Select(f => new IniPropertyFloat { CanAutoReset = f.Attribute(@"canautoreset") != null ? (bool)f.Attribute(@"canautoreset") : true, PropertyName = (string)f.Attribute(@"propertyname"), FriendlyPropertyName = (string)f.Attribute(@"friendlyname"), Notes = (string)f.Attribute(@"notes"), OriginalValue = f.Value }).ToList(), EnumProperties = e.Elements(@"enumproperty").Select(f => new IniPropertyEnum { CanAutoReset = f.Attribute(@"canautoreset") != null ? (bool)f.Attribute(@"canautoreset") : true, PropertyName = (string)f.Attribute(@"propertyname"), FriendlyPropertyName = (string)f.Attribute(@"friendlyname"), Notes = (string)f.Attribute(@"notes"), Choices = f.Elements(@"enumvalue").Select(g => new IniPropertyEnumValue { FriendlyName = (string)g.Attribute(@"friendlyname"), Notes = (string)g.Attribute(@"notes"), IniValue = g.Value }).ToList() }).ToList(), NameProperties = e.Elements(@"nameproperty").Select(f => new IniPropertyName { CanAutoReset = f.Attribute(@"canautoreset") != null ? (bool)f.Attribute(@"canautoreset") : true, PropertyName = (string)f.Attribute(@"propertyname"), FriendlyPropertyName = (string)f.Attribute(@"friendlyname"), Notes = (string)f.Attribute(@"notes"), OriginalValue = f.Value }).ToList(), }).ToList(); List <IniPropertyMaster> items = new List <IniPropertyMaster>(); foreach (IniSection sec in linqlist) { sec.PropogateOwnership(); items.AddRange(sec.GetAllProperties()); } string inifilepath = Path.Combine(configFileFolder, Path.GetFileNameWithoutExtension(kp.Key) + @".ini"); if (File.Exists(inifilepath)) { DuplicatingIni configIni = DuplicatingIni.LoadIni(inifilepath); foreach (IniPropertyMaster prop in items) { prop.LoadCurrentValue(configIni); } } else { Xceed.Wpf.Toolkit.MessageBox.Show(this, M3L.GetString(M3L.string_dialog_missingConfigFileForMEIM, Path.GetFileNameWithoutExtension(kp.Key), inifilepath)); Environment.Exit(1); } kp.Value.ReplaceAll(items); CollectionView view = (CollectionView)CollectionViewSource.GetDefaultView(kp.Value); PropertyGroupDescription groupDescription = new PropertyGroupDescription(@"SectionFriendlyName"); view.GroupDescriptions.Add(groupDescription); } } else { doNotOpen = true; Xceed.Wpf.Toolkit.MessageBox.Show(null, M3L.GetString(M3L.string_interp_dialogConfigDirectoryMissing, configFileFolder), M3L.GetString(M3L.string_cannotRunMassEffectIniModder), MessageBoxButton.OK, MessageBoxImage.Error); } }
public static TelemetryPackage GetTelemetryPackageForDLC(MEGame game, string dlcDirectory, string dlcFoldername, string destinationDLCName, string modName, string modAuthor, string modSite, Mod telemetryMod) { try { TelemetryPackage tp = new TelemetryPackage(); var sourceDir = Path.Combine(dlcDirectory, dlcFoldername); tp.DLCFolderName = destinationDLCName; //this most times will be the same as dlcFoldername, but in case of alternates, it might not be if (telemetryMod != null && telemetryMod.HumanReadableCustomDLCNames.TryGetValue(dlcFoldername, out var modNameIni)) { tp.ModName = modNameIni; } else { tp.ModName = modName; } tp.ModAuthor = modAuthor; tp.ModSite = modSite; tp.Game = game; switch (game) { case MEGame.ME1: { var parsedIni = DuplicatingIni.LoadIni(Path.Combine(sourceDir, @"AutoLoad.ini")); tp.MountPriority = int.Parse(parsedIni[@"ME1DLCMOUNT"][@"ModMount"]?.Value); tp.ModMountTLK1 = int.Parse(parsedIni[@"GUI"][@"NameStrRef"]?.Value); tp.MountFlagHR = M3L.GetString(M3L.string_me1MountFlagsNotSupportedInM3); //No mount flag right now. } break; case MEGame.ME2: { var mountFile = Path.Combine(sourceDir, @"CookedPC", @"mount.dlc"); MountFile mf = new MountFile(mountFile); tp.ModMountTLK1 = mf.TLKID; tp.MountPriority = mf.MountPriority; tp.MountFlag = (int)mf.MountFlag; tp.MountFlagHR = mf.MountFlag.ToString(); var ini = DuplicatingIni.LoadIni(Path.Combine(sourceDir, @"CookedPC", @"BIOEngine.ini")); tp.ModuleNumber = ini[@"Engine.DLCModules"][dlcFoldername]?.Value; } break; case MEGame.ME3: { var mountFile = Path.Combine(sourceDir, @"CookedPCConsole", @"mount.dlc"); MountFile mf = new MountFile(mountFile); tp.ModMountTLK1 = mf.TLKID; tp.MountPriority = mf.MountPriority; tp.MountFlag = (int)mf.MountFlag; tp.MountFlagHR = mf.MountFlag.ToString(); } break; } return(tp); } catch (Exception e) { Log.Error($@"Error building telemetry package for {dlcFoldername}: {e.Message}."); return(null); } }