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);
        }
Example #2
0
        public static void CreateReachSpec(ExportEntry startNode, bool createTwoWay, ExportEntry destinationNode, string reachSpecClass, ReachSpecSize size, PropertyCollection externalGUIDProperties = null)
        {
            IMEPackage  Pcc = startNode.FileRef;
            ExportEntry reachSpectoClone = Pcc.Exports.FirstOrDefault(x => x.ClassName == "ReachSpec");

            if (externalGUIDProperties != null) //EXTERNAL
            {
                //external node

                //Debug.WriteLine("Num Exports: " + pcc.Exports.Count);
                if (reachSpectoClone != null)
                {
                    ExportEntry outgoingSpec = reachSpectoClone.Clone();
                    Pcc.addExport(outgoingSpec);

                    IEntry reachSpecClassImp = GetEntryOrAddImport(Pcc, reachSpecClass); //new class type.

                    outgoingSpec.idxClass      = reachSpecClassImp.UIndex;
                    outgoingSpec.idxObjectName = reachSpecClassImp.idxObjectName;

                    var            properties            = outgoingSpec.GetProperties();
                    ObjectProperty outgoingSpecStartProp = properties.GetProp <ObjectProperty>("Start");                                                                   //START
                    StructProperty outgoingEndStructProp = properties.GetProp <StructProperty>("End");                                                                     //Embeds END
                    ObjectProperty outgoingSpecEndProp   = outgoingEndStructProp.Properties.GetProp <ObjectProperty>(SharedPathfinding.GetReachSpecEndName(outgoingSpec)); //END
                    outgoingSpecStartProp.Value = startNode.UIndex;
                    outgoingSpecEndProp.Value   = 0;
                    var endGuid = outgoingEndStructProp.GetProp <StructProperty>("Guid");
                    endGuid.Properties = externalGUIDProperties; //set the other guid values to our guid values

                    //Add to source node prop
                    ArrayProperty <ObjectProperty> PathList = startNode.GetProperty <ArrayProperty <ObjectProperty> >("PathList");
                    PathList.Add(new ObjectProperty(outgoingSpec.UIndex));
                    startNode.WriteProperty(PathList);
                    outgoingSpec.WriteProperties(properties);


                    //Write Spec Size
                    SharedPathfinding.SetReachSpecSize(outgoingSpec, size.SpecRadius, size.SpecHeight);

                    //Reindex reachspecs.
                    SharedPathfinding.ReindexMatchingObjects(outgoingSpec);
                }
            }
            else
            {
                //Debug.WriteLine("Source Node: " + startNode.Index);

                //Debug.WriteLine("Num Exports: " + pcc.Exports.Count);
                //int outgoingSpec = pcc.ExportCount;
                //int incomingSpec = pcc.ExportCount + 1;


                if (reachSpectoClone != null)
                {
                    ExportEntry outgoingSpec = reachSpectoClone.Clone();
                    Pcc.addExport(outgoingSpec);
                    ExportEntry incomingSpec = null;
                    if (createTwoWay)
                    {
                        incomingSpec = reachSpectoClone.Clone();
                        Pcc.addExport(incomingSpec);
                    }

                    IEntry reachSpecClassImp = GetEntryOrAddImport(Pcc, reachSpecClass); //new class type.

                    outgoingSpec.idxClass      = reachSpecClassImp.UIndex;
                    outgoingSpec.idxObjectName = reachSpecClassImp.idxObjectName;

                    var outgoingSpecProperties = outgoingSpec.GetProperties();
                    if (reachSpecClass == "Engine.SlotToSlotReachSpec")
                    {
                        outgoingSpecProperties.Add(new ByteProperty(1, "SpecDirection")); //We might need to find a way to support this edit
                    }

                    //Debug.WriteLine("Outgoing UIndex: " + outgoingSpecExp.UIndex);

                    ObjectProperty outgoingSpecStartProp = outgoingSpecProperties.GetProp <ObjectProperty>("Start");                                                       //START
                    StructProperty outgoingEndStructProp = outgoingSpecProperties.GetProp <StructProperty>("End");                                                         //Embeds END
                    ObjectProperty outgoingSpecEndProp   = outgoingEndStructProp.Properties.GetProp <ObjectProperty>(SharedPathfinding.GetReachSpecEndName(outgoingSpec)); //END
                    outgoingSpecStartProp.Value = startNode.UIndex;
                    outgoingSpecEndProp.Value   = destinationNode.UIndex;

                    //Add to source node prop
                    var PathList = startNode.GetProperty <ArrayProperty <ObjectProperty> >("PathList");
                    PathList.Add(new ObjectProperty(outgoingSpec.UIndex));
                    startNode.WriteProperty(PathList);

                    //Write Spec Size
                    SetReachSpecSize(outgoingSpecProperties, size.SpecRadius, size.SpecHeight);
                    outgoingSpec.WriteProperties(outgoingSpecProperties);

                    if (createTwoWay)
                    {
                        incomingSpec.idxClass      = reachSpecClassImp.UIndex;
                        incomingSpec.idxObjectName = reachSpecClassImp.idxObjectName;
                        var incomingSpecProperties = incomingSpec.GetProperties();
                        if (reachSpecClass == "Engine.SlotToSlotReachSpec")
                        {
                            incomingSpecProperties.Add(new ByteProperty(2, "SpecDirection"));
                        }

                        ObjectProperty incomingSpecStartProp = incomingSpecProperties.GetProp <ObjectProperty>("Start");                                                       //START
                        StructProperty incomingEndStructProp = incomingSpecProperties.GetProp <StructProperty>("End");                                                         //Embeds END
                        ObjectProperty incomingSpecEndProp   = incomingEndStructProp.Properties.GetProp <ObjectProperty>(SharedPathfinding.GetReachSpecEndName(incomingSpec)); //END

                        incomingSpecStartProp.Value = destinationNode.UIndex;                                                                                                  //Uindex
                        incomingSpecEndProp.Value   = startNode.UIndex;


                        //Add reachspec to destination node's path list (returning)
                        var DestPathList = destinationNode.GetProperty <ArrayProperty <ObjectProperty> >("PathList");
                        DestPathList.Add(new ObjectProperty(incomingSpec.UIndex));
                        destinationNode.WriteProperty(DestPathList);

                        //destNode.WriteProperty(DestPathList);
                        SetReachSpecSize(incomingSpecProperties, size.SpecRadius, size.SpecHeight);

                        incomingSpec.WriteProperties(incomingSpecProperties);
                    }

                    //Reindex reachspecs.
                    SharedPathfinding.ReindexMatchingObjects(outgoingSpec);
                }
            }
        }
