コード例 #1
0
        public static bool RandomizeExport(ExportEntry export, RandomizationOption option)
        {
            if (!CanRandomize(export))
            {
                return(false);
            }
            var settings = export.GetProperty <StructProperty>("Settings");

            if (settings != null)
            {
                MERLog.Information($@"Randomizing PostProcessingVolume settings {export.UIndex}");
                // randomize the options
                RProperty.RandBool(settings.Properties, "bEnableDOF", ThreadSafeRandom.Next(3) == 0);
                RProperty.RandBool(settings.Properties, "bEnableFilmic", ThreadSafeRandom.Next(3) == 0);
                RProperty.RandBool(settings.Properties, "bEnableBloom", ThreadSafeRandom.Next(3) == 0);
                RProperty.RandFloat(settings.Properties, "Bloom_Scale", 0, 0.4f, ThreadSafeRandom.Next(5) == 0);
                RProperty.RandFloat(settings.Properties, "DOF_BlurKernelSize", 0, 20f, ThreadSafeRandom.Next(5) == 0);
                RProperty.RandFloat(settings.Properties, "DOF_MaxNearBlurAmount", 0, 0.2f, ThreadSafeRandom.Next(5) == 0);
                RProperty.RandFloat(settings.Properties, "DOF_MaxFarBlurAmount", 0.1f, 0.5f, ThreadSafeRandom.Next(5) == 0);
                RProperty.RandFloat(settings.Properties, "DOF_InnerFocusRadius", 0, 2000f, ThreadSafeRandom.Next(5) == 0);
                RProperty.RandFloat(settings.Properties, "DOF_FocusDistance", 0, 400f, ThreadSafeRandom.Next(5) == 0);
                RProperty.RandFloat(settings.Properties, "Scene_Desaturation", 0, 0.5f, ThreadSafeRandom.Next(5) == 0);
                RProperty.RandFloat(settings.Properties, "Scene_InterpolationDuration", 0, 2f, ThreadSafeRandom.Next(5) == 0);
                RProperty.RandVector(settings.Properties, "Scene_Highlights", 0, 2, ThreadSafeRandom.Next(8) == 0);
                RProperty.RandVector(settings.Properties, "Scene_Midtones", 0, 6f, ThreadSafeRandom.Next(5) == 0);
                RProperty.RandVector(settings.Properties, "Scene_Shadows", 0, .4f, ThreadSafeRandom.Next(8) == 0);
                export.WriteProperty(settings);
                return(true);
            }
            return(false);
        }
コード例 #2
0
        private static void MakeKensonCool()
        {
            string[] files = new[]
            {
                "BioD_ArvLvl1.pcc",
                "BioD_ArvLvl4_300Entrance.pcc",
            };
            foreach (var f in files)
            {
                var kensonFile = MERFileSystem.GetPackageFile(f, false);
                if (kensonFile != null && File.Exists(kensonFile))
                {
                    var kensonP = MEPackageHandler.OpenMEPackage(kensonFile);
                    var ifp     = kensonP.FindExport("SFXGameContentKenson.Default__SFXPawn_Kenson_01.BioPawnSkeletalMeshComponent");
                    ifp.RemoveProperty("Materials");
                    ifp.RemoveProperty("SkeletalMesh");

                    // Remove materials used in base as they're wrong
                    kensonP.FindExport("SFXGameContentKenson.Default__SFXPawn_Kenson.BioPawnSkeletalMeshComponent").RemoveProperty("Materials");

                    MERFileSystem.SavePackage(kensonP);
                }
                else
                {
                    MERLog.Information($"Kenson file not found: {f}, skipping...");
                }
            }
        }
コード例 #3
0
        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);
        }
コード例 #4
0
        public static bool PerformRandomization(ExportEntry export, RandomizationOption option)
        {
            if (!CanRandomize(export))
            {
                return(false);
            }
            MERLog.Information($"{export.FileRef.FilePath}\t{export.FullPath}");
            var props = export.GetProperties();

            if (export.ClassName == "BioSunFlareComponent" || export.ClassName == "BioSunFlareStreakComponent")
            {
                var tint = props.GetProp <StructProperty>("FlareTint");
                if (tint != null)
                {
                    RStructs.RandomizeTint(tint, false);
                }
                RProperty.RandFloat(props, "Intensity", 0.0001f, 100f, false);
                RProperty.RandFloat(props, "BrightPercent", 0.0001f, 0.1f, false);
                RProperty.RandFloat(props, "Scale", 0.05f, 3f, false);
            }
            else if (export.ClassName == "BioSunActor")
            {
                var tint = props.GetProp <StructProperty>("SunTint");
                if (tint != null)
                {
                    RStructs.RandomizeTint(tint, false);
                }
            }

            export.WriteProperties(props);
            return(true);
        }
コード例 #5
0
        public static void LoadGuns()
        {
            if (AllAvailableWeapons == null)
            {
                string fileContents = MERUtilities.GetEmbeddedStaticFilesTextFile("weaponloadoutrules.json");
                LoadoutSupportsVisibleMapping = JsonConvert.DeserializeObject <ConcurrentDictionary <string, bool> >(fileContents);

                fileContents = MERUtilities.GetEmbeddedStaticFilesTextFile("weaponlistme2.json");
                var allGuns = JsonConvert.DeserializeObject <List <GunInfo> >(fileContents).ToList();
                AllAvailableWeapons     = new List <GunInfo>();
                VisibleAvailableWeapons = new List <GunInfo>();
                foreach (var g in allGuns)
                {
                    var gf = MERFileSystem.GetPackageFile(g.PackageFileName, false);
                    if (g.IsCorrectedPackage || (gf != null && File.Exists(gf)))
                    {
                        MERLog.Information($@"Adding {g.GunName} to weapon selection pools");
                        AllAvailableWeapons.Add(g);
                        if (g.HasGunMesh)
                        {
                            VisibleAvailableWeapons.Add(g);
                        }
                    }

                    if (!g.IsCorrectedPackage && gf == null)
                    {
                        MERLog.Information($@"{g.GunName} package file not found ({g.PackageFileName}), weapon not added to weapon pools");
                    }
                }
                Debug.WriteLine($"Number of available weapons for randomization: {AllAvailableWeapons.Count}");
                Debug.WriteLine($"Number of visible weapons for randomization: {VisibleAvailableWeapons.Count}");
            }
        }
コード例 #6
0
        public static void LoadPowers()
        {
            if (Powers == null)
            {
                string fileContents = MERUtilities.GetEmbeddedStaticFilesTextFile("powerlistme2.json");
                Powers = new List <PowerInfo>();
                var powermanifest = JsonConvert.DeserializeObject <List <PowerInfo> >(fileContents);
                foreach (var powerInfo in powermanifest)
                {
                    var powerFilePath = MERFileSystem.GetPackageFile(powerInfo.PackageFileName, false);
                    if (powerInfo.IsCorrectedPackage || (powerFilePath != null && File.Exists(powerFilePath)))
                    {
                        if (powerInfo.FileDependency != null && MERFileSystem.GetPackageFile(powerInfo.FileDependency, false) == null)
                        {
                            MERLog.Information($@"Dependency file {powerInfo.FileDependency} not found, not adding {powerInfo.PowerName} to power selection pool");
                            continue; // Dependency not met
                        }
                        MERLog.Information($@"Adding {powerInfo.PowerName} to power selection pool");
                        Powers.Add(powerInfo);
                    }

                    if (!powerInfo.IsCorrectedPackage && powerFilePath == null)
                    {
                        MERLog.Information($@"{powerInfo.PowerName} package file not found ({powerInfo.PackageFileName}), weapon not added to weapon pools");
                    }
                }
            }
        }
コード例 #7
0
 private static string ExtractInternalFile(string internalResourceName, bool fullname, string destination = null, bool overwrite = false, Stream destStream = null)
 {
     MERLog.Information("Extracting file: " + internalResourceName);
     if (destStream != null || (destination != null && (!File.Exists(destination) || overwrite)))
     {
         // Todo: might need adjusted for ME3
         using Stream stream = MERUtilities.GetResourceStream(fullname ? internalResourceName : "ME2Randomizer.staticfiles." + internalResourceName);
         bool close = destStream != null;
         if (destStream == null)
         {
             destStream = new FileStream(destination, FileMode.Create, FileAccess.Write);
         }
         stream.CopyTo(destStream);
         if (close)
         {
             stream.Close();
         }
     }
     else if (destination != null && !overwrite)
     {
         MERLog.Warning("File already exists");
     }
     else
     {
         MERLog.Warning("Invalid extraction parameters!");
     }
     return(destination);
 }
