示例#1
0
        public static bool InstallShepardDanceGesture(ExportEntry danceTrackExp, MERPackageCache cache)
        {
            cache ??= new MERPackageCache();

            var danceGestureData = RBioEvtSysTrackGesture.GetGestures(danceTrackExp);
            var newGestures      = new List <RBioEvtSysTrackGesture.Gesture>();

            int i = danceGestureData.Count + 1; // The default pose is the +1

            while (i > 0)
            {
                newGestures.Add(RBioEvtSysTrackGesture.InstallRandomFilteredGestureAsset(danceTrackExp.FileRef, 6, danceKeywords, notDanceKeywords, null, true, cache));
                i--;
            }

            for (int k = 0; k < danceGestureData.Count; k++)
            {
                danceGestureData[k] = newGestures.PullFirstItem();
            }
            RBioEvtSysTrackGesture.WriteGestures(danceTrackExp, danceGestureData);

            // Update the default pose
            RBioEvtSysTrackGesture.WriteDefaultPose(danceTrackExp, newGestures.PullFirstItem());

            return(true);
        }
            public virtual ExportEntry GetAsset(MERPackageCache cache = null)
            {
                IMEPackage package = null;

                if (cache != null)
                {
                    package = cache.GetCachedPackage(PackageFile);
                }
                else
                {
                    var packageF = MERFileSystem.GetPackageFile(PackageFile);
                    if (packageF != null)
                    {
                        package = MEPackageHandler.OpenMEPackage(packageF);
                    }
                }

                return(package?.FindExport(AssetPath));
            }
        public static void TestAllImportsInMERFS()
        {
            var dlcModPath = Path.Combine(MEDirectories.GetDefaultGamePath(MERFileSystem.Game), "BioGame", "DLC", $"DLC_MOD_{MERFileSystem.Game}Randomizer", "CookedPC");

            var packages = Directory.GetFiles(dlcModPath);

            var globalCache = MERFileSystem.GetGlobalCache();

            //var globalP = Path.Combine(dlcModPath, "BioP_Global.pcc");
            //if (File.Exists(globalP))
            //{
            //    // This is used for animation lookups.
            //    globalCache.InsertIntoCache(MEPackageHandler.OpenMEPackage(globalP));
            //}

            foreach (var p in packages)
            {
                if (p.RepresentsPackageFilePath())
                {
                    MERPackageCache localCache = new MERPackageCache();
                    Debug.WriteLine($"Checking package file {p}");
                    var pack = MEPackageHandler.OpenMEPackage(p);
                    foreach (var imp in pack.Imports)
                    {
                        if (imp.InstancedFullPath.StartsWith("Core.") || imp.InstancedFullPath.StartsWith("Engine."))
                        {
                            continue; // These have some natives are always in same file.
                        }
                        if (imp.InstancedFullPath == "BioVFX_Z_TEXTURES.Generic.Glass_Shards_Norm" && MERFileSystem.Game == MEGame.ME2)
                        {
                            continue; // This is... native for some reason?
                        }
                        var resolvedExp = EntryImporter.ResolveImport(imp, globalCache, localCache);
                        if (resolvedExp == null)
                        {
                            Debug.WriteLine($"Could not resolve import: {imp.InstancedFullPath}");
                        }
                    }
                }
            }
            Debug.WriteLine("Done checking imports");
        }
示例#4
0
        private static void RandomizeVIPShepDance()
        {
            var vipLoungeLF = MERFileSystem.GetPackageFile(@"BioD_OmgHub_500DenVIP_LOC_INT.pcc");

            if (vipLoungeLF != null && File.Exists(vipLoungeLF))
            {
                var vipLounge = MEPackageHandler.OpenMEPackage(vipLoungeLF);

                var playerDanceInterpData = vipLounge.GetUExport(547);
                var c = new MERPackageCache();

                InstallShepardDanceGesture(playerDanceInterpData, c);     // Paragon
                InstallShepardDanceGesture(vipLounge.GetUExport(559), c); // Stupid shep lol


                // Make able to dance again and again in convo
                var danceTalk = vipLounge.GetUExport(217);
                var bc        = new ConversationExtended(danceTalk);
                bc.LoadConversation(null);
                bc.StartingList.Clear();
                bc.StartingList.Add(0, 2);
                bc.SerializeNodes();

                MERFileSystem.SavePackage(vipLounge);
            }

            // make able to always talk to dancer
            var vipLoungeF = MERFileSystem.GetPackageFile(@"BioD_OmgHub_500DenVIP.pcc");

            if (vipLoungeF != null && File.Exists(vipLoungeF))
            {
                var vipLounge      = MEPackageHandler.OpenMEPackage(vipLoungeF);
                var selectableBool = vipLounge.GetUExport(8845);
                selectableBool.WriteProperty(new IntProperty(1, "bValue"));
                MERFileSystem.SavePackage(vipLounge);
            }
        }
        /// <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
        }