Example #3
0
        public static string GenerateUDKFileForLevel(string udkPath, IMEPackage pcc)
        {
            #region AssetPackage

            string meshPackageName = $"{Path.GetFileNameWithoutExtension(pcc.FilePath)}Meshes";
            string meshFile        = Path.Combine(udkPath, @"UDKGame\Content\Shared\", $"{meshPackageName}.upk");
            MEPackageHandler.CreateAndSavePackage(meshFile, MEGame.UDK);
            using IMEPackage meshPackage = MEPackageHandler.OpenUDKPackage(meshFile);
            meshPackage.getEntryOrAddImport("Core.Package");

            IEntry defMat    = meshPackage.getEntryOrAddImport("EngineMaterials.DefaultMaterial", "Material", "Engine");
            var    allMats   = new HashSet <int>();
            var    relinkMap = new Dictionary <IEntry, IEntry>();
            #region StaticMeshes

            List <ExportEntry> staticMeshes = pcc.Exports.Where(exp => exp.ClassName == "StaticMesh").ToList();
            foreach (ExportEntry mesh in staticMeshes)
            {
                var        mats = new Queue <int>();
                StaticMesh stm  = ObjectBinary.From <StaticMesh>(mesh);
                foreach (StaticMeshRenderData lodModel in stm.LODModels)
                {
                    foreach (StaticMeshElement meshElement in lodModel.Elements)
                    {
                        mats.Enqueue(meshElement.Material);
                        allMats.Add(meshElement.Material);
                        meshElement.Material = 0;
                    }
                }
                if (pcc.GetEntry(stm.BodySetup) is ExportEntry rbBodySetup)
                {
                    rbBodySetup.RemoveProperty("PhysMaterial");
                }
                mesh.WriteBinary(stm);
                IEntry newParent = EntryImporter.GetOrAddCrossImportOrPackage(mesh.ParentFullPath, pcc, meshPackage);
                EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneTreeAsChild, mesh, meshPackage, newParent, false, out IEntry ent, relinkMap);
                ExportEntry portedMesh = (ExportEntry)ent;
                stm = ObjectBinary.From <StaticMesh>(portedMesh);
                foreach (StaticMeshRenderData lodModel in stm.LODModels)
                {
                    foreach (StaticMeshElement meshElement in lodModel.Elements)
                    {
                        meshElement.Material = mats.Dequeue();
                    }
                }
                portedMesh.WriteBinary(stm);
            }

            #endregion

            #region Materials
            using (IMEPackage udkResources = MEPackageHandler.OpenMEPackageFromStream(Utilities.GetCustomAppResourceStream(MEGame.UDK)))
            {
                ExportEntry normDiffMat = udkResources.Exports.First(exp => exp.ObjectName == "NormDiffMat");
                foreach (int matUIndex in allMats)
                {
                    if (pcc.GetEntry(matUIndex) is ExportEntry matExp)
                    {
                        List <IEntry> textures = new MaterialInstanceConstant(matExp).Textures;
                        ExportEntry   diff     = null;
                        ExportEntry   norm     = null;
                        foreach (IEntry texEntry in textures)
                        {
                            if (texEntry is ExportEntry texport)
                            {
                                if (texport.ObjectName.Name.ToLower().Contains("diff"))
                                {
                                    diff = texport;
                                }
                                else if (texport.ObjectName.Name.ToLower().Contains("norm"))
                                {
                                    norm = texport;
                                }
                            }
                        }
                        if (diff == null)
                        {
                            relinkMap[matExp] = defMat;
                            continue;
                        }
                        else
                        {
                            EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.AddSingularAsChild, diff, meshPackage, null, false, out IEntry ent);
                            diff = (ExportEntry)ent;
                            diff.RemoveProperty("TextureFileCacheName");
                            diff.RemoveProperty("TFCFileGuid");
                            diff.RemoveProperty("LODGroup");
                        }
                        if (norm != null)
                        {
                            EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.AddSingularAsChild, norm, meshPackage, null, false, out IEntry ent);
                            norm = (ExportEntry)ent;
                            norm.RemoveProperty("TextureFileCacheName");
                            norm.RemoveProperty("TFCFileGuid");
                            norm.RemoveProperty("LODGroup");
                        }
                        EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneTreeAsChild, normDiffMat, meshPackage, null, true, out IEntry matEnt);
                        ExportEntry newMat = (ExportEntry)matEnt;
                        newMat.ObjectName = matExp.ObjectName;
                        Material matBin = ObjectBinary.From <Material>(newMat);
                        matBin.SM3MaterialResource.UniformExpressionTextures = new UIndex[] { norm?.UIndex ?? 0, diff.UIndex };
                        newMat.WriteBinary(matBin);
                        relinkMap[matExp] = newMat;
                        if (newMat.GetProperty <ArrayProperty <ObjectProperty> >("Expressions") is {} expressionsProp&& expressionsProp.Count >= 2)
                        {
                            ExportEntry diffExpression = meshPackage.GetUExport(expressionsProp[0].Value);
                            ExportEntry normExpression = meshPackage.GetUExport(expressionsProp[1].Value);
                            diffExpression.WriteProperty(new ObjectProperty(diff.UIndex, "Texture"));
                            normExpression.WriteProperty(new ObjectProperty(norm?.UIndex ?? 0, "Texture"));
                        }
                    }
                    else if (pcc.GetEntry(matUIndex) is ImportEntry matImp)
                    {
                        relinkMap[matImp] = defMat;
                    }
                }

                var relinkMapping = new OrderedMultiValueDictionary <IEntry, IEntry>(relinkMap);
                foreach (ExportEntry stmExport in staticMeshes)
                {
                    if (relinkMap.TryGetValue(stmExport, out IEntry destEnt) && destEnt is ExportEntry destExp)
                    {
                        Relinker.Relink(stmExport, destExp, relinkMapping);
                    }
                }
            }
            #endregion


            meshPackage.Save();

            #endregion


            var    staticMeshActors = new List <ExportEntry>();
            var    lightActors      = new List <ExportEntry>();
            string tempPackagePath  = Path.Combine(App.ExecFolder, $"{Path.GetFileNameWithoutExtension(pcc.FilePath)}.udk");
            File.Copy(Path.Combine(App.ExecFolder, "empty.udk"), tempPackagePath, true);
            using IMEPackage udkPackage = MEPackageHandler.OpenUDKPackage(tempPackagePath);
            {
                var topLevelMeshPackages = new List <IEntry>();
                foreach (ExportEntry exportEntry in staticMeshes)
                {
                    IEntry imp = udkPackage.getEntryOrAddImport($"{exportEntry.FullPath}", "StaticMesh", "Engine", exportEntry.ObjectName.Number);
                    while (imp.Parent != null)
                    {
                        imp = imp.Parent;
                    }
                    if (!topLevelMeshPackages.Contains(imp))
                    {
                        topLevelMeshPackages.Add(imp);
                    }
                }

                ExportEntry levelExport          = udkPackage.Exports.First(exp => exp.ClassName == "Level");
                List <int>  actorsInLevel        = ObjectBinary.From <Level>(pcc.Exports.First(exp => exp.ClassName == "Level")).Actors.Select(u => u.value).ToList();
                var         componentToMatrixMap = new Dictionary <int, Matrix>();
                foreach (int uIndex in actorsInLevel)
                {
                    if (pcc.GetEntry(uIndex) is ExportEntry stcExp)
                    {
                        if (stcExp.ClassName == "StaticMeshCollectionActor")
                        {
                            StaticMeshCollectionActor stmc = ObjectBinary.From <StaticMeshCollectionActor>(stcExp);
                            var components = stcExp.GetProperty <ArrayProperty <ObjectProperty> >("StaticMeshComponents");
                            for (int i = 0; i < components.Count; i++)
                            {
                                componentToMatrixMap[components[i].Value] = stmc.LocalToWorldTransforms[i];
                            }
                        }
                        else if (stcExp.ClassName == "StaticLightCollectionActor")
                        {
                            StaticLightCollectionActor stlc = ObjectBinary.From <StaticLightCollectionActor>(stcExp);
                            var components = stcExp.GetProperty <ArrayProperty <ObjectProperty> >("LightComponents");
                            for (int i = 0; i < components.Count; i++)
                            {
                                componentToMatrixMap[components[i].Value] = stlc.LocalToWorldTransforms[i];
                            }
                        }
                    }
                }

                #region StaticMeshActors
                {
                    var    emptySMCBin          = new StaticMeshComponent();
                    IEntry staticMeshActorClass = udkPackage.getEntryOrAddImport("Engine.StaticMeshActor");
                    udkPackage.getEntryOrAddImport("Engine.Default__StaticMeshActor", "StaticMeshActor", "Engine");
                    IEntry staticMeshComponentArchetype = udkPackage.getEntryOrAddImport("Engine.Default__StaticMeshActor.StaticMeshComponent0",
                                                                                         "StaticMeshComponent", "Engine");
                    int smaIndex = 2;
                    int smcIndex = 2;
                    foreach (ExportEntry smc in pcc.Exports.Where(exp => exp.ClassName == "StaticMeshComponent"))
                    {
                        if (smc.Parent is ExportEntry parent && actorsInLevel.Contains(parent.UIndex) && parent.IsA("StaticMeshActorBase"))
                        {
                            StructProperty locationProp;
                            StructProperty rotationProp;
                            StructProperty scaleProp = null;
                            smc.CondenseArchetypes();
                            if (!(smc.GetProperty <ObjectProperty>("StaticMesh") is { } meshProp) || !pcc.IsUExport(meshProp.Value))
                            {
                                continue;
                            }

                            smc.WriteBinary(emptySMCBin);
                            smc.RemoveProperty("bBioIsReceivingDecals");
                            smc.RemoveProperty("bBioForcePrecomputedShadows");
                            //smc.RemoveProperty("bUsePreComputedShadows");
                            smc.RemoveProperty("bAcceptsLights");
                            smc.RemoveProperty("IrrelevantLights");
                            smc.RemoveProperty("Materials"); //should make use of this?
                            smc.ObjectName = new NameReference("StaticMeshComponent", smcIndex++);
                            if (parent.ClassName == "StaticMeshCollectionActor")
                            {
                                if (!componentToMatrixMap.TryGetValue(smc.UIndex, out Matrix m))
                                {
                                    continue;
                                }
                                (Vector3 posVec, Vector3 scaleVec, Rotator rotator) = m.UnrealDecompose();
                                locationProp = CommonStructs.Vector3Prop(posVec, "Location");
                                rotationProp = CommonStructs.RotatorProp(rotator, "Rotation");
                                scaleProp    = CommonStructs.Vector3Prop(scaleVec, "DrawScale3D");
                                //smc.WriteProperty(CommonStructs.Matrix(m, "CachedParentToWorld"));
                            }
                            else
                            {
                                locationProp = parent.GetProperty <StructProperty>("Location");
                                rotationProp = parent.GetProperty <StructProperty>("Rotation");
                                scaleProp    = parent.GetProperty <StructProperty>("DrawScale3D");
                                if (parent.GetProperty <FloatProperty>("DrawScale")?.Value is float scale)
                                {
                                    Vector3 scaleVec = Vector3.One;
                                    if (scaleProp != null)
                                    {
                                        scaleVec = CommonStructs.GetVector3(scaleProp);
                                    }
                                    scaleProp = CommonStructs.Vector3Prop(scaleVec * scale, "DrawScale3D");
                                }
                            }

                            ExportEntry sma = new ExportEntry(udkPackage, EntryImporter.CreateStack(MEGame.UDK, staticMeshActorClass.UIndex))
                            {
                                ObjectName = new NameReference("StaticMeshActor", smaIndex++),
                                Class      = staticMeshActorClass,
                                Parent     = levelExport
                            };
                            sma.ObjectFlags |= UnrealFlags.EObjectFlags.HasStack;
                            udkPackage.AddExport(sma);

                            EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.AddSingularAsChild, smc, udkPackage,
                                                                 sma, true, out IEntry result);
                            var props = new PropertyCollection
                            {
                                new ObjectProperty(result.UIndex, "StaticMeshComponent"),
                                new NameProperty(new NameReference(Path.GetFileNameWithoutExtension(smc.FileRef.FilePath), smc.UIndex),
                                                 "Tag"),
                                new ObjectProperty(result.UIndex, "CollisionComponent")
                            };
                            if (locationProp != null)
                            {
                                props.Add(locationProp);
                            }
                            if (rotationProp != null)
                            {
                                props.Add(rotationProp);
                            }

                            if (scaleProp != null)
                            {
                                props.Add(scaleProp);
                            }
                            sma.WriteProperties(props);
                            staticMeshActors.Add(sma);
                        }
                    }
                    IEntry topMeshPackageImport = udkPackage.getEntryOrAddImport(meshPackageName, "Package");
                    foreach (IEntry mp in topLevelMeshPackages)
                    {
                        mp.Parent = topMeshPackageImport;
                    }
                }
                #endregion

                #region LightActors
                {
                    IEntry pointLightClass       = udkPackage.getEntryOrAddImport("Engine.PointLight");
                    IEntry spotLightClass        = udkPackage.getEntryOrAddImport("Engine.SpotLight");
                    IEntry directionalLightClass = udkPackage.getEntryOrAddImport("Engine.DirectionalLight");

                    int plaIndex = 1;
                    int plcIndex = 1;
                    int slaIndex = 1;
                    int slcIndex = 1;
                    int dlaIndex = 1;
                    int dlcIndex = 1;
                    foreach (ExportEntry lightComponent in pcc.Exports)
                    {
                        if (!(lightComponent.Parent is ExportEntry parent && actorsInLevel.Contains(parent.UIndex)))
                        {
                            continue;
                        }
                        StructProperty locationProp;
                        StructProperty rotationProp;
                        StructProperty scaleProp;
                        switch (lightComponent.ClassName)
                        {
                        case "PointLightComponent":
                            lightComponent.CondenseArchetypes();
                            lightComponent.ObjectName = new NameReference("PointLightComponent", plcIndex++);
                            if (parent.ClassName == "StaticLightCollectionActor")
                            {
                                if (!componentToMatrixMap.TryGetValue(lightComponent.UIndex, out Matrix m))
                                {
                                    continue;
                                }
                                (Vector3 posVec, Vector3 scaleVec, Rotator rotator) = m.UnrealDecompose();
                                locationProp = CommonStructs.Vector3Prop(posVec, "Location");
                                rotationProp = CommonStructs.RotatorProp(rotator, "Rotation");
                                scaleProp    = CommonStructs.Vector3Prop(scaleVec, "DrawScale3D");
                            }
                            else
                            {
                                locationProp = parent.GetProperty <StructProperty>("Location");
                                rotationProp = parent.GetProperty <StructProperty>("Rotation");
                                scaleProp    = parent.GetProperty <StructProperty>("DrawScale3D");
                                if (parent.GetProperty <FloatProperty>("DrawScale")?.Value is float scale)
                                {
                                    Vector3 scaleVec = Vector3.One;
                                    if (scaleProp != null)
                                    {
                                        scaleVec = CommonStructs.GetVector3(scaleProp);
                                    }
                                    scaleProp = CommonStructs.Vector3Prop(scaleVec * scale, "DrawScale3D");
                                }
                            }

                            ExportEntry pla = new ExportEntry(udkPackage, EntryImporter.CreateStack(MEGame.UDK, pointLightClass.UIndex))
                            {
                                ObjectName = new NameReference("PointLight", plaIndex++),
                                Class      = pointLightClass,
                                Parent     = levelExport
                            };
                            pla.ObjectFlags |= UnrealFlags.EObjectFlags.HasStack;
                            udkPackage.AddExport(pla);

                            EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.AddSingularAsChild, lightComponent, udkPackage, pla, true,
                                                                 out IEntry portedPLC);
                            var plsProps = new PropertyCollection
                            {
                                new ObjectProperty(portedPLC.UIndex, "LightComponent"),
                                new NameProperty("PointLight", "Tag"),
                            };
                            if (locationProp != null)
                            {
                                plsProps.Add(locationProp);
                            }
                            if (rotationProp != null)
                            {
                                plsProps.Add(rotationProp);
                            }
                            if (scaleProp != null)
                            {
                                plsProps.Add(scaleProp);
                            }
                            pla.WriteProperties(plsProps);
                            lightActors.Add(pla);
                            break;

                        case "SpotLightComponent":
                            lightComponent.CondenseArchetypes();
                            lightComponent.ObjectName = new NameReference("SpotLightComponent", slcIndex++);
                            if (parent.ClassName == "StaticLightCollectionActor")
                            {
                                if (!componentToMatrixMap.TryGetValue(lightComponent.UIndex, out Matrix m))
                                {
                                    continue;
                                }
                                (Vector3 posVec, Vector3 scaleVec, Rotator rotator) = m.UnrealDecompose();
                                locationProp = CommonStructs.Vector3Prop(posVec, "Location");
                                rotationProp = CommonStructs.RotatorProp(rotator, "Rotation");
                                scaleProp    = CommonStructs.Vector3Prop(scaleVec, "DrawScale3D");
                            }
                            else
                            {
                                locationProp = parent.GetProperty <StructProperty>("Location");
                                rotationProp = parent.GetProperty <StructProperty>("Rotation");
                                scaleProp    = parent.GetProperty <StructProperty>("DrawScale3D");
                                if (parent.GetProperty <FloatProperty>("DrawScale")?.Value is float scale)
                                {
                                    Vector3 scaleVec = Vector3.One;
                                    if (scaleProp != null)
                                    {
                                        scaleVec = CommonStructs.GetVector3(scaleProp);
                                    }
                                    scaleProp = CommonStructs.Vector3Prop(scaleVec * scale, "DrawScale3D");
                                }
                            }

                            ExportEntry sla = new ExportEntry(udkPackage, EntryImporter.CreateStack(MEGame.UDK, spotLightClass.UIndex))
                            {
                                ObjectName = new NameReference("SpotLight", slaIndex++),
                                Class      = spotLightClass,
                                Parent     = levelExport
                            };
                            sla.ObjectFlags |= UnrealFlags.EObjectFlags.HasStack;
                            udkPackage.AddExport(sla);

                            EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.AddSingularAsChild, lightComponent, udkPackage, sla, true,
                                                                 out IEntry portedSLC);
                            var slaProps = new PropertyCollection
                            {
                                new ObjectProperty(portedSLC.UIndex, "LightComponent"),
                                new NameProperty("SpotLight", "Tag"),
                            };
                            if (locationProp != null)
                            {
                                slaProps.Add(locationProp);
                            }
                            if (rotationProp != null)
                            {
                                slaProps.Add(rotationProp);
                            }
                            if (scaleProp != null)
                            {
                                slaProps.Add(scaleProp);
                            }
                            sla.WriteProperties(slaProps);
                            lightActors.Add(sla);
                            break;

                        case "DirectionalLightComponent":
                            lightComponent.CondenseArchetypes();
                            lightComponent.ObjectName = new NameReference("DirectionalLightComponent", dlcIndex++);
                            if (parent.ClassName == "StaticLightCollectionActor")
                            {
                                if (!componentToMatrixMap.TryGetValue(lightComponent.UIndex, out Matrix m))
                                {
                                    continue;
                                }
                                (Vector3 posVec, Vector3 scaleVec, Rotator rotator) = m.UnrealDecompose();
                                locationProp = CommonStructs.Vector3Prop(posVec, "Location");
                                rotationProp = CommonStructs.RotatorProp(rotator, "Rotation");
                                scaleProp    = CommonStructs.Vector3Prop(scaleVec, "DrawScale3D");
                            }
                            else
                            {
                                locationProp = parent.GetProperty <StructProperty>("Location");
                                rotationProp = parent.GetProperty <StructProperty>("Rotation");
                                scaleProp    = parent.GetProperty <StructProperty>("DrawScale3D");
                                if (parent.GetProperty <FloatProperty>("DrawScale")?.Value is float scale)
                                {
                                    Vector3 scaleVec = Vector3.One;
                                    if (scaleProp != null)
                                    {
                                        scaleVec = CommonStructs.GetVector3(scaleProp);
                                    }
                                    scaleProp = CommonStructs.Vector3Prop(scaleVec * scale, "DrawScale3D");
                                }
                            }

                            ExportEntry dla = new ExportEntry(udkPackage, EntryImporter.CreateStack(MEGame.UDK, directionalLightClass.UIndex))
                            {
                                ObjectName = new NameReference("DirectionalLight", dlaIndex++),
                                Class      = directionalLightClass,
                                Parent     = levelExport
                            };
                            dla.ObjectFlags |= UnrealFlags.EObjectFlags.HasStack;
                            udkPackage.AddExport(dla);

                            EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.AddSingularAsChild, lightComponent, udkPackage, dla, true,
                                                                 out IEntry portedDLC);
                            var dlaProps = new PropertyCollection
                            {
                                new ObjectProperty(portedDLC.UIndex, "LightComponent"),
                                new NameProperty("DirectionalLight", "Tag"),
                            };
                            if (locationProp != null)
                            {
                                dlaProps.Add(locationProp);
                            }
                            if (rotationProp != null)
                            {
                                dlaProps.Add(rotationProp);
                            }
                            if (scaleProp != null)
                            {
                                dlaProps.Add(scaleProp);
                            }
                            dla.WriteProperties(dlaProps);
                            lightActors.Add(dla);
                            break;
                        }
                    }
                }
                UDKifyLights(udkPackage);
                #endregion

                Level level = ObjectBinary.From <Level>(levelExport);
                level.Actors = levelExport.GetChildren().Where(ent => ent.IsA("Actor")).Select(ent => new UIndex(ent.UIndex)).ToList();
                levelExport.WriteBinary(level);

                udkPackage.Save();
            }

            string resultFilePath = Path.Combine(udkPath, @"UDKGame\Content\Maps\", $"{Path.GetFileNameWithoutExtension(pcc.FilePath)}.udk");
            using (IMEPackage udkPackage2 = MEPackageHandler.OpenUDKPackage(Path.Combine(App.ExecFolder, "empty.udk")))
            {
                ExportEntry levelExport = udkPackage2.Exports.First(exp => exp.ClassName == "Level");
                Level       levelBin    = ObjectBinary.From <Level>(levelExport);
                foreach (ExportEntry actor in staticMeshActors)
                {
                    EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneTreeAsChild, actor, udkPackage2, levelExport, true, out IEntry result);
                    levelBin.Actors.Add(result.UIndex);
                }
                foreach (ExportEntry actor in lightActors)
                {
                    EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneTreeAsChild, actor, udkPackage2, levelExport, true, out IEntry result);
                    levelBin.Actors.Add(result.UIndex);
                }
                levelExport.WriteBinary(levelBin);
                udkPackage2.Save(resultFilePath);
            }
            File.Delete(tempPackagePath);
            return(resultFilePath);
        }
