Example #1
0
        public static Gesture InstallRandomGestureAsset(IMEPackage package, float minSequenceLength = 0, MERPackageCache cache = null)
        {
            var gestureFiles    = MERUtilities.ListStaticAssets("binary.gestures");
            var randGestureFile = gestureFiles.RandomElement();

            cache ??= new MERPackageCache();
            var gPackage = cache.GetCachedPackageEmbedded(randGestureFile, isFullPath: true);
            var options  = gPackage.Exports.Where(x => x.ClassName == "AnimSequence").ToList();

            // Pick a random element, make sure it's long enough
            var randomGestureExport = options.RandomElement();
            var seqLength           = randomGestureExport.GetProperty <FloatProperty>("SequenceLength");

            int numRetries = 5;

            while (seqLength < minSequenceLength)
            {
                randomGestureExport = options.RandomElement();
                seqLength           = randomGestureExport.GetProperty <FloatProperty>("SequenceLength");
                numRetries--;
            }

            var portedInExp = PackageTools.PortExportIntoPackage(package, randomGestureExport);

            return(new Gesture(portedInExp));
        }
Example #2
0
        private static void InstallBorger()
        {
            var endGame3F = MERFileSystem.GetPackageFile("BioP_EndGm3.pcc");

            if (endGame3F != null && File.Exists(endGame3F))
            {
                var biopEndGm3 = MEPackageHandler.OpenMEPackage(endGame3F);

                var packageBin    = MERUtilities.GetEmbeddedStaticFilesBinaryFile("Delux2go_Edmonton_Burger.pcc");
                var burgerPackage = MEPackageHandler.OpenMEPackageFromStream(new MemoryStream(packageBin));

                // 1. Add the burger package
                var burgerMDL = PackageTools.PortExportIntoPackage(biopEndGm3, burgerPackage.FindExport("Edmonton_Burger_Delux2go.Burger_MDL"));

                // 2. Link up the textures
                TFCBuilder.RandomizeExport(biopEndGm3.FindExport("Edmonton_Burger_Delux2go.Textures.Burger_Diff"), null);
                TFCBuilder.RandomizeExport(biopEndGm3.FindExport("Edmonton_Burger_Delux2go.Textures.Burger_Norm"), null);
                TFCBuilder.RandomizeExport(biopEndGm3.FindExport("Edmonton_Burger_Delux2go.Textures.Burger_Spec"), null);

                // 3. Convert the collector base into lunch or possibly early dinner
                // It's early dinner cause that thing will keep you full all night long
                biopEndGm3.GetUExport(11276).WriteProperty(new ObjectProperty(burgerMDL.UIndex, "SkeletalMesh"));
                biopEndGm3.GetUExport(11282).WriteProperty(new ObjectProperty(burgerMDL.UIndex, "SkeletalMesh"));
                MERFileSystem.SavePackage(biopEndGm3);
            }
        }
Example #3
0
        private async System.Threading.Tasks.Task InitialzeEnvAndPage()
        {
            LoadingText.Text = "加载广告";
            PrepareAds();


            if (IsAppUpdated || SystemInformation.IsFirstRun)
            {
                LoadingText.Text = "解压 AriaNg";
                await PackageTools.UnZip(new Uri("ms-appx:///webui.zip"));


                ContentDialog contentDialog = new ContentDialog()
                {
                    IsPrimaryButtonEnabled = true,
                    Title             = "还差一步",
                    Content           = "激活Aria2,本次启动可能无法正常连接,如果连接失败请重新启动程序",
                    PrimaryButtonText = "激活"
                };
                contentDialog.PrimaryButtonClick += async(e, a) =>
                {
                    await FullTrustProcessLauncher.LaunchFullTrustProcessForCurrentAppAsync();
                };
                await contentDialog.ShowAsync();
            }
            else
            {
                LoadingText.Text = "加载Aria2";
                await FullTrustProcessLauncher.LaunchFullTrustProcessForCurrentAppAsync();
            }

            LoadingText.Text = "处理Session";
            await GetSessionAndStartAriaNG();
        }