コード例 #8
0
        private static void handleM3Passthrough()
        {
            if (PassthroughME1Path != null)
            {
                handlePassthrough(MEGame.ME1, PassthroughME1Path);
            }
            if (PassthroughME2Path != null)
            {
                handlePassthrough(MEGame.ME2, PassthroughME2Path);
            }
            if (PassthroughME3Path != null)
            {
                handlePassthrough(MEGame.ME3, PassthroughME3Path);
            }

            PassthroughME1Path = PassthroughME2Path = PassthroughME3Path = null;

            void handlePassthrough(MEGame game, string path)
            {
                if (path != null && Directory.Exists(path))
                {
                    GameTarget gt = new GameTarget(game, path, true, false);
                    var        passThroughValidationResult = gt.ValidateTarget(false);
                    if (passThroughValidationResult != null)
                    {
                        MERLog.Error($@"{game} path passthrough failed game target validation: {passThroughValidationResult}");
                    }
                    else
                    {
                        MERLog.Information($@"Valid passthrough for game {game}. Assigning path.");
                        Locations.SetTarget(gt, false);
                    }
                }
            }
        }
コード例 #9
0
        private static void RandomizeVIMaterial(ExportEntry exp)
        {
            var data = exp.Data;

            //RandomizeRGBA(data, 0x70C, false);
            RandomizeRGBA(data, 0x72C, false);
            MERLog.Information($@"Randomized VI material {exp.InstancedFullPath} in {exp.FileRef.FilePath}");
            exp.Data = data;
        }
コード例 #10
0
        private static void PerformRAMCheck(Action <string, string> messageCallback)
        {
            var ramAmountsBytes = Utilities.GetInstalledRamAmount();
            var installedRamGB  = ramAmountsBytes * 1.0d / (2 ^ 30);

            if (ramAmountsBytes > 0 && installedRamGB < 10)
            {
                messageCallback?.Invoke("System memory is less than 10 GB", "Randomization can use significant amounts of memory (up to 6GB) in multithreaded mode. It is recommended that you disable multithreaded randomization if your system has less than 10GB of memory. This will increase randomization time but will reduce the memory required to randomize.");
            }
#if WINDOWS
            //Check pagefile
            try
            {
                //Current
                var pageFileLocations = new List <string>();
                using (var query = new ManagementObjectSearcher("SELECT Caption,AllocatedBaseSize FROM Win32_PageFileUsage"))
                {
                    foreach (ManagementBaseObject obj in query.Get())
                    {
                        string pagefileName = (string)obj.GetPropertyValue("Caption");
                        MERLog.Information("Detected pagefile: " + pagefileName);
                        pageFileLocations.Add(pagefileName.ToLower());
                    }
                }

                //Max
                using (var query = new ManagementObjectSearcher("SELECT Name,MaximumSize FROM Win32_PageFileSetting"))
                {
                    foreach (ManagementBaseObject obj in query.Get())
                    {
                        string pagefileName = (string)obj.GetPropertyValue("Name");
                        uint   max          = (uint)obj.GetPropertyValue("MaximumSize");
                        if (max > 0)
                        {
                            // Not system managed
                            pageFileLocations.RemoveAll(x => Path.GetFullPath(x).Equals(Path.GetFullPath(pagefileName)));
                            MERLog.Error($"Pagefile has been modified by the end user. The maximum page file size on {pagefileName} is {max} MB. Does this user **actually** know what capping a pagefile does?");
                        }
                    }
                }

                if (pageFileLocations.Any())
                {
                    MERLog.Information("We have a usable system managed page file - OK");
                }
                else
                {
                    MERLog.Error("We have no uncapped or available pagefiles to use! Very high chance application will run out of memory");
                    messageCallback?.Invoke($"Pagefile is off or size has been capped", $"The system pagefile (virtual memory) settings are not currently managed by Windows, or the pagefile is off. Mass Effect 2 Randomizer uses significant amounts of memory and will crash if the system runs low on memory. You should always leave page files managed by Windows.");
                }
            }
            catch (Exception e)
            {
                MERLog.Exception(e, "Unable to check pagefile settings:");
            }
#endif
        }
コード例 #11
0
        /// <summary>
        /// Hack to force power lists to load with only a single check
        /// </summary>
        /// <param name="option"></param>
        /// <returns></returns>
        public static bool Init(RandomizationOption option)
        {
            MERLog.Information(@"Preloading weapon data");
            LoadGuns();
            WeaponAnimsPackage        = MERFileSystem.GetStartupPackage();
            WeaponAnimationsArrayProp = WeaponAnimsPackage.FindExport("WeaponAnimData").GetProperty <ArrayProperty <StructProperty> >("WeaponAnimSpecs");

            MERLog.Information(@"Installing weapon animations startup package");
            MERFileSystem.InstallStartupPackage(); // Contains weapon animations
            return(true);
        }
コード例 #12
0
        public static void GetAntivirusInfo()
        {
            ManagementObjectSearcher   wmiData = new ManagementObjectSearcher(@"root\SecurityCenter2", "SELECT * FROM AntivirusProduct");
            ManagementObjectCollection data    = wmiData.Get();

            foreach (ManagementObject virusChecker in data)
            {
                var  virusCheckerName = virusChecker["displayName"];
                var  productState     = virusChecker["productState"];
                uint productVal       = (uint)productState;
                var  bytes            = BitConverter.GetBytes(productVal);
                MERLog.Information("Antivirus info: " + virusCheckerName + " with state " + bytes[1].ToString("X2") + " " + bytes[2].ToString("X2") + " " + bytes[3].ToString("X2"));
            }
        }
コード例 #13
0
        private static void SetVeetorFootage()
        {
            var moviedata   = RTextureMovie.GetTextureMovieAssetBinary("Veetor.size_mer.bik");
            var veetorFiles = MERFileSystem.LoadedFiles.Keys.Where(x => x.StartsWith("BioD_ProFre_501Veetor")).ToList();

            foreach (var v in veetorFiles)
            {
                MERLog.Information($@"Setting veetor footage in {v}");
                var mpackage     = MERFileSystem.GetPackageFile(v);
                var package      = MEPackageHandler.OpenMEPackage(mpackage);
                var veetorExport = package.FindExport("BioVFX_Env_Hologram.ProFre_501_VeetorFootage");
                if (veetorExport != null)
                {
                    RTextureMovie.RandomizeExportDirect(veetorExport, null, moviedata);
                }
                MERFileSystem.SavePackage(package);
            }
        }
コード例 #14
0
        public static bool RandomizePawnSize(ExportEntry export, RandomizationOption option)
        {
            if (!CanRandomize(export))
            {
                return(false);
            }
            MERLog.Information($"[{Path.GetFileNameWithoutExtension(export.FileRef.FilePath)}] Randomizing pawn size for " + export.UIndex + ": " + export.InstancedFullPath);
            var       existingSize = export.GetProperty <StructProperty>("DrawScale3D");
            CFVector3 d3d          = existingSize == null ? new CFVector3()
            {
                X = 1, Y = 1, Z = 1
            } : CFVector3.FromStructProperty(existingSize, "X", "Y", "Z");

            d3d.X *= ThreadSafeRandom.NextFloat(1 - option.SliderValue, 1 + option.SliderValue);
            d3d.Y *= ThreadSafeRandom.NextFloat(1 - option.SliderValue, 1 + option.SliderValue);
            d3d.Z *= ThreadSafeRandom.NextFloat(1 - option.SliderValue, 1 + option.SliderValue);
            export.WriteProperty(d3d.ToStructProperty("X", "Y", "Z", "DrawScale3D", true));
            return(true);
        }
コード例 #15
0
        private static void PerformUACCheck()
        {
            bool isAdmin = Utilities.IsAdministrator();

            //Check if UAC is off
            bool   uacIsOn     = true;
            string softwareKey = @"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System";

            int?value = (int?)Registry.GetValue(softwareKey, "EnableLUA", null);

            if (value != null)
            {
                uacIsOn = value > 0;
                MERLog.Information("UAC is on: " + uacIsOn);
            }
            if (isAdmin && uacIsOn)
            {
                MERLog.Warning("This session is running as administrator.");
                //await this.ShowMessageAsync($"{Utilities.GetAppPrefixedName()} Installer should be run as standard user", $"Running {Utilities.GetAppPrefixedName()} Installer as an administrator will disable drag and drop functionality and may cause issues due to the program running in a different user context. You should restart the application without running it as an administrator unless directed by the developers.");
            }
        }
コード例 #16
0
        public static bool RandomizeExport(ExportEntry exp, RandomizationOption option)
        {
            if (!CanRandomize(exp))
            {
                return(false);
            }
            MERLog.Information($"Randomizing illusive eye color in {exp.FileRef.FilePath}");
            var props = exp.GetProperties();

            //eye color
            var emisVector = props.GetProp <ArrayProperty <StructProperty> >("VectorParameterValues").First(x => x.GetProp <NameProperty>("ParameterName").Value.Name == "Emis_Color").GetProp <StructProperty>("ParameterValue");

            //tint is float based
            RStructs.RandomizeTint(emisVector, false);

            var emisScalar = props.GetProp <ArrayProperty <StructProperty> >("ScalarParameterValues").First(x => x.GetProp <NameProperty>("ParameterName").Value.Name == "Emis_Scalar").GetProp <FloatProperty>("ParameterValue");

            emisScalar.Value = 3; //very vibrant
            exp.WriteProperties(props);
            return(true);
        }