Example #4
0
        private static void UDKifySpotLights(IMEPackage pcc, IEnumerable <ExportEntry> spotLightComponents)
        {
            var drawLightRadiusComponentClass  = pcc.getEntryOrAddImport("Engine.DrawLightRadiusComponent");
            var drawLightConeComponentClass    = pcc.getEntryOrAddImport("Engine.DrawLightConeComponent");
            var drawLightRadiusArchetype       = pcc.getEntryOrAddImport("Engine.Default__SpotLight.DrawLightRadius0", packageFile: "Engine", className: "DrawLightRadiusComponent");
            var drawLightSourceRadiusArchetype = pcc.getEntryOrAddImport("Engine.Default__SpotLight.DrawLightSourceRadius0", packageFile: "Engine", className: "DrawLightRadiusComponent");
            var drawInnerConeArchetype         = pcc.getEntryOrAddImport("Engine.Default__SpotLight.DrawInnerCone0", packageFile: "Engine", className: "DrawLightConeComponent");
            var drawOuterConeArchetype         = pcc.getEntryOrAddImport("Engine.Default__SpotLight.DrawOuterCone0", packageFile: "Engine", className: "DrawLightConeComponent");
            int dlcIndex = 1;
            int dlrIndex = 1;

            foreach (ExportEntry slc in spotLightComponents)
            {
                var   lightingChannels = slc.GetProperty <StructProperty>("LightingChannels");
                var   innerConeAngle   = slc.GetProperty <FloatProperty>("InnerConeAngle")?.Value ?? 0f;
                var   outerConeAngle   = slc.GetProperty <FloatProperty>("OuterConeAngle")?.Value ?? 44f;
                float radius           = slc.GetProperty <FloatProperty>("Radius")?.Value ?? 1024f;
                var   drawInnerCone    = new ExportEntry(pcc, new byte[8], new PropertyCollection
                {
                    new FloatProperty(radius, "ConeRadius"),
                    new FloatProperty(innerConeAngle, "ConeAngle")
                })
                {
                    ObjectName = new NameReference("DrawLightConeComponent", dlcIndex++),
                    Class      = drawLightConeComponentClass,
                    Parent     = slc.Parent,
                    Archetype  = drawInnerConeArchetype
                };
                var drawOuterCone = new ExportEntry(pcc, new byte[8], new PropertyCollection
                {
                    new FloatProperty(radius, "ConeRadius"),
                    new FloatProperty(outerConeAngle, "ConeAngle")
                })
                {
                    ObjectName = new NameReference("DrawLightConeComponent", dlcIndex++),
                    Class      = drawLightConeComponentClass,
                    Parent     = slc.Parent,
                    Archetype  = drawOuterConeArchetype
                };
                var drawLightRadius = new ExportEntry(pcc, new byte[8], new PropertyCollection {
                    new FloatProperty(radius, "SphereRadius")
                })
                {
                    ObjectName = new NameReference("DrawLightRadiusComponent", dlrIndex++),
                    Class      = drawLightRadiusComponentClass,
                    Parent     = slc.Parent,
                    Archetype  = drawLightRadiusArchetype
                };
                var drawLightSourceRadius = new ExportEntry(pcc, new byte[8], new PropertyCollection {
                    new FloatProperty(32f, "SphereRadius")
                })
                {
                    ObjectName = new NameReference("DrawLightRadiusComponent", dlrIndex++),
                    Class      = drawLightRadiusComponentClass,
                    Parent     = slc.Parent,
                    Archetype  = drawLightSourceRadiusArchetype
                };
                if (lightingChannels != null)
                {
                    drawInnerCone.WriteProperty(lightingChannels);
                    drawOuterCone.WriteProperty(lightingChannels);
                    drawLightRadius.WriteProperty(lightingChannels);
                    drawLightSourceRadius.WriteProperty(lightingChannels);
                }

                pcc.AddExport(drawInnerCone);
                pcc.AddExport(drawOuterCone);
                pcc.AddExport(drawLightRadius);
                pcc.AddExport(drawLightSourceRadius);

                slc.WriteProperty(new ObjectProperty(drawInnerCone.UIndex, "PreviewInnerCone"));
                slc.WriteProperty(new ObjectProperty(drawOuterCone.UIndex, "PreviewOuterCone"));
                slc.WriteProperty(new ObjectProperty(drawLightRadius.UIndex, "PreviewLightRadius"));
                slc.WriteProperty(new ObjectProperty(drawLightSourceRadius.UIndex, "PreviewLightSourceRadius"));
            }
        }
        private static ActorLookup GetLookupInfo(ExportEntry entry, SeqTools.VarLinkInfo varilink)
        {
            ActorLookup lookupInfo = new ActorLookup();

            if (entry.ClassName == "SeqVar_Player")
            {
                // We now look for 'Player'
                lookupInfo.FindActor = "Player";
                entry.WriteProperty(new BoolProperty(true, "bReturnPawns")); // This is required for moved links to work. So just always add it
            }
            else
            {
                if (varilink.LinkDesc.StartsWith("Node"))
                {
                    if (entry.ClassName == "BioSeqVar_ObjectFindByTag")
                    {
                        var tag = entry.GetProperty <StrProperty>("m_sObjectTagToFind");
                        if (tag != null)
                        {
                            lookupInfo.FindActor = tag.Value;
                        }
                        else
                        {
                            // ??
                            Debug.WriteLine("Could not find object by tag, tag was missing!");
                        }
                    }
                    else if (entry.ClassName == "SeqVar_Object")
                    {
                        // Pinned object.
                        var resolvedEntry = entry.GetProperty <ObjectProperty>("ObjValue")?.ResolveToEntry(entry.FileRef) as ExportEntry;
                        if (resolvedEntry != null)
                        {
                            // Look for it's tag and use that cause it's what will probably be used in the
                            // conversation
                            var tag = resolvedEntry.GetProperty <NameProperty>("Tag");
                            if (tag != null)
                            {
                                lookupInfo.FindActor = tag.Value;
                            }
                            else
                            {
                                //Debug.WriteLine("No tag on resolved object! Is it dynamic?");
                                //lookupInfo.FindActor = entry.GetProperty<NameProperty>("m_nmFindActor").Value; // keep the original value, I guess
                                lookupInfo.CouldNotResolve = true;
                            }
                        }
                        else
                        {
                            //Debug.WriteLine("Could not resolve object! Is it dynamic?");
                            //lookupInfo.FindActor = entry.GetProperty<NameProperty>("m_nmFindActor").Value; // keep the original value, I guess
                            lookupInfo.CouldNotResolve = true;
                        }
                    }
                    else if (entry.ClassName == "SeqVar_ScopedNamed")
                    {
                        // We have to find an object in the sequence that has the VarName
                        // What a dumb system
                        var findVarName = entry.GetProperty <NameProperty>("FindVarName");
                        if (findVarName == null)
                        {
                            Debugger.Break();
                        }

                        var seqObjs = SeqTools.GetAllSequenceElements(entry).OfType <ExportEntry>();
                        foreach (var seqObj in seqObjs)
                        {
                            var props   = seqObj.GetProperties();
                            var varname = props.GetProp <NameProperty>("VarName");
                            if (varname != null && varname.Value == findVarName.Value)
                            {
                                // Pinned object.
                                var resolvedEntry = props.GetProp <ObjectProperty>("ObjValue")?.ResolveToEntry(entry.FileRef) as ExportEntry;
                                if (resolvedEntry != null)
                                {
                                    // Look for it's tag and use that cause it's what will probably be used in the
                                    // conversation
                                    var tag = resolvedEntry.GetProperty <NameProperty>("Tag");
                                    if (tag != null)
                                    {
                                        lookupInfo.FindActor = tag.Value;
                                    }
                                    else
                                    {
                                        //Debug.WriteLine("No tag on resolved object! Is it dynamic?");
                                        //lookupInfo.FindActor = entry.GetProperty<NameProperty>("m_nmFindActor").Value; // keep the original value, I guess
                                        lookupInfo.CouldNotResolve = true;
                                    }
                                }
                                else
                                {
                                    //Debug.WriteLine("Could not resolve object! Is it dynamic?");
                                    //lookupInfo.FindActor = entry.GetProperty<NameProperty>("m_nmFindActor").Value; // keep the original value, I guess
                                    lookupInfo.CouldNotResolve = true;
                                }
                                break;
                            }
                        }
                    }
                    else
                    {
                        Debug.WriteLine($"Unknown type on Node convo item: {entry.ClassName}");
                    }
                }
                else
                {
                    switch (varilink.LinkDesc)
                    {
                    // We don't need to do owner as everything for Owner seems to be always pointing
                    // to the input of the SfxSeqAct_StartConversation
                    // So if we change it there, it... in theory should change
                    case "Owner":
                        lookupInfo.FindActor = "Owner";     // Special case. We should not change owner to something else. We should only update what owner now points to
                        // or something... this shit is so confusing
                        break;

                    case "Puppet1_1":
                        lookupInfo.FindActor = new NameReference("Pup1", 2);
                        lookupInfo.FindMode  = EActorTrackFindActorMode.ActorTrack_FindActorByNode;
                        break;

                    case "Puppet1_2":
                        lookupInfo.FindActor = new NameReference("Pup1", 3);
                        lookupInfo.FindMode  = EActorTrackFindActorMode.ActorTrack_FindActorByNode;
                        break;

                    case "Puppet2_1":
                        lookupInfo.FindActor = new NameReference("Pup2", 2);
                        lookupInfo.FindMode  = EActorTrackFindActorMode.ActorTrack_FindActorByNode;
                        break;

                    case "Puppet2_2":
                        lookupInfo.FindActor = new NameReference("Pup2", 3);
                        lookupInfo.FindMode  = EActorTrackFindActorMode.ActorTrack_FindActorByNode;
                        break;

                    default:
                        Debugger.Break();
                        break;
                    }
                }
            }

            return(lookupInfo);
        }
        public void CreateLiveEditFile()
        {
            string filePath = LiveFaceFxEditorFilePath;

            File.Copy(Path.Combine(App.ExecFolder, "ME3EmptyLevel.pcc"), filePath);
            LiveFile = MEPackageHandler.OpenMEPackage(filePath);
            for (int i = 0; i < LiveFile.Names.Count; i++)
            {
                if (LiveFile.Names[i].Equals("ME3EmptyLevel"))
                {
                    LiveFile.replaceName(i, Path.GetFileNameWithoutExtension(filePath));
                }
            }

            var packguid = Guid.NewGuid();
            var package  = LiveFile.GetUExport(1);

            package.PackageGUID  = packguid;
            LiveFile.PackageGuid = packguid;

            EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneAllDependencies, SourceAnimSet.Export.Parent, LiveFile, null, true, out _);

            var gender = SourceAnimSet.Export.ObjectNameString.Last() switch
            {
                'F' => FaceFXGender.Female,
                'M' => FaceFXGender.Male,
                _ => FaceFXGender.NonSpkr
            };

            ActorTag = null;
            try
            {
                if (gender is not FaceFXGender.NonSpkr)
                {
                    bool isFemale        = gender is FaceFXGender.Female;
                    var  bioConv         = LiveFile.Exports.First(exp => exp.Class.ObjectName == "BioConversation");
                    var  LiveFileAnimSet = LiveFile.FindExport(SourceAnimSet.Export.InstancedFullPath);
                    var  propName        = isFemale ? "m_aMaleFaceSets" : "m_aFemaleFaceSets";
                    int  idx             = bioConv.GetProperty <ArrayProperty <ObjectProperty> >(propName).FindIndex(objProp => objProp.Value == LiveFileAnimSet.UIndex);
                    if (idx is 0)
                    {
                        //player
                        ActorTag = $"Player_{(isFemale ? 'F' : 'M')}";
                        IEntry ent;
                        using (IMEPackage soldierFile = MEPackageHandler.OpenME3Package(Path.Combine(ME3Directory.CookedPCPath, "SFXCharacterClass_Soldier.pcc")))
                        {
                            EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneAllDependencies, soldierFile.GetUExport(isFemale ? 10327 : 10330),
                                                                 LiveFile, LiveFile.GetUExport(3), true, out ent);
                        }
                        ExportEntry actor = (ExportEntry)ent;
                        LiveFile.AddToLevelActorsIfNotThere(actor);
                        actor.WriteProperty(new NameProperty(ActorTag, "Tag"));

                        using (IMEPackage clothingFile = MEPackageHandler.OpenME3Package(Path.Combine(ME3Directory.CookedPCPath, $"BIOG_HM{(isFemale ? "F" : "M")}_ARM_CTH_R.pcc")))
                        {
                            var clothingPackage = EntryImporter.GetOrAddCrossImportOrPackage("CTHa", clothingFile, LiveFile);
                            EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneAllDependencies, clothingFile.GetUExport(isFemale ? 1625 : 1966),
                                                                 LiveFile, clothingPackage, true, out ent);
                        }

                        ExportEntry bodyComponent = LiveFile.GetUExport(actor.GetProperty <ObjectProperty>("BodyMesh").Value);
                        bodyComponent.WriteProperty(new ObjectProperty(ent.UIndex, "SkeletalMesh"));
                    }
                    else if (idx is 1)
                    {
                        //owner
                        using IMEPackage parentFile = getParentFile();
                        foreach (ExportEntry export in parentFile.Exports.Where(exp => exp.ClassName is "SFXSeqAct_StartConversation" or "SFXSeqAct_StartAmbientConv"))
                        {
                            if (export.GetProperty <ObjectProperty>("Conv") is ObjectProperty convProp && parentFile.TryGetImport(convProp.Value, out var convImport) &&
                                convImport.ObjectName == bioConv.ObjectName)
                            {
                                ExportEntry seqVar = parentFile.GetUExport(export.GetProperty <ArrayProperty <StructProperty> >("VariableLinks")[0].GetProp <ArrayProperty <ObjectProperty> >("LinkedVariables")[0].Value);
                                if (seqVar.ClassName == "BioSeqVar_ObjectFindByTag")
                                {
                                    ActorTag = seqVar.GetProperty <NameProperty>("m_sObjectTagToFind").Value;
                                    if (!ActorTag.StartsWith("hench_", StringComparison.OrdinalIgnoreCase))
                                    {
                                        importTaggedActor(parentFile);
                                    }
                                }
                                else
                                {
                                    EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneAllDependencies,
                                                                         parentFile.GetUExport(seqVar.GetProperty <ObjectProperty>("ObjValue").Value),
                                                                         LiveFile, LiveFile.GetUExport(3), true, out var ent);
                                    ExportEntry actor = (ExportEntry)ent;
                                    LiveFile.AddToLevelActorsIfNotThere(actor);
                                    ActorTag = actor.GetProperty <NameProperty>("Tag")?.Value.Name;
                                    if (ActorTag is null)
                                    {
                                        ActorTag = "ConvoOwner";
                                        actor.WriteProperty(new NameProperty(ActorTag, "Tag"));
                                    }
                                }
                                break;
                            }
                        }
                    }
                    else
                    {
                        ActorTag = bioConv.GetProperty <ArrayProperty <NameProperty> >("m_aSpeakerList")[idx - 2].Value;
                        if (!ActorTag.StartsWith("hench_", StringComparison.OrdinalIgnoreCase))
                        {
                            using IMEPackage parentFile = getParentFile();
                            importTaggedActor(parentFile);
                        }
                    }
                }
                else
                {
                    //find nonspkr linkage somehow
                }
            }
        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 void WriteObjValue(ExportEntry export, IEntry objValue)
 {
     export.WriteProperty(new ObjectProperty(objValue.UIndex, "ObjValue"));
 }