Example #4
0
        private static void RandomizeDancer(ExportEntry skeletalMeshActorMatArchetype)
        {
            // Install new head and body assets
            var newInfo = IlliumHub.DancerOptions.RandomElement();

            while (newInfo.Location != null || newInfo.Rotation != null || (newInfo.BodyAsset != null && !newInfo.BodyAsset.IsAssetFileAvailable()) || (newInfo.HeadAsset != null && !newInfo.HeadAsset.IsAssetFileAvailable()))
            {
                // Make sure assets are available, if not, repick
                // I don't want anything that requires specific positioning data
                newInfo = IlliumHub.DancerOptions.RandomElement();
            }

            var newBody = PackageTools.PortExportIntoPackage(skeletalMeshActorMatArchetype.FileRef, newInfo.BodyAsset.GetAsset());

            var bodySM = skeletalMeshActorMatArchetype.GetProperty <ObjectProperty>("SkeletalMeshComponent").ResolveToEntry(skeletalMeshActorMatArchetype.FileRef) as ExportEntry;
            var headSM = skeletalMeshActorMatArchetype.GetProperty <ObjectProperty>("HeadMesh").ResolveToEntry(skeletalMeshActorMatArchetype.FileRef) as ExportEntry;

            bodySM.WriteProperty(new ObjectProperty(newBody.UIndex, "SkeletalMesh"));

            if (newInfo.HeadAsset != null)
            {
                var newHead = PackageTools.PortExportIntoPackage(skeletalMeshActorMatArchetype.FileRef, 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,
                };
                skeletalMeshActorMatArchetype.WriteProperty(ds.ToLocationStructProperty("DrawScale3D")); //hack
            }

            if (newInfo.MorphFace != null)
            {
                var newHead = PackageTools.PortExportIntoPackage(skeletalMeshActorMatArchetype.FileRef, newInfo.MorphFace.GetAsset());
                headSM.WriteProperty(new ObjectProperty(newHead.UIndex, "MorphHead"));
            }
        }