コード例 #17
0
        public bool RandomizeExport(ExportEntry export, RandomizationOption option)
        {
            if (!CanRandomize(export))
            {
                return(false);
            }
            MERLog.Information("Randomizing BioWaypointSet " + export.UIndex + " in " + Path.GetFileName(export.FileRef.FilePath));
            var waypointReferences = export.GetProperty <ArrayProperty <StructProperty> >("WaypointReferences");

            if (waypointReferences != null)
            {
                //Get list of valid targets
                var pcc       = export.FileRef;
                var waypoints = pcc.Exports.Where(x => x.ClassName == "BioPathPoint" || x.ClassName == "PathNode").ToList();
                waypoints.Shuffle();

                foreach (var waypoint in waypointReferences)
                {
                    var nav = waypoint.GetProp <ObjectProperty>("Nav");
                    if (nav != null && nav.Value > 0)
                    {
                        ExportEntry currentPoint = export.FileRef.GetUExport(nav.Value);
                        if (currentPoint.ClassName == "BioPathPoint" || currentPoint.ClassName == "PathNode")
                        {
                            nav.Value = waypoints[0].UIndex;
                            waypoints.RemoveAt(0);
                        }
                        else
                        {
                            Debug.WriteLine("SKIPPING NODE TYPE " + currentPoint.ClassName);
                        }
                    }
                }
            }

            export.WriteProperty(waypointReferences);
            return(true);
        }
コード例 #18
0
 public static int runProcessAsAdmin(string exe, string args, bool standAlone = false)
 {
     MERLog.Information("Running process as admin: " + exe + " " + args);
     using (Process p = new Process())
     {
         p.StartInfo.CreateNoWindow  = true;
         p.StartInfo.FileName        = exe;
         p.StartInfo.UseShellExecute = true;
         p.StartInfo.Arguments       = args;
         p.StartInfo.Verb            = "runas";
         try
         {
             p.Start();
             if (!standAlone)
             {
                 p.WaitForExit(60000);
                 try
                 {
                     return(p.ExitCode);
                 }
                 catch (Exception e)
                 {
                     MERLog.Error("Error getting return code from admin process. It may have timed out.\n" + FlattenException(e));
                     return(-1);
                 }
             }
             else
             {
                 return(0);
             }
         }
         catch (System.ComponentModel.Win32Exception e)
         {
             MERLog.Error("Error running elevated process: " + e.Message);
             return(WIN32_EXCEPTION_ELEVATED_CODE);
         }
     }
 }
コード例 #19
0
        /// <summary>
        /// Swap the vowels around. Optional hard mode allows swapping 2 consonants to make it extra difficult to read
        /// </summary>
        /// <param name="Tlks"></param>
        public static bool RandomizeVowels(RandomizationOption option)
        {
            // Map of what letter maps to what other letter
            MERLog.Information("Randomizing vowels in words");
            var hardMode = option.HasSubOptionSelected(RTexts.SUBOPTIONKEY_VOWELS_HARDMODE);


            var existingTLK = TLKHandler.GetBuildingTLK();
            var skipIDs     = existingTLK.StringRefs.Select(x => x.StringID).ToList();
            var MERTLKs     = TLKHandler.GetMERTLKs();
            Dictionary <char, char> vowels      = null;
            List <char>             vowelValues = null;

            bool retryMapping = true;

            while (retryMapping)
            {
                bool failed = false;
                vowels      = GetVowelMap();
                vowelValues = vowels.Values.ToList();

                int numAttemptsRemaining = 10;

                foreach (var sourceVowel in vowels.Keys)
                {
                    var value = vowelValues.RandomElement();
                    while (hardMode && value == sourceVowel && numAttemptsRemaining > 0)
                    {
                        value = vowelValues.RandomElement();
                        numAttemptsRemaining--;
                    }

                    if (numAttemptsRemaining == 0 && hardMode && value == sourceVowel)
                    {
                        // This attempt has failed
                        MERLog.Warning(@"Hard mode vowel randomization failed, retrying");
                        failed = true;
                        break;
                    }

                    vowelValues.Remove(value); // Do not allow reassignment of same vowel
                    Debug.WriteLine($"Vowel Randomizer: {sourceVowel} -> {value}");
                    vowels[sourceVowel] = value;
                }

                if (!failed)
                {
                    retryMapping = false;
                }
            }

            var consonants = GetConsonantMap();

            if (hardMode)
            {
                // Swap some consontants around
                var numConsonantsToRandomize = 2;
                var consonantValues          = consonants.Values.ToList();
                while (numConsonantsToRandomize > 0)
                {
                    var sourceValue = consonantValues.RandomElement();
                    var value       = consonantValues.RandomElement();
                    while (sourceValue == value)
                    {
                        value = consonantValues.RandomElement();
                    }
                    consonantValues.Remove(value);       // Do not allow reassignment of same vowel
                    consonantValues.Remove(sourceValue); // Do not allow reassignment of same vowel

                    Debug.WriteLine($"Vowel Randomizer Hard Mode: {sourceValue} -> {value}");

                    consonants[sourceValue] = value;
                    consonants[value]       = sourceValue;
                    numConsonantsToRandomize--;
                }
            }

            // Build full translation map (uppercase)
            var translationMapUC = new[] { vowels, consonants }.SelectMany(dict => dict)
            .ToDictionary(pair => pair.Key, pair => pair.Value);

            // Add lowercase translation
            var lowerCaseMap = translationMapUC.ToDictionary(x => char.ToLowerInvariant(x.Key), x => char.ToLowerInvariant(x.Value));

            // Build a full translation
            var translationMap = new[] { translationMapUC, lowerCaseMap }.SelectMany(dict => dict)
            .ToDictionary(pair => pair.Key, pair => pair.Value);

            var nonMERTLKs = TLKHandler.GetAllTLKs().Where(x => !MERTLKs.Contains(x)).ToList();

            // MER

            option.ProgressValue         = 0;
            option.ProgressMax           = nonMERTLKs.Sum(x => x.StringRefs.Count(y => y.StringID > 0 && !string.IsNullOrWhiteSpace(y.Data)));
            option.ProgressMax          += MERTLKs.Sum(x => x.StringRefs.Count(y => y.StringID > 0 && !string.IsNullOrWhiteSpace(y.Data)));
            option.ProgressIndeterminate = false;

            foreach (var merTLK in MERTLKs)
            {
                RandomizeVowelsInternal(merTLK, skipIDs, translationMap, true, option);
            }

            // Non MER
            Parallel.ForEach(nonMERTLKs, tf =>
            {
                RandomizeVowelsInternal(tf, skipIDs, translationMap, false, option);
            });
            return(true);
        }
コード例 #20
0
 /// <summary>
 /// Hack to force power lists to load with only a single check
 /// </summary>
 /// <param name="option"></param>
 /// <returns></returns>
 public static bool Init(RandomizationOption option)
 {
     MERLog.Information(@"Preloading power data");
     LoadPowers();
     return(true);
 }