Example #9
0
        /*
         * private static void VerifyGesturesWork(ExportEntry trackExport)
         * {
         *  var gestures = RBioEvtSysTrackGesture.GetGestures(trackExport);
         *  var defaultPose = RBioEvtSysTrackGesture.GetDefaultPose(trackExport);
         *
         *  var gesturesToCheck = gestures.Append(defaultPose).ToList();
         *
         *  // Get the containing sequence
         *  var owningSequence = SeqTools.GetParentSequence(trackExport);
         *  while (owningSequence.ClassName != "Sequence")
         *  {
         *      owningSequence = owningSequence.Parent as ExportEntry;
         *      var parSeq = SeqTools.GetParentSequence(owningSequence);
         *      if (parSeq != null)
         *      {
         *          owningSequence = parSeq;
         *      }
         *  }
         *
         *  var kismetBioDynamicAnimSets = owningSequence.GetProperty<ArrayProperty<ObjectProperty>>("m_aBioDynAnimSets");
         *  if (kismetBioDynamicAnimSets == null)
         *  {
         *      // We don't have any animsets!
         *      throw new Exception("Track's sequence is missing animsets property!");
         *  }
         *
         *  // Get a list of all supported animations
         *  List<Gesture> supportedGestures = new List<Gesture>();
         *  foreach (var kbdas in kismetBioDynamicAnimSets)
         *  {
         *      var sequenceBioDynamicAnimSet = kbdas.ResolveToEntry(trackExport.FileRef) as ExportEntry; // I don't think these can be imports as they're part of the seq
         *      var associatedset = sequenceBioDynamicAnimSet.GetProperty<ObjectProperty>("m_pBioAnimSetData").ResolveToEntry(trackExport.FileRef);
         *
         *  }
         *
         *  // Check all gestures
         *  foreach (var gesture in gesturesToCheck)
         *  {
         *      var bioAnimSet = gesture.GetBioAnimSet(trackExport.FileRef);
         *
         *  }
         *
         *
         *
         * }
         *
         * internal class TestingBioDynamicAnimSet
         * {
         *  public NameReference OrigSetName { get; }
         *  public List<string> SupportedGesturesFullPaths { get; }
         *  public IEntry BioAnimSetData { get; }
         *
         *  internal TestingBioDynamicAnimSet(ExportEntry export)
         *  {
         *      var props = export.GetProperties();
         *      OrigSetName = props.GetProp<NameProperty>("m_nmOrigSetName").Value;
         *      BioAnimSetData = props.GetProp<ObjectProperty>("m_pBioAnimSetData").ResolveToEntry(export.FileRef);
         *      SupportedGesturesFullPaths = props.GetProp<ArrayProperty<ObjectProperty>>("Sequences").Select(x => x.ResolveToEntry(export.FileRef).InstancedFullPath).ToList();
         *  }
         * }
         */
        private static void InstallDynamicAnimSetRefForSeq(ref ExportEntry owningSequence, ExportEntry export, Gesture gesture)
        {
            // Find owning sequence
            if (owningSequence == null)
            {
                owningSequence = export;
            }
            while (owningSequence.ClassName != "Sequence")
            {
                owningSequence = owningSequence.Parent as ExportEntry;
                var parSeq = SeqTools.GetParentSequence(owningSequence);
                if (parSeq != null)
                {
                    owningSequence = parSeq;
                }
            }

            // We have parent sequence data
            var kismetBioDynamicAnimSets = owningSequence.GetProperty <ArrayProperty <ObjectProperty> >("m_aBioDynAnimSets")
                                           ?? new ArrayProperty <ObjectProperty>("m_aBioDynamicAnimSets");

            // Check to see if there is any item that uses our bioanimset
            var bioAnimSet = gesture.GetBioAnimSet(export.FileRef);

            if (bioAnimSet != null)
            {
                ExportEntry kismetBDAS = null;
                foreach (var kbdas in kismetBioDynamicAnimSets)
                {
                    var kEntry        = kbdas.ResolveToEntry(export.FileRef) as ExportEntry; // I don't think these can be imports as they're part of the seq
                    var associatedset = kEntry.GetProperty <ObjectProperty>("m_pBioAnimSetData").ResolveToEntry(export.FileRef);
                    if (associatedset == bioAnimSet)
                    {
                        // It's this one
                        kismetBDAS = kEntry;
                        break;
                    }
                }

                if (kismetBDAS == null)
                {
                    // We need to generate a new one
                    PropertyCollection props = new PropertyCollection();
                    props.Add(new NameProperty(gesture.GestureSet, "m_nmOrigSetName"));
                    props.Add(new ArrayProperty <ObjectProperty>("Sequences"));
                    props.Add(new ObjectProperty(bioAnimSet, "m_pBioAnimSetData"));
                    kismetBDAS            = ExportCreator.CreateExport(export.FileRef, $"KIS_DYN_{gesture.GestureSet}", "BioDynamicAnimSet", owningSequence);
                    kismetBDAS.indexValue = 0;

                    // Write a blank count of 0 - we will update this in subsequent call
                    // This must be here to ensure parser can read it
                    kismetBDAS.WritePropertiesAndBinary(props, new byte[4]);
                    kismetBioDynamicAnimSets.Add(new ObjectProperty(kismetBDAS)); // Add new export to sequence's list of biodynamicanimsets
                    owningSequence.WriteProperty(kismetBioDynamicAnimSets);
                }

                var currentObjs = kismetBDAS.GetProperty <ArrayProperty <ObjectProperty> >("Sequences");
                if (currentObjs.All(x => x.Value != gesture.Entry.UIndex))
                {
                    // We need to add our item to it
                    currentObjs.Add(new ObjectProperty(gesture.Entry));
                    var bin = ObjectBinary.From <BioDynamicAnimSet>(kismetBDAS);
                    bin.SequenceNamesToUnkMap[gesture.GestureAnim] = 1; // Not sure what the value should be, or if game actually reads this
                    // FIX IT IF WE EVER FIGURE IT OUT!
                    kismetBDAS.WriteProperty(currentObjs);
                    kismetBDAS.WriteBinary(bin);
                }
            }
        }