Example #5
0
        private static void RandomizeALDancers()
        {
            {
                var denBar = MERFileSystem.GetPackageFile(@"BioD_OmgHub_220DenBar.pcc");
                if (denBar != null)
                {
                    var denBarP = MEPackageHandler.OpenMEPackage(denBar);
                    RandomizeDancer(denBarP.GetUExport(1287));
                    RandomizeDancer(denBarP.GetUExport(1288));
                    RandomizeDancer(denBarP.GetUExport(1289));
                    RandomizeDancer(denBarP.GetUExport(1292));
                    RandomizeDancer(denBarP.GetUExport(1293));
                    MERFileSystem.SavePackage(denBarP);
                }
            }

            var denDance = MERFileSystem.GetPackageFile(@"BioD_OmgHub_230DenDance.pcc");

            if (denDance != null)
            {
                var denDanceP = MEPackageHandler.OpenMEPackage(denDance);
                RandomizeDancer(denDanceP.GetUExport(1257)); //sit
                RandomizeDancer(denDanceP.GetUExport(1250));
                RandomizeDancer(denDanceP.GetUExport(1251));

                // shep sits at dancer. it uses different pawn.
                var entertainerBPSKM = denDanceP.GetUExport(4322);
                var newInfo          = IlliumHub.DancerOptions.RandomElement();
                while (newInfo.Location != null || newInfo.Rotation != null || newInfo.KeepHead == false || (newInfo.BodyAsset != null && !newInfo.BodyAsset.IsAssetFileAvailable()) || (newInfo.HeadAsset != null && !newInfo.HeadAsset.IsAssetFileAvailable()))
                {
                    // I don't want anything that requires specific positioning data, and I want to keep the head.
                    newInfo = IlliumHub.DancerOptions.RandomElement();
                }

                var newDancerMDL = PackageTools.PortExportIntoPackage(denDanceP, newInfo.BodyAsset.GetAsset());
                entertainerBPSKM.WriteProperty(new ObjectProperty(newDancerMDL, "SkeletalMesh"));
                MERFileSystem.SavePackage(denDanceP);
            }
        }
        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);
        }
        /// <summary>
        /// Ports a power into a package
        /// </summary>
        /// <param name="targetPackage"></param>
        /// <param name="powerInfo"></param>
        /// <param name="additionalPowers">A list of additioanl powers that are referenced when this powerinfo is an import only power (prevent re-opening package)</param>
        /// <returns></returns>
        public static IEntry PortPowerIntoPackage(IMEPackage targetPackage, PowerInfo powerInfo, out IMEPackage sourcePackage)
        {
            if (powerInfo.IsCorrectedPackage)
            {
                var sourceData = MERUtilities.GetEmbeddedStaticFilesBinaryFile("correctedloadouts.powers." + powerInfo.PackageFileName);
                sourcePackage = MEPackageHandler.OpenMEPackageFromStream(new MemoryStream(sourceData));
            }
            else
            {
                sourcePackage = NonSharedPackageCache.Cache.GetCachedPackage(powerInfo.PackageFileName);
            }

            if (sourcePackage != null)
            {
                var sourceExport = sourcePackage.GetUExport(powerInfo.SourceUIndex);
                if (!sourceExport.InheritsFrom("SFXPower") || sourceExport.IsDefaultObject)
                {
                    throw new Exception("Wrong setup!");
                }
                if (sourceExport.Parent != null && sourceExport.Parent.ClassName != "Package")
                {
                    throw new Exception("Cannot port power - parent object is not Package!");
                }

                var    newParent = EntryExporter.PortParents(sourceExport, targetPackage);
                IEntry newEntry;
                if (powerInfo.ImportOnly)
                {
                    //Debug.WriteLine($"ImportOnly in file {targetPackage.FilePath}");
                    if (powerInfo.RequiresStartupPackage)
                    {
                        ThreadSafeDLCStartupPackage.AddStartupPackage(Path.GetFileNameWithoutExtension(powerInfo.PackageFileName));
                        if (powerInfo.IsCorrectedPackage)
                        {
                            // File must be added to MERFS DLC
                            var outP = Path.Combine(MERFileSystem.DLCModCookedPath, powerInfo.PackageFileName);
                            if (!File.Exists(outP))
                            {
                                sourcePackage.Save(outP, true);
                            }
                        }
                    }

                    newEntry = PackageTools.CreateImportForClass(sourceExport, targetPackage, newParent);

                    // Port in extra imports so the calling class can reference them as necessary.
                    foreach (var addlPow in powerInfo.AdditionalRequiredPowers)
                    {
                        var addlSourceExp = sourcePackage.FindExport(addlPow);
                        PackageTools.CreateImportForClass(addlSourceExp, targetPackage, EntryExporter.PortParents(addlSourceExp, targetPackage));
                    }
                }
                else
                {
#if DEBUG
                    // DEBUG ONLY-----------------------------------
                    //var defaults = sourceExport.GetDefaults();
                    //defaults.RemoveProperty("VFX");
                    //var vfx = defaults.GetProperty<ObjectProperty>("VFX").ResolveToEntry(sourcePackage) as ExportEntry;
                    //vxx.RemoveProperty("PlayerCrust");
                    //vfx.FileRef.GetUExport(1544).RemoveProperty("oPrefab");

                    ////vfx = defaults.FileRef.GetUExport(6211); // Prefab
                    ////vfx.RemoveProperty("WorldImpactVisualEffect");
                    //MERPackageCache cached = new MERPackageCache();
                    //EntryExporter.ExportExportToPackage(vfx, targetPackage, out newEntry, cached);
                    //PackageTools.AddReferencesToWorld(targetPackage, new [] {newEntry as ExportEntry});

                    //return null;


                    // END DEBUG ONLY--------------------------------
#endif
                    List <EntryStringPair> relinkResults = null;
                    if ((powerInfo.IsCorrectedPackage || (PackageTools.IsPersistentPackage(powerInfo.PackageFileName) && MERFileSystem.GetPackageFile(powerInfo.PackageFileName.ToLocalizedFilename()) == null)))
                    {
                        // Faster this way, without having to check imports
                        Dictionary <IEntry, IEntry> crossPCCObjectMap = new Dictionary <IEntry, IEntry>(); // Not sure what this is used for these days. SHould probably just be part of the method
                        relinkResults = EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneAllDependencies, sourceExport, targetPackage,
                                                                             newParent, true, out newEntry, crossPCCObjectMap);
                    }
                    else
                    {
                        // MEMORY SAFE (resolve imports to exports)
                        MERPackageCache cache = new MERPackageCache();
                        relinkResults = EntryExporter.ExportExportToPackage(sourceExport, targetPackage, out newEntry, cache);
                    }

                    if (relinkResults.Any())
                    {
                        Debugger.Break();
                    }
                }

                return(newEntry);
            }
            return(null); // No package was found
        }