コード例 #21
0
        private static bool ForcedRun(ExportEntry hairMeshExport)
        {
            if (hairMeshExport.GetProperty <ObjectProperty>("SkeletalMesh") is ObjectProperty obj && obj.Value != 0 && obj.ResolveToEntry(hairMeshExport.FileRef) is IEntry entry)
            {
                var isfemaleHair = entry.ObjectName.Name.StartsWith("HMF_HIR_");
                var newHair      = isfemaleHair ? HairListFemale.RandomElement() : HairListMale.RandomElement();
                if (newHair.ObjectName.Name == entry.ObjectName.Name)
                {
                    return(false); // We are not changing this
                }
                MERLog.Information($"{Path.GetFileName(hairMeshExport.FileRef.FilePath)} Changing hair mesh: {entry.ObjectName} -> {newHair.ObjectName}, object {hairMeshExport.FullPath}, class {entry.ClassName}");
                var newHairMdl = PackageTools.PortExportIntoPackage(hairMeshExport.FileRef, newHair);
                var mdlBin     = ObjectBinary.From <SkeletalMesh>(newHairMdl);
                obj.Value = newHairMdl.UIndex;
                hairMeshExport.WriteProperty(obj);

                // Update the materials
                var materials = hairMeshExport.GetProperty <ArrayProperty <ObjectProperty> >("Materials");
                if (materials != null && materials.Any())
                {
                    //if (materials.Count() != 1)
                    //    Debugger.Break();
                    var mat = materials[0].ResolveToEntry(hairMeshExport.FileRef) as ExportEntry;
                    if (mat != null)
                    {
                        mat.WriteProperty(new ObjectProperty(mdlBin.Materials[0], "Parent"));
                        var parentMat = mdlBin.Materials[0] > 0 ? hairMeshExport.FileRef.GetUExport(mdlBin.Materials[0]) : EntryImporter.ResolveImport(hairMeshExport.FileRef.GetImport(mdlBin.Materials[0]));
                        // Need to match child to parent params that start with HAIR
                        var parentMatTextureParms = parentMat.GetProperty <ArrayProperty <StructProperty> >("TextureParameterValues");
                        if (parentMatTextureParms != null)
                        {
                            var parentMatHairParms = parentMatTextureParms.Where(x => x.Properties.GetProp <NameProperty>("ParameterName").Value.Name.StartsWith("HAIR_")).ToList();

                            // Need to match child to parent params that start with HAIR
                            var matTextureParms = mat.GetProperty <ArrayProperty <StructProperty> >("TextureParameterValues");
                            if (matTextureParms != null)
                            {
                                var matHairParms = matTextureParms.Where(x => x.Properties.GetProp <NameProperty>("ParameterName").Value.Name.StartsWith("HAIR_")).ToList();

                                // Map them
                                foreach (var matHairParm in matHairParms)
                                {
                                    var locName        = matHairParm.Properties.GetProp <NameProperty>("ParameterName");
                                    var matchingParent = parentMatHairParms.FirstOrDefault(x => x.Properties.GetProp <NameProperty>("ParameterName").Value == locName.Value);

                                    // Assign it
                                    if (matchingParent != null)
                                    {
                                        matHairParm.Properties.AddOrReplaceProp(matchingParent.GetProp <ObjectProperty>("ParameterValue"));
                                    }
                                }
                                mat.WriteProperty(matTextureParms);
                            }
                        }
                        else
                        {
                        }
                    }

                    //foreach (var mat in materials)
                    //{

                    //    mdlBin.
                    //}
                }
                return(true);
            }
            return(false);
        }
コード例 #22
0
        internal static bool RandomizeExport(ExportEntry export, RandomizationOption option)
        {
            if (!CanRandomize(export))
            {
                return(false);
            }
#if DEBUG
            //if (!export.ObjectName.Name.Contains("HeavyWeaponMech"))
            //    return false;
#endif

            var powers = export.GetProperty <ArrayProperty <ObjectProperty> >("Powers");

            if (powers == null)
            {
                // This loadout has no powers!
                // Randomly give them some powers.
                if (ThreadSafeRandom.Next(1) == 0)
                {
                    // unlimited power
                    List <ObjectProperty> blankPows = new List <ObjectProperty>();
                    // Add two blanks. We'll strip blanks before writing it
                    blankPows.Add(new ObjectProperty(int.MinValue));
                    blankPows.Add(new ObjectProperty(int.MinValue));
                    powers = new ArrayProperty <ObjectProperty>(blankPows, "Powers");
                }
                else
                {
                    // Sorry mate no powers for you
                    return(false);
                }
            }

            var originalPowerUIndexes = powers.Where(x => x.Value > 0).Select(x => x.Value).ToList();

            foreach (var power in powers.ToList())
            {
                if (power.Value == 0)
                {
                    return(false);                  // Null entry in weapons list
                }
                IEntry existingPowerEntry = null;
                if (power.Value != int.MinValue)
                {
                    // Husk AI kinda depends on melee or they just kinda breath on you all creepy like
                    // We'll give them a chance to change it up though
                    existingPowerEntry = power.ResolveToEntry(export.FileRef);
                    if (existingPowerEntry.ObjectName.Name.Contains("Melee", StringComparison.InvariantCultureIgnoreCase) && ThreadSafeRandom.Next(2) == 0)
                    {
                        MERLog.Information($"Not changing melee power {existingPowerEntry.ObjectName.Name}");
                        continue; // Don't randomize power
                    }
                    if (PowersToNotSwap.Contains(existingPowerEntry.ObjectName.Name))
                    {
                        MERLog.Information($"Not changing power {existingPowerEntry.ObjectName.Name}");
                        continue; // Do not change this power
                    }
                }

                // DEBUG
                PowerInfo randomNewPower = Powers.RandomElement();
                //if (option.SliderValue < 0)
                //{
                //    randomNewPower = Powers.RandomElement();
                //}
                //else
                //{
                //    randomNewPower = Powers[(int)option.SliderValue];
                //}


                // Prevent krogan from getting a death power
                while (export.ObjectName.Name.Contains("Krogan", StringComparison.InvariantCultureIgnoreCase) && randomNewPower.Type == EPowerCapabilityType.Death)
                {
                    MERLog.Information(@"Re-roll no-death-power on krogan");
                    // Reroll. Krogan AI has something weird about it
                    randomNewPower = Powers.RandomElement();
                }

                // Prevent powerful enemies from getting super stat boosters
                while (randomNewPower.Type == EPowerCapabilityType.Buff && (
                           export.ObjectName.Name.Contains("Praetorian", StringComparison.InvariantCultureIgnoreCase) ||
                           export.ObjectName.Name.Contains("ShadowBroker", StringComparison.InvariantCultureIgnoreCase)))
                {
                    MERLog.Information(@"Re-roll no-buffs for powerful enemy");
                    randomNewPower = Powers.RandomElement();
                }

                #region YMIR MECH fixes
                if (export.ObjectName.Name.Contains("HeavyWeaponMech"))
                {
                    // Heavy weapon mech chooses named death powers so we cannot change these
                    // HeavyMechDeathExplosion is checked for existence. NormalExplosion for some reason isn't
                    if ((existingPowerEntry.ObjectName.Name == "SFXPower_HeavyMechNormalExplosion"))
                    {
                        MERLog.Information($@"YMIR mech power HeavyMechNormalExplosion cannot be randomized, skipping");
                        continue;
                    }

                    // Do not add buff powers to YMIR
                    while (randomNewPower.Type == EPowerCapabilityType.Buff)
                    {
                        MERLog.Information($@"Re-roll YMIR mech power to prevent potential enemy too difficult to kill softlock. Incompatible power: {randomNewPower.PowerName}");
                        randomNewPower = Powers.RandomElement();
                    }
                }
                #endregion

                // CHANGE THE POWER
                if (existingPowerEntry == null || randomNewPower.PowerName != existingPowerEntry.ObjectName)
                {
                    if (powers.Any(x => power.Value != int.MinValue && power.ResolveToEntry(export.FileRef).ObjectName == randomNewPower.PowerName))
                    {
                        continue; // Duplicate powers crash the game. It seems this code is not bulletproof here and needs changed a bit...
                    }
                    MERLog.Information($@"Changing power {export.ObjectName} {existingPowerEntry?.ObjectName ?? "(+New Power)"} => {randomNewPower.PowerName }");
                    // It's a different power.

                    // See if we need to port this in
                    var fullName = randomNewPower.PackageName + "." + randomNewPower.PowerName; // SFXGameContent_Powers.SFXPower_Hoops
                    var existingVersionOfPower = export.FileRef.FindEntry(fullName);

                    if (existingVersionOfPower != null)
                    {
                        // Power does not need ported in
                        power.Value = existingVersionOfPower.UIndex;
                    }
                    else
                    {
                        // Power needs ported in
                        power.Value = PortPowerIntoPackage(export.FileRef, randomNewPower, out _)?.UIndex ?? int.MinValue;
                    }

                    if (existingPowerEntry != null && existingPowerEntry.UIndex > 0 && PackageTools.IsPersistentPackage(export.FileRef.FilePath))
                    {
                        // Make sure we add the original power to the list of referenced memory objects
                        // so subfiles that depend on this power existing don't crash the game!
                        var world     = export.FileRef.FindExport("TheWorld");
                        var worldBin  = ObjectBinary.From <World>(world);
                        var extraRefs = worldBin.ExtraReferencedObjects.ToList();
                        extraRefs.Add(new UIndex(existingPowerEntry.UIndex));
                        worldBin.ExtraReferencedObjects = extraRefs.Distinct().ToArray(); // Filter out duplicates that may have already been in package
                        world.WriteBinary(worldBin);
                    }

                    foreach (var addlPow in randomNewPower.AdditionalRequiredPowers)
                    {
                        var existingPow = export.FileRef.FindEntry(addlPow);
                        //if (existingPow == null && randomNewPower.ImportOnly && sourcePackage != null)
                        //{
                        //    existingPow = PackageTools.CreateImportForClass(sourcePackage.FindExport(randomNewPower.PackageName + "." + randomNewPower.PowerName), export.FileRef);
                        //}

                        if (existingPow == null)
                        {
                            Debugger.Break();
                        }
                        powers.Add(new ObjectProperty(existingPow));
                    }
                }
            }

            // Strip any blank powers we might have added, remove any duplicates
            powers.RemoveAll(x => x.Value == int.MinValue);
            powers.ReplaceAll(powers.ToList().Distinct()); //tolist prevents concurrent modification in nested linq

            // DEBUG
#if DEBUG
            var duplicates = powers
                             .GroupBy(i => i.Value)
                             .Where(g => g.Count() > 1)
                             .Select(g => g.Key).ToList();
            if (duplicates.Any())
            {
                foreach (var dup in duplicates)
                {
                    Debug.WriteLine($"DUPLICATE POWER IN LOADOUT {export.FileRef.GetEntry(dup).ObjectName}");
                }
                Debugger.Break();
            }
#endif
            export.WriteProperty(powers);

            // Our precalculated map should have accounted for imports already, so we odn't need to worry about missing imports upstream
            // If this is not a master or localization file (which are often used for imports)
            // Change the number around so it will work across packages.
            // May need disabled if game becomes unstable.

            // We check if less than 10 as it's very unlikely there will be more than 10 loadouts in a non-persistent package
            // if it's > 10 it's likely already a memory-changed item by MER
            var pName = Path.GetFileName(export.FileRef.FilePath);
            if (export.indexValue < 10 && !PackageTools.IsPersistentPackage(pName) && !PackageTools.IsLocalizationPackage(pName))
            {
                export.ObjectName = new NameReference(export.ObjectName, ThreadSafeRandom.Next(2000));
            }

            if (originalPowerUIndexes.Any())
            {
                // We should ensure the original objects are still referenced so shared objects they have (vfx?) are kept in memory
                // Dunno if this actually fixes the problems...
                PackageTools.AddReferencesToWorld(export.FileRef, originalPowerUIndexes.Select(x => export.FileRef.GetUExport(x)));
            }

            return(true);
        }