示例#6
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);
        }
示例#7
0
        private static void RandomizeAfterlifeShepDance()
        {
            var denDanceF = MERFileSystem.GetPackageFile(@"BioD_OmgHub_230DenDance.pcc");

            if (denDanceF != null)
            {
                var loungeP  = MEPackageHandler.OpenMEPackage(denDanceF);
                var sequence = loungeP.GetUExport(3924);

                MERPackageCache cache = new MERPackageCache();
                List <InterpTools.InterpData> interpDatas = new List <InterpTools.InterpData>();
                var interp1 = loungeP.GetUExport(3813);

                // Make 2 additional dance options by cloning the interp and the data tree
                var interp2 = MERSeqTools.CloneBasicSequenceObject(interp1);
                var interp3 = MERSeqTools.CloneBasicSequenceObject(interp1);


                // Clone the interp data for attaching to 2 and 3
                var interpData1 = loungeP.GetUExport(1174);
                var interpData2 = EntryCloner.CloneTree(interpData1);
                var interpData3 = EntryCloner.CloneTree(interpData2);
                KismetHelper.AddObjectToSequence(interpData2, sequence);
                KismetHelper.AddObjectToSequence(interpData3, sequence);

                // Load ID for randomization
                interpDatas.Add(new InterpTools.InterpData(interpData1));
                interpDatas.Add(new InterpTools.InterpData(interpData2));
                interpDatas.Add(new InterpTools.InterpData(interpData3));


                // Chance the data for interp2/3
                var id2 = SeqTools.GetVariableLinksOfNode(interp2);
                id2[0].LinkedNodes[0] = interpData2;
                SeqTools.WriteVariableLinksToNode(interp2, id2);

                var id3 = SeqTools.GetVariableLinksOfNode(interp3);
                id3[0].LinkedNodes[0] = interpData3;
                SeqTools.WriteVariableLinksToNode(interp3, id3);

                // Add additional finished states for fadetoblack when done
                KismetHelper.CreateOutputLink(loungeP.GetUExport(958), "Finished", interp2, 2);
                KismetHelper.CreateOutputLink(loungeP.GetUExport(958), "Finished", interp3, 2);


                // Link up the random choice it makes
                var randSw = MERSeqTools.InstallRandomSwitchIntoSequence(sequence, 3);
                KismetHelper.CreateOutputLink(randSw, "Link 1", interp1);
                KismetHelper.CreateOutputLink(randSw, "Link 2", interp2);
                KismetHelper.CreateOutputLink(randSw, "Link 3", interp3);

                // Break the original output to start the interp, repoint it's output to the switch instead
                var sgm = loungeP.GetUExport(1003); //set gesture mode
                KismetHelper.RemoveOutputLinks(sgm);
                KismetHelper.CreateOutputLink(sgm, "Done", loungeP.GetUExport(960));
                KismetHelper.CreateOutputLink(sgm, "Done", randSw);

                // Now install the dances
                foreach (var id in interpDatas)
                {
                    var danceTrack = id.InterpGroups[0].Tracks[0];
                    OmegaHub.InstallShepardDanceGesture(danceTrack.Export, cache);
                }

                MERFileSystem.SavePackage(loungeP);
            }
        }
