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);
        }
Exemple #2
0
        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;
                }
            }
        }
Exemple #3
0
        /// <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));
        }
Exemple #4
0
        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;
            }
        }
Exemple #6
0
        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)));
 }
Exemple #8
0
        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));
                }
            }
        }
Exemple #9
0
        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;
     }
 }
Exemple #12
0
        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})"));
                        //}
                    }
                }
            }
        }
Exemple #14
0
        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);
                }
            }
        }
Exemple #15
0
 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);
            }
        }