コード例 #23
0
        private static bool RandomizeWeaponLoadout(ExportEntry export, RandomizationOption option)
        {
            // Check for blacklisted changes
            // HACK FOR NOW until we have better solution in place
            if (export.ObjectName.Name.Contains("HammerHead", StringComparison.InvariantCultureIgnoreCase))
            {
                return(false); // Do not randomize hammerhead
            }

            var guns = export.GetProperty <ArrayProperty <ObjectProperty> >("Weapons");

            if (guns.Count == 1) //Randomizing multiple guns could be difficult and I'm not sure enemies ever change their weapons.
            {
                var gun = guns[0];
                if (gun.Value == 0)
                {
                    return(false);                // Null entry in weapons list
                }
                var allowedGuns = GetAllowedWeaponsForLoadout(export);
                if (allowedGuns.Any())
                {
                    var randomNewGun = allowedGuns.RandomElementByWeight(x => x.Weight);
                    if (option.HasSliderOption && option.SliderValue >= 0)
                    {
                        randomNewGun = AllAvailableWeapons[(int)option.SliderValue];
                    }
                    //if (ThreadSafeRandom.Next(1) == 0)
                    //{
                    //    randomNewGun = allowedGuns.FirstOrDefault(x => x.GunName.Contains("GrenadeLauncher"));
                    //}

                    var originalGun = gun.ResolveToEntry(export.FileRef);
                    if (randomNewGun.GunName != originalGun.ObjectName)
                    {
                        var gunInfo = randomNewGun;
                        MERLog.Information($@"Changing gun {export.ObjectName} => {randomNewGun.GunName}");
                        // It's a different gun.

                        // See if we need to port this in
                        var fullName = gunInfo.PackageName + "." + randomNewGun.GunName;
                        var repoint  = export.FileRef.FindEntry(fullName);

                        if (repoint != null)
                        {
                            // Gun does not need ported in
                            gun.Value = repoint.UIndex;
                        }
                        else
                        {
                            // Gun needs ported in
                            var newEntry = PortWeaponIntoPackage(export.FileRef, randomNewGun);
                            gun.Value = newEntry.UIndex;
                        }

                        //if (!tried)
                        export.WriteProperty(guns);
                        var pName = Path.GetFileName(export.FileRef.FilePath);

                        // If this is not a master or localization file (which are often used for imports)
                        // Change the number around so it will work across packages.
                        // May need disabled if game becomes unstable.

                        // We check if less than 10 as it's very unlikely there will be more than 10 loadouts in a non-persistent package
                        // if it's > 10 it's likely already a memory-changed item by MER
                        var isPersistentPackage = PackageTools.IsPersistentPackage(pName);
                        if (export.indexValue < 10 && !isPersistentPackage && !PackageTools.IsLocalizationPackage(pName))
                        {
                            export.ObjectName = new NameReference(export.ObjectName, ThreadSafeRandom.Next(2000) + 10);
                        }
                        else if (isPersistentPackage && originalGun.UIndex > 0)
                        {
                            // Make sure we add the original gun to the list of referenced memory objects
                            // so subfiles that depend on this gun existing don't crash the game!
                            var world     = export.FileRef.FindExport("TheWorld");
                            var worldBin  = ObjectBinary.From <World>(world);
                            var extraRefs = worldBin.ExtraReferencedObjects.ToList();
                            extraRefs.Add(new UIndex(originalGun.UIndex));
                            worldBin.ExtraReferencedObjects = extraRefs.Distinct().ToArray(); // Filter out duplicates that may have already been in package
                            world.WriteBinary(worldBin);
                        }


                        tried = true;
                    }
                }
                return(true);
            }

            return(false);
        }
コード例 #24
0
        private static bool PerformWriteCheck(Action <string, string> messageCallback)
        {
#if WINDOWS
            MERLog.Information("Performing write check on all game directories...");
            var targets = Locations.GetAllAvailableTargets();
            try
            {
                List <string> directoriesToGrant = new List <string>();
                foreach (var t in targets)
                {
                    // Check all folders are writable
                    bool isFullyWritable = true;
                    var  testDirectories = Directory.GetDirectories(t.TargetPath, "*", SearchOption.AllDirectories);
                    foreach (var d in testDirectories)
                    {
                        isFullyWritable &= Utilities.IsDirectoryWritable(d);
                    }
                }

                bool isAdmin = Utilities.IsAdministrator();

                if (directoriesToGrant.Any())
                {
                    string args = "";
                    // Some directories not writable
                    foreach (var dir in directoriesToGrant)
                    {
                        if (args != "")
                        {
                            args += " ";
                        }

                        args += $"\"{dir}\"";
                    }

                    args = $"\"{System.Security.Principal.WindowsIdentity.GetCurrent().Name}\" {args}";

                    throw new Exception("not implemented.");

                    /*
                     * var permissionsGranterExe = Path.Combine(Locations.ResourcesDir, "Binaries", "PermissionsGranter.exe");
                     *
                     * //need to run write permissions program
                     * if (isAdmin)
                     * {
                     *  int result = Utilities.RunProcess(permissionsGranterExe, args, true, true, true, true);
                     *  if (result == 0)
                     *  {
                     *      MERLog.Information("Elevated process returned code 0, directories are hopefully writable now.");
                     *      return true;
                     *  }
                     *  else
                     *  {
                     *      MERLog.Error("Elevated process returned code " + result +
                     *                ", directories probably aren't writable.");
                     *      return false;
                     *  }
                     * }
                     * else
                     * {
                     *  string message = $"The Mass Effect 2 game folder is not writeable by your user account. Mass Effect 2 Randomizer will attempt to grant access to these folders/registry with the PermissionsGranter.exe program:\n";
                     *
                     *  foreach (string str in directoriesToGrant)
                     *  {
                     *      message += "\n" + str;
                     *  }
                     *
                     *  messageCallback?.Invoke("Write permissions required for modding", message);
                     *  int result = Utilities.RunProcess(permissionsGranterExe, args, true, true, true, true);
                     *  if (result == 0)
                     *  {
                     *      MERLog.Information("Elevated process returned code 0, directories are hopefully writable now.");
                     *      return true;
                     *  }
                     *  else
                     *  {
                     *      MERLog.Error($"Elevated process returned code {result}, directories probably aren't writable.");
                     *      return false;
                     *  }
                     * }
                     */
                }
            }
            catch (Exception e)
            {
                MERLog.Exception(e, "Error checking for write privileges. This may be a significant sign that an installed game is not in a good state.");
                return(false);
            }
#endif
            return(true);
        }