Example #8
0
        public static bool RandomizeBasicGestures(ExportEntry export, RandomizationOption option)
        {
            if (!CanRandomize(export))
            {
                return(false);
            }
            if (export.GetProperty <ObjectProperty>("SkeletalMeshComponent")?.ResolveToEntry(export.FileRef) is ExportEntry smc)
            {
                //Debug.WriteLine($"Installing new lite animations for {export.InstancedFullPath}");
                var animsets         = smc.GetProperty <ArrayProperty <ObjectProperty> >("AnimSets");
                var animTreeTemplate = smc.GetProperty <ObjectProperty>("AnimTreeTemplate")?.ResolveToEntry(export.FileRef) as ExportEntry;
                if (animsets != null && animTreeTemplate != null)
                {
                    int numAnimationsSupported = 0;
                    foreach (var animsetO in animsets)
                    {
                        var animset   = animsetO.ResolveToEntry(export.FileRef) as ExportEntry;
                        var sequences = animset.GetProperty <ArrayProperty <ObjectProperty> >("Sequences");
                        numAnimationsSupported += sequences.Count;
                    }

                    smc.RemoveProperty("AnimSets"); // We want to force new animations. we'll waste a bit of memory doing this but oh well
                    List <RBioEvtSysTrackGesture.Gesture> installedGestures = new List <RBioEvtSysTrackGesture.Gesture>();
                    var animationPackagesCache = new MERPackageCache();
                    while (numAnimationsSupported > 0)
                    {
                        // should we make sure they're unique?
                        var randGest = RBioEvtSysTrackGesture.InstallRandomFilteredGestureAsset(export.FileRef, 2, smaKeywords, null, null, true);
                        InstallDynamicAnimSetRefForSkeletalMesh(smc, randGest);
                        installedGestures.Add(randGest);
                        numAnimationsSupported--;
                    }
                    animationPackagesCache.ReleasePackages();
                    var isSubfile = PackageTools.IsLevelSubfile(Path.GetFileName(export.FileRef.FilePath));
                    if (isSubfile)
                    {
                        var newName = export.ObjectName + "_MER";
                        export.ObjectName = new NameReference(newName, ThreadSafeRandom.Next(25685462));
                    }

                    // Update the anim tree to use the new animations
                    // Too lazy to properly trace to find nodes. Just take children of this node that are AnimNodeSequences

                    // Add blend times to nodes so they 'blend' together a bit more, look a bit less jank
                    SetupChildrenBlend(animTreeTemplate);


                    // If the animtree has 'DebugPostLoad' flag, it means MER already is using this for something else
                    // We need to generate a new tree so the animations work properly
                    if (animTreeTemplate.ObjectFlags.Has(UnrealFlags.EObjectFlags.DebugPostLoad))
                    {
                        animTreeTemplate            = EntryCloner.CloneTree(animTreeTemplate, true);
                        animTreeTemplate.ObjectName = export.FileRef.GetNextIndexedName("MER_AnimTree"); // New name
                        smc.WriteProperty(new ObjectProperty(animTreeTemplate, "AnimTreeTemplate"));     // Write the template back
                    }
                    else if (isSubfile)
                    {
                        // if it's a subfile it won't be used as an import
                        // Let's rename this object
                        animTreeTemplate.ObjectName = new NameReference("MER_AnimTree", ThreadSafeRandom.Next(200000000)); // New name
                    }


                    var animNodeSequences = export.FileRef.Exports.Where(x => x.idxLink == animTreeTemplate.UIndex && x.IsA("AnimNodeSequence")).ToList();
                    for (int i = 0; i < installedGestures.Count; i++)
                    {
                        var installedG = installedGestures[i];
                        var ans        = animNodeSequences[i];
                        ans.WriteProperty(new NameProperty(installedG.GestureAnim, "AnimSeqName"));
                    }
                    animTreeTemplate.ObjectFlags |= UnrealFlags.EObjectFlags.DebugPostLoad; // Set as used
                    return(true);
                }
            }
            return(false);
        }
        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);
            }
        }
        public static bool RandomizeNPCExport2(ExportEntry export, RandomizationOption randOption)
        {
            if (!CanRandomizeNPCExport2(export))
            {
                return(false);
            }

            var props    = export.GetProperties();
            var isIconic = props.GetProp <BoolProperty>("bIconicAppearance");

            if (isIconic != null && isIconic)
            {
                return(false); // Don't modify an iconic look as it has a bunch fo stuff in it that can totally break it like scalp seams.
            }

            Dictionary <string, CFVector4> vectorValues = new();
            Dictionary <string, float>     scalarValues = new();

            if (export.IsA("BioPawn"))
            {
                ChangeColorsInSubObjects(export, vectorValues, scalarValues, props);
            }
            else
            {
                // It's a SFXSkeletalMeshActorMAT, a basic type of NPC.
                var parms = VectorParameter.GetVectorParameters(export);
                if (parms != null)
                {
                    foreach (var parm in parms)
                    {
                        vectorValues[parm.ParameterName] = parm.ParameterValue;
                        RStructs.RandomizeTint(parm.ParameterValue, false);
                    }
                    VectorParameter.WriteVectorParameters(export, parms, "VectorParameters");

                    // Get submaterials and write out their properties too
                    ChangeColorsInSubObjects(export, vectorValues, scalarValues, props);
                }
                // Should we try to randomize things that don't have a skin tone...?

                if (export.ObjectFlags.Has(UnrealFlags.EObjectFlags.ArchetypeObject) && PackageTools.IsLevelSubfile(Path.GetFileName(export.FileRef.FilePath)))
                {
                    export.indexValue = ThreadSafeRandom.Next();
                }
            }

            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);
        }
        public static IEntry PortWeaponIntoPackage(IMEPackage targetPackage, GunInfo gunInfo)
        {
            IMEPackage sourcePackage;

            if (gunInfo.IsCorrectedPackage)
            {
                var sourceData = MERUtilities.GetEmbeddedStaticFilesBinaryFile("correctedloadouts.weapons." + gunInfo.PackageFileName);
                sourcePackage = MEPackageHandler.OpenMEPackageFromStream(new MemoryStream(sourceData));

                if (gunInfo.ImportOnly)
                {
                    // We need to install this file
                    var outfname = Path.Combine(MERFileSystem.DLCModCookedPath, gunInfo.PackageFileName);
                    if (!File.Exists(outfname))
                    {
                        sourcePackage.Save(outfname, true);
                        ThreadSafeDLCStartupPackage.AddStartupPackage(Path.GetFileNameWithoutExtension(gunInfo.PackageFileName));
                    }
                }
            }
            else
            {
                sourcePackage = NonSharedPackageCache.Cache.GetCachedPackage(gunInfo.PackageFileName);
            }

            if (sourcePackage != null)
            {
                var sourceExport = sourcePackage.GetUExport(gunInfo.SourceUIndex);

                if (!sourceExport.InheritsFrom("SFXWeapon") || sourceExport.IsDefaultObject)
                {
                    throw new Exception("Wrong setup!");
                }

                if (sourceExport.Parent != null && sourceExport.Parent.ClassName != "Package")
                {
                    throw new Exception("Cannot port weapon - parent object is not Package!");
                }

                // 1. Setup the link that will be used.
                //var newParent = EntryExporter.PortParents(sourceExport, targetPackage);
                var newParent = EntryExporter.PortParents(sourceExport, targetPackage, gunInfo.ImportOnly);

                void errorOccuredCB(string s)
                {
                    Debugger.Break();
                }

                IEntry newEntry = null;
                if (gunInfo.ImportOnly)
                {
                    Debug.WriteLine($"Gun ImportOnly in file {targetPackage.FilePath}");
                    if (gunInfo.RequiresStartupPackage)
                    {
                        ThreadSafeDLCStartupPackage.AddStartupPackage(Path.GetFileNameWithoutExtension(gunInfo.PackageFileName));
                    }

                    newEntry = PackageTools.CreateImportForClass(sourceExport, targetPackage, newParent);
                }
                else
                {
                    List <EntryStringPair> relinkResults = null;
                    if (gunInfo.IsCorrectedPackage || (PackageTools.IsPersistentPackage(gunInfo.PackageFileName) && MERFileSystem.GetPackageFile(gunInfo.PackageFileName.ToLocalizedFilename()) == null))
                    {
                        // Faster this way, without having to check imports
                        Dictionary <IEntry, IEntry> crossPCCObjectMap = new Dictionary <IEntry, IEntry>(); // Not sure what this is used for these days. SHould probably just be part of the method
                        relinkResults = EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneAllDependencies, sourceExport, targetPackage,
                                                                             newParent, true, out newEntry, crossPCCObjectMap);
                    }
                    else
                    {
                        // MEMORY SAFE (resolve imports to exports)
                        MERPackageCache cache = new MERPackageCache();
                        relinkResults = EntryExporter.ExportExportToPackage(sourceExport, targetPackage, out newEntry, cache);
                    }

                    if (relinkResults.Any())
                    {
                        Debugger.Break();
                    }
                }

                return(newEntry);
            }
            else
            {
                Debug.WriteLine($"Package for gun porting not found: {gunInfo.PackageFileName}");
            }
            return(null); // No package was found
        }