Example #10
0
 public static void SetLocation(ExportEntry export, float x, float y, float z)
 {
     export.WriteProperty(CommonStructs.Vector3(x, y, z, "location"));
 }
Example #11
0
        public static void RunGame2EmailMerge(GameTarget target)
        {
            M3MergeDLC.RemoveMergeDLC(target);
            var loadedFiles = MELoadedFiles.GetFilesLoadedInGame(target.Game, gameRootOverride: target.TargetPath);

            // File to base modifications on
            using IMEPackage pcc = MEPackageHandler.OpenMEPackage(loadedFiles[@"BioD_Nor103_Messages.pcc"]);

            // Path to Message templates file - different files for ME2/LE2
            string ResourcesFilePath = $@"MassEffectModManagerCore.modmanager.emailmerge.{target.Game}.103Message_Template_{target.Game}";

            using IMEPackage resources = MEPackageHandler.OpenMEPackageFromStream(Utilities.GetResourceStream(ResourcesFilePath));

            // Startup file to place conditionals and transitions into
            using IMEPackage startup = MEPackageHandler.OpenMEPackageFromStream(Utilities.GetResourceStream(
                                                                                    $@"MassEffectModManagerCore.modmanager.mergedlc.{target.Game}.Startup_{M3MergeDLC.MERGE_DLC_FOLDERNAME}.pcc"));


            var emailInfos        = new List <ME2EmailMergeFile>();
            var jsonSupercedances = M3Directories.GetFileSupercedances(target, new[] { @".json" });

            if (jsonSupercedances.TryGetValue(EMAIL_MERGE_MANIFEST_FILE, out var jsonList))
            {
                jsonList.Reverse();
                foreach (var dlc in jsonList)
                {
                    var jsonFile = Path.Combine(M3Directories.GetDLCPath(target), dlc, target.Game.CookedDirName(),
                                                EMAIL_MERGE_MANIFEST_FILE);
                    emailInfos.Add(JsonConvert.DeserializeObject <ME2EmailMergeFile>(File.ReadAllText(jsonFile)));
                }
            }

            // Sanity checks
            if (!emailInfos.Any() || !emailInfos.SelectMany(e => e.Emails).Any())
            {
                return;
            }

            if (emailInfos.Any(e => e.Game != target.Game))
            {
                throw new Exception("ME2 email merge manifest targets incorrect game");
            }

            // Startup File
            // Could replace this with full instanced path in M3 implementation
            ExportEntry stateEventMapExport = startup.Exports
                                              .First(e => e.ClassName == "BioStateEventMap" && e.ObjectName == "StateTransitionMap");
            BioStateEventMap StateEventMap    = stateEventMapExport.GetBinaryData <BioStateEventMap>();
            ExportEntry      ConditionalClass =
                startup.FindExport($@"PlotManager{M3MergeDLC.MERGE_DLC_FOLDERNAME}.BioAutoConditionals");

            #region Sequence Exports
            // Send message - All email conditionals are checked and emails transitions are triggered
            ExportEntry SendMessageContainer = pcc.FindExport(@"TheWorld.PersistentLevel.Main_Sequence.Send_Messages");
            ExportEntry LastSendMessage      = KismetHelper.GetSequenceObjects(SendMessageContainer).OfType <ExportEntry>()
                                               .FirstOrDefault(e =>
            {
                var outbound = KismetHelper.GetOutboundLinksOfNode(e);
                return(outbound.Count == 1 && outbound[0].Count == 0);
            });
            ExportEntry TemplateSendMessage          = resources.FindExport(@"TheWorld.PersistentLevel.Main_Sequence.Send_MessageTemplate");
            ExportEntry TemplateSendMessageBoolCheck = resources.FindExport(@"TheWorld.PersistentLevel.Main_Sequence.Send_MessageTemplate_BoolCheck");


            // Mark Read - email ints are set to read
            // This is the only section that does not gracefully handle different DLC installations - DLC_CER is required atm
            ExportEntry MarkReadContainer = pcc.FindExport(@"TheWorld.PersistentLevel.Main_Sequence.Mark_Read");
            ExportEntry LastMarkRead      = pcc.FindExport(@"TheWorld.PersistentLevel.Main_Sequence.Mark_Read.DLC_CER");
            ExportEntry MarkReadOutLink   = KismetHelper.GetOutboundLinksOfNode(LastMarkRead)[0][0].LinkedOp as ExportEntry;
            KismetHelper.RemoveOutputLinks(LastMarkRead);

            ExportEntry TemplateMarkRead           = resources.FindExport(@"TheWorld.PersistentLevel.Main_Sequence.Mark_ReadTemplate");
            ExportEntry TemplateMarkReadTransition = resources.FindExport(@"TheWorld.PersistentLevel.Main_Sequence.Mark_Read_Transition");


            // Display Messages - Str refs are passed through to GUI
            ExportEntry DisplayMessageContainer =
                pcc.FindExport(@"TheWorld.PersistentLevel.Main_Sequence.Display_Messages");
            ExportEntry DisplayMessageOutLink =
                pcc.FindExport(@"TheWorld.PersistentLevel.Main_Sequence.Display_Messages.SeqCond_CompareBool_0");

            ExportEntry LastDisplayMessage = SeqTools.FindOutboundConnectionsToNode(DisplayMessageOutLink, KismetHelper.GetSequenceObjects(DisplayMessageContainer).OfType <ExportEntry>())[0];
            KismetHelper.RemoveOutputLinks(LastDisplayMessage);
            var         DisplayMessageVariableLinks = LastDisplayMessage.GetProperty <ArrayProperty <StructProperty> >("VariableLinks");
            ExportEntry TemplateDisplayMessage      =
                resources.FindExport(@"TheWorld.PersistentLevel.Main_Sequence.Display_MessageTemplate");

            // Archive Messages - Message ints are set to 3
            ExportEntry ArchiveContainer = pcc.FindExport(@"TheWorld.PersistentLevel.Main_Sequence.Archive_Message");
            ExportEntry ArchiveSwitch    = pcc.FindExport(@"TheWorld.PersistentLevel.Main_Sequence.Archive_Message.SeqAct_Switch_0");
            ExportEntry ArchiveOutLink   =
                pcc.FindExport(
                    @"TheWorld.PersistentLevel.Main_Sequence.Archive_Message.BioSeqAct_PMCheckConditional_1");
            ExportEntry ExampleSetInt  = KismetHelper.GetOutboundLinksOfNode(ArchiveSwitch)[0][0].LinkedOp as ExportEntry;
            ExportEntry ExamplePlotInt = SeqTools.GetVariableLinksOfNode(ExampleSetInt)[0].LinkedNodes[0] as ExportEntry;
            #endregion

            int messageID      = KismetHelper.GetOutboundLinksOfNode(ArchiveSwitch).Count + 1;
            int currentSwCount = ArchiveSwitch.GetProperty <IntProperty>("LinkCount").Value;

            foreach (var emailMod in emailInfos)
            {
                string modName = "DLC_MOD_" + emailMod.ModName;

                foreach (var email in emailMod.Emails)
                {
                    string emailName = modName + "_" + email.EmailName;

                    // Create send transition
                    int transitionId  = WriteTransition(StateEventMap, email.StatusPlotInt);
                    int conditionalId = WriteConditional(email.TriggerConditional);

                    #region SendMessage
                    //////////////
                    // SendMessage
                    //////////////

                    // Create seq object
                    var SMTemp = emailMod.InMemoryBool.HasValue ? TemplateSendMessageBoolCheck : TemplateSendMessage;
                    EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneTreeAsChild,
                                                         SMTemp, pcc, SendMessageContainer, true, new RelinkerOptionsPackage(), out var outSendEntry);

                    var newSend = outSendEntry as ExportEntry;

                    // Set name, comment, add to sequence
                    newSend.ObjectName = new NameReference(emailName);
                    KismetHelper.AddObjectToSequence(newSend, SendMessageContainer);
                    KismetHelper.SetComment(newSend, emailName);
                    if (target.Game == MEGame.ME2)
                    {
                        newSend.WriteProperty(new StrProperty(emailName, "ObjName"));
                    }

                    // Set Trigger Conditional
                    var pmCheckConditionalSM = newSend.GetChildren()
                                               .FirstOrDefault(e => e.ClassName == "BioSeqAct_PMCheckConditional" && e is ExportEntry);
                    if (pmCheckConditionalSM is ExportEntry conditional)
                    {
                        conditional.WriteProperty(new IntProperty(conditionalId, "m_nIndex"));
                        KismetHelper.SetComment(conditional, "Time for " + email.EmailName + "?");
                    }

                    // Set Send Transition
                    var pmExecuteTransitionSM = newSend.GetChildren()
                                                .FirstOrDefault(e => e.ClassName == "BioSeqAct_PMExecuteTransition" && e is ExportEntry);
                    if (pmExecuteTransitionSM is ExportEntry transition)
                    {
                        transition.WriteProperty(new IntProperty(transitionId, "m_nIndex"));
                        KismetHelper.SetComment(transition, "Send " + email.EmailName + " message.");
                    }

                    // Set Send Transition
                    if (emailMod.InMemoryBool.HasValue)
                    {
                        var pmCheckStateSM = newSend.GetChildren()
                                             .FirstOrDefault(e => e.ClassName == "BioSeqAct_PMCheckState" && e is ExportEntry);
                        if (pmCheckStateSM is ExportEntry checkState)
                        {
                            checkState.WriteProperty(new IntProperty(emailMod.InMemoryBool.Value, "m_nIndex"));
                            KismetHelper.SetComment(checkState, "Is " + emailMod.ModName + " installed?");
                        }
                    }

                    // Hook up output links
                    KismetHelper.CreateOutputLink(LastSendMessage, "Out", newSend);
                    LastSendMessage = newSend;
                    #endregion

                    #region MarkRead
                    ///////////
                    // MarkRead
                    ///////////

                    // Create seq object
                    var MRTemp = email.ReadTransition.HasValue ? TemplateMarkReadTransition : TemplateMarkRead;
                    EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneTreeAsChild,
                                                         MRTemp, pcc, MarkReadContainer, true, new RelinkerOptionsPackage(), out var outMarkReadEntry);
                    var newMarkRead = outMarkReadEntry as ExportEntry;

                    // Set name, comment, add to sequence
                    newMarkRead.ObjectName = new NameReference(emailName);
                    KismetHelper.AddObjectToSequence(newMarkRead, MarkReadContainer);
                    KismetHelper.SetComment(newMarkRead, emailName);
                    if (target.Game == MEGame.ME2)
                    {
                        newMarkRead.WriteProperty(new StrProperty(emailName, "ObjName"));
                    }

                    // Set Plot Int
                    var storyManagerIntMR = newMarkRead.GetChildren()
                                            .FirstOrDefault(e => e.ClassName == "BioSeqVar_StoryManagerInt" && e is ExportEntry);
                    if (storyManagerIntMR is ExportEntry plotIntMR)
                    {
                        plotIntMR.WriteProperty(new IntProperty(email.StatusPlotInt, "m_nIndex"));
                        KismetHelper.SetComment(plotIntMR, email.EmailName);
                    }

                    if (email.ReadTransition.HasValue)
                    {
                        var pmExecuteTransitionMR = newMarkRead.GetChildren()
                                                    .FirstOrDefault(e => e.ClassName == "BioSeqAct_PMExecuteTransition" && e is ExportEntry);
                        if (pmExecuteTransitionMR is ExportEntry transitionMR)
                        {
                            transitionMR.WriteProperty(new IntProperty(email.ReadTransition.Value, "m_nIndex"));
                            KismetHelper.SetComment(transitionMR, "Trigger " + email.EmailName + " read transition");
                        }
                    }

                    // Hook up output links
                    KismetHelper.CreateOutputLink(LastMarkRead, "Out", newMarkRead);
                    LastMarkRead = newMarkRead;
                    #endregion

                    #region DisplayEmail
                    ////////////////
                    // Display Email
                    ////////////////

                    // Create seq object
                    EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneTreeAsChild,
                                                         TemplateDisplayMessage, pcc, DisplayMessageContainer, true, new RelinkerOptionsPackage(), out var outDisplayMessage);
                    var newDisplayMessage = outDisplayMessage as ExportEntry;

                    // Set name, comment, variable links, add to sequence
                    newDisplayMessage.ObjectName = new NameReference(emailName);
                    KismetHelper.AddObjectToSequence(newDisplayMessage, DisplayMessageContainer);
                    newDisplayMessage.WriteProperty(DisplayMessageVariableLinks);
                    KismetHelper.SetComment(newDisplayMessage, emailName);
                    if (target.Game == MEGame.ME2)
                    {
                        newDisplayMessage.WriteProperty(new StrProperty(emailName, "ObjName"));
                    }

                    var displayChildren = newDisplayMessage.GetChildren();

                    // Set Plot Int
                    var storyManagerIntDE = displayChildren.FirstOrDefault(e =>
                                                                           e.ClassName == "BioSeqVar_StoryManagerInt" && e is ExportEntry);
                    if (storyManagerIntDE is ExportEntry plotIntDE)
                    {
                        plotIntDE.WriteProperty(new IntProperty(email.StatusPlotInt, "m_nIndex"));
                    }

                    // Set Email ID
                    var emailIdDE = displayChildren.FirstOrDefault(e =>
                                                                   e.ClassName == "SeqVar_Int" && e is ExportEntry);
                    if (emailIdDE is ExportEntry EmailIDDE)
                    {
                        EmailIDDE.WriteProperty(new IntProperty(messageID, "IntValue"));
                    }

                    // Set Title StrRef
                    var titleStrRef = displayChildren.FirstOrDefault(e =>
                                                                     e.ClassName == "BioSeqVar_StrRef" && e is ExportEntry ee && ee.GetProperty <NameProperty>("VarName").Value == "Title StrRef");
                    if (titleStrRef is ExportEntry Title)
                    {
                        Title.WriteProperty(new StringRefProperty(email.TitleStrRef, "m_srValue"));
                    }

                    // Set Description StrRef
                    var descStrRef = displayChildren.FirstOrDefault(e =>
                                                                    e.ClassName == "BioSeqVar_StrRef" && e is ExportEntry ee && ee.GetProperty <NameProperty>("VarName").Value == "Desc StrRef");
                    if (descStrRef is ExportEntry Desc)
                    {
                        Desc.WriteProperty(new StringRefProperty(email.DescStrRef, "m_srValue"));
                    }

                    // Hook up output links
                    KismetHelper.CreateOutputLink(LastDisplayMessage, "Out", newDisplayMessage);
                    LastDisplayMessage = newDisplayMessage;
                    #endregion

                    #region ArchiveEmail
                    ////////////////
                    // Archive Email
                    ////////////////

                    var NewSetInt = EntryCloner.CloneEntry(ExampleSetInt);
                    KismetHelper.AddObjectToSequence(NewSetInt, ArchiveContainer);
                    KismetHelper.CreateOutputLink(NewSetInt, "Out", ArchiveOutLink);

                    KismetHelper.CreateNewOutputLink(ArchiveSwitch, "Link " + (messageID - 1), NewSetInt);

                    var NewPlotInt = EntryCloner.CloneEntry(ExamplePlotInt);
                    KismetHelper.AddObjectToSequence(NewPlotInt, ArchiveContainer);
                    NewPlotInt.WriteProperty(new IntProperty(email.StatusPlotInt, "m_nIndex"));
                    NewPlotInt.WriteProperty(new StrProperty(emailName, "m_sRefName"));

                    var linkedVars = SeqTools.GetVariableLinksOfNode(NewSetInt);
                    linkedVars[0].LinkedNodes = new List <IEntry>()
                    {
                        NewPlotInt
                    };
                    SeqTools.WriteVariableLinksToNode(NewSetInt, linkedVars);

                    messageID++;
                    currentSwCount++;
                    #endregion
                }
            }
            KismetHelper.CreateOutputLink(LastMarkRead, "Out", MarkReadOutLink);
            KismetHelper.CreateOutputLink(LastDisplayMessage, "Out", DisplayMessageOutLink);
            ArchiveSwitch.WriteProperty(new IntProperty(currentSwCount, "LinkCount"));

            stateEventMapExport.WriteBinary(StateEventMap);

            // Save Messages file into DLC
            var cookedDir   = Path.Combine(M3Directories.GetDLCPath(target), M3MergeDLC.MERGE_DLC_FOLDERNAME, target.Game.CookedDirName());
            var outMessages = Path.Combine(cookedDir, @"BioD_Nor103_Messages.pcc");
            pcc.Save(outMessages);

            // Save Startup file into DLC
            var startupF = Path.Combine(cookedDir, $@"Startup_{M3MergeDLC.MERGE_DLC_FOLDERNAME}.pcc");
            startup.Save(startupF);
        }
        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);
        }