コード例 #25
0
        public static async void StartRestore(MainWindow mw, bool isQuick, Action postRestoreDelegate = null)
        {
            var pd = await mw.ShowProgressAsync("Restoring game", "Preparing to restore game");

            pd.SetIndeterminate();
            await Task.Run(() =>
            {
                if (isQuick)
                {
                    // Nuke the DLC
                    MERLog.Information(@"Quick restore started");
                    pd.SetMessage("Removing randomize DLC component");
                    var dlcModPath = MERFileSystem.GetDLCModPath();
                    if (Directory.Exists(dlcModPath))
                    {
                        MERLog.Information($@"Deleting {dlcModPath}");
                        Utilities.DeleteFilesAndFoldersRecursively(dlcModPath);
                    }

                    mw.DLCComponentInstalled = false;


                    // Restore basegame only files
                    pd.SetMessage("Restoring randomized basegame files");
                    var isControllerModInstalled = SFXGame.IsControllerBasedInstall();

                    var backupPath       = BackupService.GetGameBackupPath(MERFileSystem.Game, out _, false);
                    var gameCookedPath   = M3Directories.GetCookedPath(Locations.GetTarget(MERFileSystem.Game));
                    var backupCookedPath = MEDirectories.GetCookedPath(MERFileSystem.Game, backupPath);
                    foreach (var bgf in MERFileSystem.alwaysBasegameFiles)
                    {
                        var srcPath  = Path.Combine(backupCookedPath, bgf);
                        var destPath = Path.Combine(gameCookedPath, bgf);
                        MERLog.Information($@"Restoring {bgf}");
                        File.Copy(srcPath, destPath, true);
                    }

                    if (isControllerModInstalled)
                    {
                        // We must also restore Coalesced.ini or it will reference a UI that is no longer available and game will not boot
                        MERLog.Information(@"Controller based install detected, also restoring Coalesced.ini to prevent startup crash");
                        File.Copy(Path.Combine(backupPath, "BioGame", "Config", "PC", "Cooked", "Coalesced.ini"), Path.Combine(Locations.GetTarget(MERFileSystem.Game).TargetPath, "BioGame", "Config", "PC", "Cooked", "Coalesced.ini"), true);
                    }

                    // Delete basegame TFC
                    var baseTFC = MERFileSystem.GetTFCPath(false);
                    if (File.Exists(baseTFC))
                    {
                        File.Delete(baseTFC);
                    }

                    // Done!
                }
                else
                {
                    // Full restore
                    var target = Locations.GetTarget(MERFileSystem.Game);
                    MERLog.Information($@"Performing full game restore on {target.TargetPath} target after restore");

                    object syncObj = new object();
                    BackupHandler.GameRestore gr = new BackupHandler.GameRestore(MERFileSystem.Game)
                    {
                        ConfirmationCallback = (title, message) =>
                        {
                            bool response = false;
                            Application.Current.Dispatcher.Invoke(async() =>
                            {
                                response = await mw.ShowMessageAsync(title, message,
                                                                     MessageDialogStyle.AffirmativeAndNegative,
                                                                     new MetroDialogSettings()
                                {
                                    AffirmativeButtonText = "OK",
                                    NegativeButtonText    = "Cancel",
                                }) == MessageDialogResult.Affirmative;
                                lock (syncObj)
                                {
                                    Monitor.Pulse(syncObj);
                                }
                            });
                            lock (syncObj)
                            {
                                Monitor.Wait(syncObj);
                            }

                            return(response);
                        },
                        BlockingErrorCallback = (title, message) => { Application.Current.Dispatcher.Invoke(async() => { await mw.ShowMessageAsync(title, message); }); },
                        RestoreErrorCallback  = (title, message) => { Application.Current.Dispatcher.Invoke(async() => { await mw.ShowMessageAsync(title, message); }); },
                        UpdateStatusCallback  = message =>
                                                Application.Current.Dispatcher.Invoke(() => pd.SetMessage(message)),
                        UpdateProgressCallback = (done, total) =>
                                                 Application.Current.Dispatcher.Invoke(() =>
                        {
                            pd.SetProgress(done * 1d / total);
                            if (total != 0)
                            {
                                TaskbarHelper.SetProgressState(TaskbarProgressBarState.Normal);
                                TaskbarHelper.SetProgress(done * 1.0 / total);
                            }
                        }),
                        SetProgressIndeterminateCallback = indeterminate => Application.Current.Dispatcher.Invoke(() =>
                        {
                            if (indeterminate)
                            {
                                pd.SetIndeterminate();
                            }
                            TaskbarHelper.SetProgressState(indeterminate ? TaskbarProgressBarState.Indeterminate : TaskbarProgressBarState.Normal);
                        }),
                        SelectDestinationDirectoryCallback = (title, message) =>
                        {
                            string selectedPath = null;
                            Application.Current.Dispatcher.Invoke(() =>
                            {
                                // Not sure if this has to be synced
                                CommonOpenFileDialog ofd = new CommonOpenFileDialog()
                                {
                                    Title            = "Select restore destination directory",
                                    IsFolderPicker   = true,
                                    EnsurePathExists = true
                                };
                                if (ofd.ShowDialog() == CommonFileDialogResult.Ok)
                                {
                                    selectedPath = ofd.FileName;
                                }
                            });
                            return(selectedPath);
                        }
                    };
                    gr.PerformRestore(target.TargetPath);
                    mw.DLCComponentInstalled = false;
                    MERLog.Information(@"Reloading target after restore");
                    target.ReloadGameTarget(false, false);
                    mw.SetupTargetDescriptionText();
                }
            }).ContinueWithOnUIThread(async x =>
            {
                TaskbarHelper.SetProgressState(TaskbarProgressBarState.NoProgress);
                await pd.CloseAsync();
                postRestoreDelegate?.Invoke();
            });
        }
コード例 #26
0
        public static bool InstallOHKO(RandomizationOption arg)
        {
            MERLog.Information("Installing One-Hit KO");

            var sfxgame = MERFileSystem.GetPackageFile("SFXGame.pcc");

            if (sfxgame != null && File.Exists(sfxgame))
            {
                var sfxgameP = MEPackageHandler.OpenMEPackage(sfxgame);

                // Blood on screen VFX
                sfxgameP.GetUExport(29336).RemoveProperty("BleedOutEventPair");
                sfxgameP.GetUExport(29336).RemoveProperty("BleedOutVFXTemplate");

                // Prevent weird landing glitch
                var fallingStateLanded = sfxgameP.GetUExport(11293);
                var landedData         = fallingStateLanded.Data;
                NopRange(landedData, 0x2C, 0x14);
                fallingStateLanded.Data = landedData;

                MERFileSystem.SavePackage(sfxgameP);
            }
            else
            {
            }


            // ProCer tutorials setting min1Health
            SetupProCer();

            // Player classes - Remove shields, set maxhealth to 1
            string[] classes = new[] { "Adept", "Engineer", "Infiltrator", "Sentinel", "Soldier", "Vanguard" };
            foreach (var c in classes)
            {
                var charClass = MERFileSystem.GetPackageFile($"SFXCharacterClass_{c}.pcc");
                if (charClass != null && File.Exists(charClass))
                {
                    var charClassP = MEPackageHandler.OpenMEPackage(charClass);
                    var ccLoadout  = charClassP.FindExport($"BioChar_Loadouts.Player.PLY_{c}");

                    var ccProps = ccLoadout.GetProperties();
                    ccProps.GetProp <ArrayProperty <StructProperty> >("ShieldLoadouts").Clear(); // Remove shields

                    // Set health to 1
                    var health = ccProps.GetProp <StructProperty>("MaxHealth");
                    health.GetProp <FloatProperty>("X").Value = 1;
                    health.GetProp <FloatProperty>("Y").Value = 1;

                    ccLoadout.WriteProperties(ccProps);

                    // Remove any passive powers
                    ZeroOutStatList(charClassP.FindExport($"SFXGameContent_Powers.SFXPower_{c}Passive"), "HealthBonus", false);
                    ZeroOutStatList(charClassP.FindExport($"SFXGameContent_Powers.SFXPower_{c}Passive_Evolved1"), "HealthBonus", false);
                    ZeroOutStatList(charClassP.FindExport($"SFXGameContent_Powers.SFXPower_{c}Passive_Evolved2"), "HealthBonus", false);

                    if (c == "Vanguard")
                    {
                        // Patch the immunity effect
                        var shieldEffectOnApplied = charClassP.GetUExport(530);
                        var seData = shieldEffectOnApplied.Data;
                        NopRange(seData, 0x2BF, 0x13);
                        shieldEffectOnApplied.Data = seData;
                    }

                    MERFileSystem.SavePackage(charClassP);
                }
            }

            // Zero out stats in tables
            MERPackageCache cache = new MERPackageCache();

            foreach (var asset in ZeroOutStatAssets)
            {
                var statClass = asset.GetAsset(cache);
                if (statClass != null)
                {
                    foreach (var zos in asset.PropertiesToZeroOut)
                    {
                        ZeroOutStatList(statClass, zos, true);
                    }
                }
            }

            foreach (var package in cache.GetPackages())
            {
                MERFileSystem.SavePackage(package);
            }

            {
                //var reaveF = MERFileSystem.GetPackageFile("SFXPower_Reave_Player.pcc");
                //if (reaveF != null && File.Exists(reaveF))
                //{
                //    var reaveP = MEPackageHandler.OpenMEPackage(reaveF);

                //    var defaultReave = reaveP.GetUExport(27);
                //    var regen = defaultReave.GetProperty<ArrayProperty<FloatProperty>>("HealthRegenMult");
                //    regen[0].Value = 0;
                //    regen[1].Value = 0;
                //    regen[2].Value = 0;
                //    regen[3].Value = 0;
                //    defaultReave.WriteProperty(regen);

                //    var bonusDuration = defaultReave.GetProperty<ArrayProperty<FloatProperty>>("HealthBonusDuration");
                //    bonusDuration[0].Value = 0;
                //    bonusDuration[1].Value = 0;
                //    bonusDuration[2].Value = 0;
                //    bonusDuration[3].Value = 0;
                //    defaultReave.WriteProperty(bonusDuration);

                //    MERFileSystem.SavePackage(reaveP);
                //}
            }

            return(true);
        }