示例#8
0
        public static bool InstallOHKO(RandomizationOption arg)
        {
            MERLog.Information("Installing One-Hit KO");

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

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

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

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

                MERFileSystem.SavePackage(sfxgameP);
            }
            else
            {
            }


            // ProCer tutorials setting min1Health
            SetupProCer();

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

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

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

                    ccLoadout.WriteProperties(ccProps);

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

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

                    MERFileSystem.SavePackage(charClassP);
                }
            }

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

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

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

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

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

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

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

            return(true);
        }
        public static bool RandomizePackageActorsInConversation(IMEPackage package, RandomizationOption option)
        {
            var conversationStartExports = package.Exports.Where(CanRandomizeSeqActStartConvo).ToList();

            if (!conversationStartExports.Any())
            {
                return(false);
            }

            MERPackageCache localCache = new MERPackageCache();

            foreach (var convStart in conversationStartExports)
            {
                //if (convStart.UIndex < 13638)
                //    continue;
                if (!CanRandomizeConversationStart(convStart))
                {
                    continue;
                }
                var bioConvImportProp = convStart.GetProperty <ObjectProperty>("Conv");
                if (bioConvImportProp == null)
                {
                    continue; // Some conversation starts are just filler stubs and are missing data like Nor_340a/bZaeed
                }
                var           bioConvImport = bioConvImportProp.ResolveToEntry(package) as ImportEntry;
                List <string> inputTags     = new();

                // Shuffle the inputs to the conversation. We will store these and then have to update the Owner and Player tags
                // I think......
                var seqLinks = SeqTools.GetVariableLinksOfNode(convStart);

                // Dictionary of linked nodes, and var links that point to them.
                List <ExportEntry>          shufflableNodes = new List <ExportEntry>();
                List <SeqTools.VarLinkInfo> applicableLinks = new();
                ExportEntry ownerEntry      = null;
                ExportEntry playerEntry     = null;
                var         sequenceObjects = SeqTools.GetAllSequenceElements(convStart).OfType <ExportEntry>().ToList();
                foreach (var varilink in seqLinks)
                {
                    if (CanLinkBeRandomized(varilink, out _))
                    {
                        var connectedItem = varilink.LinkedNodes[0] as ExportEntry;
                        if (!shufflableNodes.Contains(connectedItem))
                        {
                            // Check to make sure node has a value
                            if (connectedItem.ClassName == "SeqVar_Object")
                            {
                                var objValue = connectedItem.GetProperty <ObjectProperty>("ObjValue");
                                if (objValue == null && !MERSeqTools.IsAssignedBioPawn(convStart, connectedItem, sequenceObjects))
                                {
                                    continue; // This is not a shufflable node, it is never assigned anything
                                }
                            }

                            shufflableNodes.Add(connectedItem);
                        }

                        if (varilink.LinkedNodes[0].ClassName == "SeqVar_Player")
                        {
                            playerEntry = varilink.LinkedNodes[0] as ExportEntry;
                        }
                        else if (varilink.LinkDesc == "Owner")
                        {
                            ownerEntry = varilink.LinkedNodes[0] as ExportEntry;
                        }

                        applicableLinks.Add(varilink);
                    }
                }

                if (shufflableNodes.Count <= 1)
                {
                    continue; // We cannot edit this one
                }
                if (shufflableNodes.Count == 2 && playerEntry != null && ownerEntry != null)
                {
                    continue; // We can't swap owner and player due to hardcoded owner and player tags
                }
                // Build shuffle map
                bool retry = true;
                Dictionary <int, int> shuffleMap = null;
                while (retry)
                {
                    shuffleMap = new Dictionary <int, int>();
                    var reAssigned = shufflableNodes.ToList();
                    reAssigned.Shuffle();

                    for (int i = 0; i < shufflableNodes.Count; i++)
                    {
                        var sourceEntry = shufflableNodes[i];
                        var remapEntry  = reAssigned.PullFirstItem();

                        int retryCount = reAssigned.Count;
                        while (retryCount > 0 && (sourceEntry == remapEntry || (ownerEntry == sourceEntry && remapEntry == ownerEntry)))
                        {
                            reAssigned.Add(remapEntry);
                            sourceEntry = reAssigned.PullFirstItem();
                            retryCount--;
                        }

                        if (sourceEntry == ownerEntry && remapEntry == playerEntry)
                        {
                            // Cannot set player to owner
                            break; // We must force a retry
                        }

                        shuffleMap[sourceEntry.UIndex] = remapEntry.UIndex;
                    }

                    if (shuffleMap.Count != shufflableNodes.Count)
                    {
                        continue; // Try again
                    }
                    // We did it
                    retry = false;
                }

                // Apply the shuffle map
                Dictionary <NameReference, ActorLookup> findActorMap = new();

                foreach (var varilink in applicableLinks)
                {
                    var repointedItem = shuffleMap[varilink.LinkedNodes[0].UIndex];
                    //if (varilink.LinkedNodes[0] == playerEntry || repointedItem == playerEntry.UIndex)
                    //{
                    // Build FindActor mapping for player
                    // it should be:
                    // Player -> [Some actor, like Pup1_1]
                    // Pup1_1 -> Player
                    // When parsing the interpdatas, change the findactor's
                    // by this methodology
                    BuildActorMap(findActorMap, varilink, repointedItem);
                    //}

                    // Actor map for updating the bioconversation

                    //Debug.WriteLine($"Shuffle actor on varilink in convo: {varilink.LinkedNodes[0].ObjectName.Instanced} => {package.GetUExport(repointedItem).ObjectName.Instanced}");
                    varilink.LinkedNodes[0] = package.GetUExport(repointedItem);
                }

                //SeqTools.PrintVarLinkInfo(seqLinks);

                // Write the updated links out.
                SeqTools.WriteVariableLinksToNode(convStart, seqLinks);



                // Update the localizations
                foreach (var loc in Localizations)
                {
                    var bioConversation = EntryImporter.ResolveImport(bioConvImport, MERFileSystem.GetGlobalCache(), localCache, loc);
                    var conv            = new ConversationExtended(bioConversation);
                    conv.LoadConversation(null, true);

                    // Step 1. Update tags via map
                    var allConvEntries = conv.ReplyList.ToList();
                    allConvEntries.AddRange(conv.EntryList);
                    foreach (var convNode in allConvEntries)
                    {
                        // Update speaker
                        if (convNode.IsReply)
                        {
                            // Player. We can't do anything (or can we?)
                        }
                        else
                        {
                            // Non-player node. We can change the tag
                            var speakerTag = convNode.SpeakerTag;

                            // Even though it is dictionary, since it is NameRef, it is considered case sensitive. We have to use case insensitive check
                            var newName = findActorMap.FirstOrDefault(x => x.Key.Instanced.Equals(speakerTag.SpeakerName, StringComparison.InvariantCultureIgnoreCase)).Value;
                            if (newName != null && newName.FindActor.Name != null)
                            {
                                var newTagIdx = conv.Speakers.FirstOrDefault(x => x.SpeakerName.Equals(newName.FindActor.Instanced, StringComparison.InvariantCultureIgnoreCase));
                                if (newTagIdx != null)
                                {
                                    convNode.SpeakerIndex = newTagIdx.SpeakerID;
                                }
                                else
                                {
                                    var newSpeaker = new SpeakerExtended(conv.Speakers.Count - 3, new NameReference(newName.FindActor.Name.ToLower(), newName.FindActor.Number));
                                    newSpeaker.FaceFX_Male   = speakerTag.FaceFX_Male;
                                    newSpeaker.FaceFX_Female = speakerTag.FaceFX_Male;

                                    conv.Speakers.Add(newSpeaker);
                                    convNode.SpeakerIndex = newSpeaker.SpeakerID;
                                    //Debugger.Break();
                                }
                            }
                            else
                            {
                                //Debugger.Break();
                            }
                        }



                        // Update interpolation data
                        if (convNode.Interpdata == null)
                        {
                            continue;
                        }
                        var interpData = convNode.Interpdata;

                        InterpData id    = new InterpData(interpData);
                        var        convo = id.InterpGroups.FirstOrDefault(x => x.GroupName == "Conversation");
                        if (convo != null)
                        {
                            foreach (var it in convo.Tracks)
                            {
                                var props     = it.Export.GetProperties();
                                var findActor = props.GetProp <NameProperty>("m_nmFindActor");
                                if (findActor != null && findActor.Value.Name != "Owner" && findActorMap.TryGetValue(findActor.Value, out var newInfo) && newInfo.FindActor.Name != null)
                                {
                                    //Debug.WriteLine($"Updating find actor info: {findActor.Value.Instanced} -> {newInfo.FindActor.Instanced}");
                                    findActor.Value = newInfo.FindActor;
                                    if (newInfo.FindMode != null)
                                    {
                                        props.AddOrReplaceProp(new EnumProperty(newInfo.FindMode.ToString(), "EActorTrackFindActorMode", MERFileSystem.Game, "m_eFindActorMode"));
                                    }
                                    else
                                    {
                                        props.RemoveNamedProperty("m_eFindActorMode");
                                    }
                                }

                                var lookAtKeys = props.GetProp <ArrayProperty <StructProperty> >("m_aLookAtKeys");
                                if (lookAtKeys != null)
                                {
                                    foreach (var lookAtS in lookAtKeys)
                                    {
                                        var lookAt = lookAtS.GetProp <NameProperty>("nmFindActor");

                                        if (lookAt.Value.Name != "Owner" && findActorMap.TryGetValue(lookAt.Value, out var newInfoLA) && newInfoLA.FindActor.Name != null)
                                        {
                                            //Debug.WriteLine($"Updating lookat find actor info: {lookAt.Value.Instanced} -> {newInfoLA.FindActor.Instanced}");
                                            if (newInfoLA.FindActor.Name == null)
                                            {
                                                Debugger.Break();
                                            }
                                            lookAt.Value = newInfoLA.FindActor;
                                            var lookatFindMode = newInfoLA.FindMode?.ToString();
                                            lookatFindMode ??= "ActorTrack_FindActorByTag"; // if it's null, set it to the default. As this is struct, the property must exist
                                            lookAtS.Properties.AddOrReplaceProp(new EnumProperty(lookatFindMode, "EActorTrackFindActorMode", MERFileSystem.Game, "eFindActorMode"));
                                        }
                                    }
                                }

                                it.Export.WriteProperties(props);

                                //if (IsAllowedFindActor(findActor))
                                //{
                                //    if (actorsToFind.All(x => x.FindActor.Instanced != findActor.Value.Instanced))
                                //    {

                                //        ActorLookup al = new ActorLookup() { FindActor = findActor.Value };
                                //        var lookupType = it.Export.GetProperty<EnumProperty>("m_eFindActorMode");
                                //        if (lookupType != null && Enum.TryParse<EActorTrackFindActorMode>(lookupType.Value.Name, out var result))
                                //        {
                                //            al.FindMode = result;
                                //        }

                                //        actorsToFind.Add(al);
                                //    }

                                //    // add track
                                //    tracksToUpdate.Add(it);
                                //}
                            }
                        }
                    }
                    conv.SerializeNodes(); // Write the updated info back
                    MERFileSystem.SavePackage(bioConversation.FileRef);
                }
            }

            //// Step 2. Build the remapping
            //if (actorsToFind.Count <= 1)
            //    return false; // Nothing to randomize

            //// Instanced name to NameReference
            //Dictionary<string, ActorLookup> actorRemap = new Dictionary<string, ActorLookup>();
            //var shuffledActors = actorsToFind.ToList();
            //var unshuffledActors = actorsToFind.Select(x => x.FindActor.Instanced).ToList();
            //shuffledActors.Shuffle();

            //Debug.WriteLine("");
            //while (shuffledActors.Count > 0)
            //{
            //    var sourceItem = unshuffledActors.PullFirstItem();
            //    var remappedItem = shuffledActors.PullFirstItem();
            //    actorRemap[sourceItem] = remappedItem;
            //    Debug.WriteLine($"Remapping actor: {sourceItem} => {remappedItem.FindActor.Instanced}");
            //}

            //// Step 3. Update all tracks with new remap
            //foreach (var track in tracksToUpdate)
            //{
            //    var props = track.Export.GetProperties();
            //    var findActor = props.GetProp<NameProperty>("m_nmFindActor");
            //    if (IsAllowedFindActor(findActor))
            //    {
            //        if (actorRemap[findActor.Value.Instanced].FindMode != null)
            //        {
            //            props.AddOrReplaceProp(new EnumProperty(actorRemap[findActor.Value.Instanced].FindMode.ToString(), "EActorTrackFindActorMode", MERFileSystem.Game, "m_eFindActorMode"));
            //        }
            //        else
            //        {
            //            props.RemoveNamedProperty("m_eFindActorNode");
            //        }
            //        findActor.Value = actorRemap[findActor.Value.Instanced].FindActor;
            //        track.Export.WriteProperties(props);
            //    }
            //}


            return(true);
        }
        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
        }
示例#11
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);
        }
示例#12
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));
        }