Example #13
0
 private static void RandSeqVarInt(ExportEntry export, int min, int max)
 {
     export.WriteProperty(new IntProperty(ThreadSafeRandom.Next(min, max), "IntValue"));
 }
Example #14
0
        public static bool RandomizeExport(ExportEntry export, RandomizationOption option)
        {
            if (!CanRandomize(export))
            {
                return(false);
            }
            //build groups
            //var props = export.GetProperties();
            var trackBoneNames = export.GetProperty <ArrayProperty <NameProperty> >("TrackBoneNames");

            if (trackBoneNames != null)
            {
                // Test first if we should randomize based on the option.
                //int max = option.SliderValue switch
                //{
                //    MODERATE_RANDOM => 8,
                //    HIGH_RANDOM => 4,
                //    VERY_RANDOM => 3,
                //    ALL_RANDOM => 1,
                //    _ => 10
                //};

                //if (ThreadSafeRandom.Next(max) != 0) return false; // Skip this pass!

                // We should randomize this pass
                if (option.SliderValue == ALL_RANDOM)
                {
                    // Randomize everything. This will probably entirely ruin it, but why not.
                    trackBoneNames.Shuffle();
                }
                else if (option.SliderValue == VERY_RANDOM)
                {
                    // Index => New Value at that index
                    SwapRandomBones(10, trackBoneNames);
                }
                else
                {
                    var randomizationGroups = new Dictionary <string, List <string> >();

                    List <string> shuffledItems = new List <string>(); // Items that cannot be added to the > Basic Randomizer pass.
                    var           groups        = basicBoneGroups;
                    if (option.SliderValue >= MODERATE_RANDOM)
                    {
                        groups = advancedBoneGroups;
                    }
                    // GROUP RANDOMIZER -------------------
                    foreach (var key in groups)
                    {
                        var keysP1 = trackBoneNames.Where(x => x.Value.Name.Contains(key, StringComparison.InvariantCultureIgnoreCase)).ToList();
                        randomizationGroups[key] = keysP1.Select(x => x.Value.Name).ToList();
                        shuffledItems.AddRange(randomizationGroups[key]);
                        randomizationGroups[key].Shuffle();
                    }

                    if (shuffledItems.Any())
                    {
                        // For every bone in the track bones...
                        foreach (var prop in trackBoneNames)
                        {
                            // Get the name of the bone
                            var propname = prop.Value.Name;

                            // Get the key of the bone to the list of keys it can map to that contain the key... (?)
                            var randoKey = randomizationGroups.Keys.FirstOrDefault(x => propname.Contains(x, StringComparison.InvariantCultureIgnoreCase));
                            //Debug.WriteLine(propname);
                            if (randoKey != null)
                            {
                                var randoKeyList = randomizationGroups[randoKey];
                                prop.Value = randoKeyList[0];
                                randoKeyList.RemoveAt(0);
                            }
                        } // ----------------------------------
                    }

                    // > BASIC RANDOMIZER
                    int numAdditionalToSwap = option.SliderValue switch
                    {
                        HIGH_RANDOM => 3,
                        _ => 0
                        // The other cases are handled above in a diff if statement block
                    };
                    SwapRandomBones(numAdditionalToSwap, trackBoneNames);
                }

                export.WriteProperty(trackBoneNames);
                return(true);
            }

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

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

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

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

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

                    export.WriteProperty(variableLinks);
                    if (export.EntryHasPendingChanges)
                    {
                        break;
                    }
                }
                return(true);
            }
            return(false);
        }
        public void serializeTalkfileToExport(ExportEntry export, bool savePackage = false)
        {
            /* converts Huffmann Tree to binary form */
            byte[] treeBuffer = ConvertHuffmanTreeToBuffer();

            var encodedStrings = new List <EncodedString>();
            int i = 0;

            foreach (var entry in _inputData)
            {
                if (entry.Flags == 0)
                {
                    if (entry.StringID > 0)
                    {
                        entry.Index = -1;
                    }
                    else
                    {
                        entry.Index = 0;
                    }
                }
                else
                {
                    entry.Index = i;
                    i++;
                    var binaryData   = new List <BitArray>();
                    int binaryLength = 0;

                    /* for every character in a string, put it's binary code into data array */
                    foreach (char c in entry.ASCIIData)
                    {
                        binaryData.Add(_huffmanCodes[c]);
                        binaryLength += _huffmanCodes[c].Count;
                    }
                    byte[] buffer = BitArrayListToByteArray(binaryData, binaryLength);
                    encodedStrings.Add(new EncodedString(entry.ASCIIData.Length, buffer.Length, buffer));
                }
            }


            /* writing properties */
            export.WriteProperty(new IntProperty(_inputData.Count, "m_nHashTableSize"));

            MemoryStream m = new MemoryStream();

            /* writing entries */
            m.Write(BitConverter.GetBytes(_inputData.Count), 0, 4);
            foreach (TLKStringRef entry in _inputData)
            {
                m.Write(BitConverter.GetBytes(entry.StringID), 0, 4);
                m.Write(BitConverter.GetBytes(entry.Flags), 0, 4);
                m.Write(BitConverter.GetBytes(entry.Index), 0, 4);
            }

            /* writing HuffmanTree */
            m.Write(treeBuffer, 0, treeBuffer.Length);

            /* writing data */
            m.Write(BitConverter.GetBytes(encodedStrings.Count), 0, 4);
            foreach (EncodedString enc in encodedStrings)
            {
                m.Write(BitConverter.GetBytes(enc.stringLength), 0, 4);
                m.Write(BitConverter.GetBytes(enc.encodedLength), 0, 4);
                m.Write(enc.binaryData, 0, enc.encodedLength);
            }

            byte[] buff = m.ToArray();
            export.WriteBinary(buff);
            if (savePackage)
            {
                export.FileRef.Save(export.FileRef.FilePath);
            }
        }
 public static void WriteOriginator(ExportEntry export, IEntry originator)
 {
     export.WriteProperty(new ObjectProperty(originator.UIndex, "Originator"));
 }