コード例 #27
0
        /// <summary>
        /// Shuffler from ME1 Randomizer
        /// </summary>
        /// <param name="export"></param>
        /// <param name="option"></param>
        /// <returns></returns>
        public static bool ShuffleCutscenePawns(ExportEntry export, RandomizationOption option)
        {
            if (!CanRandomize(export, out var cutsceneName))
            {
                return(false);
            }
            if (acceptableTagsForPawnShuffling == null)
            {
                LoadAsset();
            }
            var variableLinks = export.GetProperty <ArrayProperty <StructProperty> >("VariableLinks");

            List <ObjectProperty> pawnsToShuffle = new List <ObjectProperty>();
            var playerRefs = new List <ExportEntry>();

            foreach (var variableLink in variableLinks)
            {
                var expectedType    = variableLink.GetProp <ObjectProperty>("ExpectedType");
                var expectedTypeStr = export.FileRef.GetEntry(expectedType.Value).ObjectName;
                var DEBUG           = variableLink.GetProp <StrProperty>("LinkDesc");
                if (expectedTypeStr == "SeqVar_Object" || expectedTypeStr == "SeqVar_Player" || expectedTypeStr == "BioSeqVar_ObjectFindByTag")
                {
                    //Investigate the links
                    var linkedVariables = variableLink.GetProp <ArrayProperty <ObjectProperty> >("LinkedVariables");
                    foreach (var objRef in linkedVariables)
                    {
                        var linkedObj = export.FileRef.GetUExport(objRef.Value).GetProperty <ObjectProperty>("ObjValue");
                        if (linkedObj != null)
                        {
                            //This is the data the node is referencing
                            var linkedObjectEntry = export.FileRef.GetEntry(linkedObj.Value);
                            var linkedObjName     = linkedObjectEntry.ObjectName;
                            if (linkedObjName == "BioPawn" && linkedObjectEntry is ExportEntry bioPawnExport)
                            {
                                var flyingpawn = bioPawnExport.GetProperty <BoolProperty>("bCanFly")?.Value;
                                if (flyingpawn == null || flyingpawn == false)
                                {
                                    pawnsToShuffle.Add(objRef); //pointer to this node
                                }
                            }
                        }
                        else if (expectedTypeStr == "SeqVar_Object")
                        {
                            //We might be assigned to. We need to look at the parent sequence
                            //and find what assigns me
                            var node      = export.FileRef.GetUExport(objRef.Value);
                            var parentRef = node.GetProperty <ObjectProperty>("ParentSequence");
                            if (parentRef != null)
                            {
                                var parent          = export.FileRef.GetUExport(parentRef.Value);
                                var sequenceObjects = parent.GetProperty <ArrayProperty <ObjectProperty> >("SequenceObjects");
                                if (sequenceObjects != null)
                                {
                                    foreach (var obj in sequenceObjects)
                                    {
                                        if (obj.Value <= 0)
                                        {
                                            continue;
                                        }
                                        var sequenceObject = export.FileRef.GetUExport(obj.Value);
                                        if (sequenceObject.InheritsFrom("SequenceAction") && sequenceObject.ClassName == "SeqAct_SetObject" && sequenceObject != export)
                                        {
                                            //check if target is my node
                                            var varlinqs = sequenceObject.GetProperty <ArrayProperty <StructProperty> >("VariableLinks");
                                            if (varlinqs != null)
                                            {
                                                var targetLink = varlinqs.FirstOrDefault(x =>
                                                {
                                                    var linkdesc = x.GetProp <StrProperty>("LinkDesc");
                                                    return(linkdesc != null && linkdesc == "Target");
                                                });
                                                var targetLinkedVariables = targetLink?.GetProp <ArrayProperty <ObjectProperty> >("LinkedVariables");
                                                if (targetLinkedVariables != null)
                                                {
                                                    //see if target is node we are investigating for setting.
                                                    foreach (var targetLinkedVariable in targetLinkedVariables)
                                                    {
                                                        var potentialTarget = export.FileRef.GetUExport(targetLinkedVariable.Value);
                                                        if (potentialTarget == node)
                                                        {
                                                            Debug.WriteLine("FOUND TARGET!");
                                                            //See what value this is set to. If it inherits from BioPawn we can use it in the shuffling.
                                                            var valueLink = varlinqs.FirstOrDefault(x =>
                                                            {
                                                                var linkdesc = x.GetProp <StrProperty>("LinkDesc");
                                                                return(linkdesc != null && linkdesc == "Value");
                                                            });
                                                            var valueLinkedVariables = valueLink?.GetProp <ArrayProperty <ObjectProperty> >("LinkedVariables");
                                                            if (valueLinkedVariables != null && valueLinkedVariables.Count == 1)
                                                            {
                                                                var linkedNode     = export.FileRef.GetUExport(valueLinkedVariables[0].Value);
                                                                var linkedNodeType = linkedNode.GetProperty <ObjectProperty>("ObjValue");
                                                                if (linkedNodeType != null)
                                                                {
                                                                    var linkedNodeData = export.FileRef.GetUExport(linkedNodeType.Value);
                                                                    if (linkedNodeData.InheritsFrom("BioPawn"))
                                                                    {
                                                                        //We can shuffle this item.
                                                                        Debug.WriteLine("Adding shuffle item: " + objRef.Value);
                                                                        pawnsToShuffle.Add(objRef); //pointer to this node
                                                                    }
                                                                }
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        string className = export.FileRef.GetUExport(objRef.Value).ClassName;
                        if (className == "SeqVar_Player")
                        {
                            playerRefs.Add(export.FileRef.GetUExport(objRef.Value));
                            pawnsToShuffle.Add(objRef); //pointer to this node
                        }
                        else if (className == "BioSeqVar_ObjectFindByTag")
                        {
                            var tagToFind = export.FileRef.GetUExport(objRef.Value).GetProperty <StrProperty>("m_sObjectTagToFind")?.Value;
                            if (tagToFind != null && acceptableTagsForPawnShuffling.Contains(tagToFind))
                            {
                                pawnsToShuffle.Add(objRef); //pointer to this node
                            }
                        }
                    }
                }
            }

            if (pawnsToShuffle.Count > 1)
            {
                int reshuffleAttemptsRemaining = 3;
                while (reshuffleAttemptsRemaining > 0)
                {
                    reshuffleAttemptsRemaining--;
                    MERLog.Information("Randomizing pawns in interp: " + export.FullPath);
                    foreach (var refx in playerRefs)
                    {
                        refx.WriteProperty(new BoolProperty(true, "bReturnsPawns")); //Ensure the object returns pawns. It should, but maybe it doesn't.
                    }

                    var newAssignedValues = pawnsToShuffle.Select(x => x.Value).ToList();
                    newAssignedValues.Shuffle();
                    for (int i = 0; i < pawnsToShuffle.Count; i++)
                    {
                        pawnsToShuffle[i].Value = newAssignedValues[i];
                    }

                    export.WriteProperty(variableLinks);
                    if (export.EntryHasPendingChanges)
                    {
                        break;
                    }
                }
                return(true);
            }
            return(false);
        }
コード例 #28
0
        //public static ALOTVersionInfo GetInstalledALOTInfo()
        //{
        //    string gamePath = MERUtilities.GetALOTMarkerFilePath();
        //    if (gamePath != null && File.Exists(gamePath))
        //    {
        //        try
        //        {
        //            using (FileStream fs = new FileStream(gamePath, System.IO.FileMode.Open, FileAccess.Read))
        //            {
        //                fs.SeekEnd();
        //                long endPos = fs.Position;
        //                fs.Position = endPos - 4;
        //                uint memi = fs.ReadUInt32();

        //                if (memi == MEMI_TAG)
        //                {
        //                    //ALOT has been installed
        //                    fs.Position = endPos - 8;
        //                    int installerVersionUsed = fs.ReadInt32();
        //                    int perGameFinal4Bytes = 0;

        //                    if (installerVersionUsed >= 10 && installerVersionUsed != perGameFinal4Bytes) //default bytes before 178 MEMI Format
        //                    {
        //                        fs.Position = endPos - 12;
        //                        short ALOTVER = fs.ReadInt16();
        //                        byte ALOTUPDATEVER = (byte)fs.ReadByte();
        //                        byte ALOTHOTFIXVER = (byte)fs.ReadByte();

        //                        //unused for now
        //                        fs.Position = endPos - 16;
        //                        int MEUITMVER = fs.ReadInt32();

        //                        return new ALOTVersionInfo(ALOTVER, ALOTUPDATEVER, ALOTHOTFIXVER, MEUITMVER);
        //                    }
        //                    else
        //                    {
        //                        return new ALOTVersionInfo(0, 0, 0, 0); //MEMI tag but no info we know of
        //                    }
        //                }
        //            }
        //        }
        //        catch (Exception e)
        //        {
        //            MERLog.Error("Error reading marker file for Mass Effect. ALOT Info will be returned as null (nothing installed). " + e.Message);
        //            return null;
        //        }
        //    }
        //    return null;
        //}


        public static int runProcess(string exe, string args, bool standAlone = false)
        {
            MERLog.Information("Running process: " + exe + " " + args);
            using (Process p = new Process())
            {
                p.StartInfo.CreateNoWindow         = true;
                p.StartInfo.FileName               = exe;
                p.StartInfo.UseShellExecute        = false;
                p.StartInfo.Arguments              = args;
                p.StartInfo.RedirectStandardOutput = true;
                p.StartInfo.RedirectStandardError  = true;


                StringBuilder output = new StringBuilder();
                StringBuilder error  = new StringBuilder();

                using (AutoResetEvent outputWaitHandle = new AutoResetEvent(false))
                    using (AutoResetEvent errorWaitHandle = new AutoResetEvent(false))
                    {
                        p.OutputDataReceived += (sender, e) =>
                        {
                            if (e.Data == null)
                            {
                                outputWaitHandle.Set();
                            }
                            else
                            {
                                output.AppendLine(e.Data);
                            }
                        };
                        p.ErrorDataReceived += (sender, e) =>
                        {
                            if (e.Data == null)
                            {
                                errorWaitHandle.Set();
                            }
                            else
                            {
                                error.AppendLine(e.Data);
                            }
                        };

                        p.Start();
                        if (!standAlone)
                        {
                            int timeout = 600000;
                            p.BeginOutputReadLine();
                            p.BeginErrorReadLine();

                            if (p.WaitForExit(timeout) &&
                                outputWaitHandle.WaitOne(timeout) &&
                                errorWaitHandle.WaitOne(timeout))
                            {
                                // Process completed. Check process.ExitCode here.
                                MERLog.Information("Process standard output of " + exe + " " + args + ":");
                                if (output.ToString().Length > 0)
                                {
                                    MERLog.Information("Standard:\n" + output.ToString());
                                }
                                if (error.ToString().Length > 0)
                                {
                                    MERLog.Error("Error output:\n" + error.ToString());
                                }
                                return(p.ExitCode);
                            }
                            else
                            {
                                // Timed out.
                                MERLog.Error("Process timed out: " + exe + " " + args);
                                return(-1);
                            }
                        }
                        else
                        {
                            return(0); //standalone
                        }
                    }
            }
        }
コード例 #29
0
        public static bool RandomizeExport(ExportEntry export, RandomizationOption option)
        {
            if (!CanRandomize(export))
            {
                return(false);
            }
            MERLog.Information($"[{Path.GetFileNameWithoutExtension(export.FileRef.FilePath)}] Randomizing movement interpolations for " + export.UIndex + ": " + export.InstancedFullPath);
            var props    = export.GetProperties();
            var posTrack = props.GetProp <StructProperty>("PosTrack");

            if (posTrack != null)
            {
                var points = posTrack.GetProp <ArrayProperty <StructProperty> >("Points");
                if (points != null)
                {
                    foreach (StructProperty s in points)
                    {
                        var outVal = s.GetProp <StructProperty>("OutVal");
                        if (outVal != null)
                        {
                            FloatProperty x = outVal.GetProp <FloatProperty>("X");
                            FloatProperty y = outVal.GetProp <FloatProperty>("Y");
                            FloatProperty z = outVal.GetProp <FloatProperty>("Z");
                            x.Value = x.Value * ThreadSafeRandom.NextFloat(1 - option.SliderValue, 1 + option.SliderValue);
                            y.Value = y.Value * ThreadSafeRandom.NextFloat(1 - option.SliderValue, 1 + option.SliderValue);
                            z.Value = z.Value * ThreadSafeRandom.NextFloat(1 - option.SliderValue, 1 + option.SliderValue);
                        }
                    }
                }
            }

            var eulerTrack = props.GetProp <StructProperty>("EulerTrack");

            if (eulerTrack != null)
            {
                var points = eulerTrack.GetProp <ArrayProperty <StructProperty> >("Points");
                if (points != null)
                {
                    foreach (StructProperty s in points)
                    {
                        var outVal = s.GetProp <StructProperty>("OutVal");
                        if (outVal != null)
                        {
                            FloatProperty x = outVal.GetProp <FloatProperty>("X");
                            FloatProperty y = outVal.GetProp <FloatProperty>("Y");
                            FloatProperty z = outVal.GetProp <FloatProperty>("Z");
                            if (x.Value != 0)
                            {
                                x.Value = x.Value * ThreadSafeRandom.NextFloat(1 - option.SliderValue, 1 + option.SliderValue);
                            }
                            else
                            {
                                x.Value = ThreadSafeRandom.NextFloat(0, ThreadSafeRandom.NextFloat(-1000 * option.SliderValue, 1000 * option.SliderValue));
                            }

                            if (y.Value != 0)
                            {
                                y.Value = y.Value * ThreadSafeRandom.NextFloat(1 - option.SliderValue, 1 + option.SliderValue);
                            }
                            else
                            {
                                y.Value = ThreadSafeRandom.NextFloat(0, ThreadSafeRandom.NextFloat(-1000 * option.SliderValue, 1000 * option.SliderValue));
                            }

                            if (z.Value != 0)
                            {
                                z.Value = z.Value * ThreadSafeRandom.NextFloat(1 - option.SliderValue, 1 + option.SliderValue);
                            }
                            else
                            {
                                z.Value = ThreadSafeRandom.NextFloat(0, ThreadSafeRandom.NextFloat(-1000 * option.SliderValue, 1000 * option.SliderValue));
                            }
                        }
                    }
                }
            }

            export.WriteProperties(props);
            return(true);
        }
コード例 #30
0
        private static void RandomizeDancer()
        {
            var loungeF = MERFileSystem.GetPackageFile("BioD_TwrHub_202Lounge.pcc");

            if (loungeF != null && File.Exists(loungeF))
            {
                var package = MEPackageHandler.OpenMEPackage(loungeF);
                var bodySM  = package.GetUExport(4509);
                var headSM  = package.GetUExport(2778);

                // Install new head and body assets
                var newInfo = DancerOptions.RandomElement();
                while (newInfo.BodyAsset != null && !newInfo.BodyAsset.IsAssetFileAvailable())
                {
                    // Find another asset that is available
                    MERLog.Information($@"Asset {newInfo.BodyAsset.AssetPath} in {newInfo.BodyAsset.PackageFile} not available, repicking...");
                    newInfo = DancerOptions.RandomElement();
                }
                var newBody = PackageTools.PortExportIntoPackage(package, newInfo.BodyAsset.GetAsset());
                bodySM.WriteProperty(new ObjectProperty(newBody.UIndex, "SkeletalMesh"));

                if (newInfo.HeadAsset != null)
                {
                    var newHead = PackageTools.PortExportIntoPackage(package, newInfo.HeadAsset.GetAsset());
                    headSM.WriteProperty(new ObjectProperty(newHead.UIndex, "SkeletalMesh"));
                }
                else if (!newInfo.KeepHead)
                {
                    headSM.RemoveProperty("SkeletalMesh");
                }


                if (newInfo.DrawScale != 1)
                {
                    // Install DS3D on the archetype. It works. Not gonna question it
                    var ds = new CFVector3()
                    {
                        X = newInfo.DrawScale,
                        Y = newInfo.DrawScale,
                        Z = newInfo.DrawScale,
                    };
                    package.GetUExport(619).WriteProperty(ds.ToLocationStructProperty("DrawScale3D")); //hack
                }

                // Install any updates to locations/rotations
                var dancerInstance = package.GetUExport(4510); // contains location data for dancer which may need to be slightly adjusted
                if (newInfo.Location != null)
                {
                    dancerInstance.WriteProperty(newInfo.Location.ToLocationStructProperty("Location"));
                }
                if (newInfo.Rotation != null)
                {
                    dancerInstance.WriteProperty(newInfo.Rotation.ToRotatorStructProperty("Rotation"));
                }

                if (newInfo.MorphFace != null)
                {
                    var newHead = PackageTools.PortExportIntoPackage(package, newInfo.MorphFace.GetAsset());
                    headSM.WriteProperty(new ObjectProperty(newHead.UIndex, "MorphHead"));
                }
                MERFileSystem.SavePackage(package);
            }
        }