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); }
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..."); } } }
public static bool RandomizeWeapons(RandomizationOption option) { var me2rbioweapon = CoalescedHandler.GetIniFile("BIOWeapon.ini"); // We must manually fetch game files cause MERFS will return the ini from the dlc mod instead. ME2Coalesced me2basegamecoalesced = new ME2Coalesced(MERFileSystem.GetSpecificFile(@"BioGame\Config\PC\Cooked\Coalesced.ini")); MERLog.Information("Randomizing basegame weapon ini"); var bioweapon = me2basegamecoalesced.Inis.FirstOrDefault(x => Path.GetFileName(x.Key) == "BIOWeapon.ini").Value; RandomizeWeaponIni(bioweapon, me2rbioweapon); var weaponInis = Directory.GetFiles(MEDirectories.GetDLCPath(MERFileSystem.Game), "BIOWeapon.ini", SearchOption.AllDirectories).ToList(); foreach (var wi in weaponInis) { if (wi.Contains($"DLC_MOD_{MERFileSystem.Game}Randomizer")) { continue; // Skip randomizer folders } MERLog.Information($@"Randomizing weapon ini {wi}"); //Log.Information("Randomizing weapons in ini: " + wi); var dlcWeapIni = DuplicatingIni.LoadIni(wi); RandomizeWeaponIni(dlcWeapIni, me2rbioweapon); //if (!MERFileSystem.UsingDLCModFS) //{ // Log.Information("Writing DLC BioWeapon: " + wi); // File.WriteAllText(wi, dlcWeapIni.ToString()); //} } return(true); }
public 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); }
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}"); } }
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"); } } } }
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); }
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); } } } }
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; }
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 }
/// <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); }
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")); } }
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); } }
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); }
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."); } }
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); }
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); }
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); } } }
/// <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); }
/// <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); }
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); }
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); }
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); }
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); }
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(); }); }
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); }
/// <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); }
//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 } } } }
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); }
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); } }