Example #13
0
        public static Gesture InstallRandomFilteredGestureAsset(IMEPackage targetPackage, float minLength = 0, string[] filterKeywords = null, string[] blacklistedKeywords = null, string[] mainPackagesAllowed = null, bool includeSpecial = false, MERPackageCache cache = null)
        {
            var gestureFiles = MERUtilities.ListStaticAssets("binary.gestures", includeSpecial);

            // Special and package file filtering
            if (mainPackagesAllowed != null)
            {
                var newList = new List <string>();
                foreach (var gf in gestureFiles)
                {
                    if (includeSpecial && gf.Contains("gestures.special."))
                    {
                        newList.Add(gf);
                        continue;
                    }

                    var packageName = Path.GetFileNameWithoutExtension(MERUtilities.GetFilenameFromAssetName(gf));
                    if (mainPackagesAllowed.Contains(packageName))
                    {
                        newList.Add(gf);
                        continue;
                    }
                }

                gestureFiles = newList;
            }

            // Pick a random package
            var randGestureFile = gestureFiles.RandomElement();
            var hasCache        = cache != null;

            cache ??= new MERPackageCache();
            var gPackage = cache.GetCachedPackageEmbedded(randGestureFile, isFullPath: true);
            List <ExportEntry> options;

            if (filterKeywords != null && blacklistedKeywords != null)
            {
                options = gPackage.Exports.Where(x => x.ClassName == "AnimSequence" &&
                                                 x.ObjectName.Name.ContainsAny(StringComparison.InvariantCultureIgnoreCase, filterKeywords) &&
                                                 !x.ObjectName.Name.ContainsAny(blacklistedKeywords)).ToList();
            }
            else if (filterKeywords != null)
            {
                options = gPackage.Exports.Where(x => x.ClassName == "AnimSequence" &&
                                                 x.ObjectName.Name.ContainsAny(StringComparison.InvariantCultureIgnoreCase, filterKeywords)).ToList();
            }
            else if (blacklistedKeywords != null)
            {
                options = gPackage.Exports.Where(x => x.ClassName == "AnimSequence" &&
                                                 !x.ObjectName.Name.ContainsAny(blacklistedKeywords)).ToList();
            }
            else
            {
                options = gPackage.Exports.Where(x => x.ClassName == "AnimSequence").ToList();
            }

            if (options.Any())
            {
                // Pick a random element
                var randomGestureExport = options.RandomElement();

                // Filter it out if we cannot use it
                var seqLength = randomGestureExport.GetProperty <FloatProperty>("SequenceLength");

                int numRetries = 7;
                while (seqLength < minLength && numRetries >= 0)
                {
                    randomGestureExport = options.RandomElement();
                    seqLength           = randomGestureExport.GetProperty <FloatProperty>("SequenceLength");
                    numRetries--;
                }

                var portedInExp = PackageTools.PortExportIntoPackage(targetPackage, randomGestureExport);
                if (!hasCache)
                {
                    cache.ReleasePackages();
                }

                return(new Gesture(portedInExp));
            }

            return(null);
        }
        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);
        }
        public static bool PortPawnIntoPackage(PortablePawn pawn, IMEPackage targetPackage)
        {
            if (IsPawnAssetInPackageAlready(pawn, targetPackage))
            {
                return(true); // Pawn asset to port in already ported in
            }

            IMEPackage pawnPackage = null;

            if (pawn.IsCorrectedPackage)
            {
                // DEBUG
                //if (pawn.PackageFilename == "BioPawn_Collector_Batarian.pcc")
                //{
                //    pawnPackage = MEPackageHandler.OpenMEPackage(@"C:\Users\mgame\source\repos\ME2Randomizer\ME2Randomizer\staticfiles\binary\correctedpawns\" + pawn.PackageFilename);
                //}
                //else
                //{
                var correctedPawnData = MERUtilities.GetEmbeddedStaticFilesBinaryFile($"correctedpawns.{pawn.PackageFilename}");
                pawnPackage = MEPackageHandler.OpenMEPackageFromStream(new MemoryStream(correctedPawnData));
                //}
            }
            else
            {
                var pF = MERFileSystem.GetPackageFile(pawn.PackageFilename);
                if (pF != null)
                {
                    pawnPackage = MERFileSystem.OpenMEPackage(pF);
                }
                else
                {
                    Debug.WriteLine("Pawn package not found: {pawn.PackageFilename}");
                }
            }

            if (pawnPackage != null)
            {
                PackageTools.PortExportIntoPackage(targetPackage, pawnPackage.FindExport(pawn.AssetToPortIn), useMemorySafeImport: !pawn.IsCorrectedPackage);

                // Ensure the assets are too as they may not be directly referenced except in the level instance
                foreach (var asset in pawn.AssetPaths)
                {
                    if (targetPackage.FindExport(asset) == null)
                    {
                        PackageTools.PortExportIntoPackage(targetPackage, pawnPackage.FindExport(asset), useMemorySafeImport: !pawn.IsCorrectedPackage);
                    }
                }

                if (pawn.TextureUpdates != null)
                {
                    foreach (var tu in pawn.TextureUpdates)
                    {
                        var targetTextureExp = targetPackage.FindExport(tu.TextureInstancedFullPath);
                        TFCBuilder.InstallTexture(tu, targetTextureExp);
                    }
                }

                return(true);
            }
            return(false);
        }