Exemple #1
0
        public static bool AttemptMerge(IMEPackage vanillaPackage, IMEPackage modifiedVanillaPackage, IMEPackage targetPackage)
        {
            PackageDelta vanillaToModifiedDelta = PackageDelta.CalculateDelta(vanillaPackage, modifiedVanillaPackage);
            PackageDelta vanillaToTargetDelta   = PackageDelta.CalculateDelta(vanillaPackage, targetPackage);
            string       loggingPrefix          = File.Exists(targetPackage.FilePath) ? Path.GetFileName(targetPackage.FilePath) : targetPackage.FilePath;
            //Check merge conditions
            var nameConflicts   = vanillaToModifiedDelta.NameDeltas.Keys.Intersect(vanillaToTargetDelta.NameDeltas.Keys).ToList();
            var importConflicts = vanillaToModifiedDelta.ImportDeltas.Keys.Intersect(vanillaToTargetDelta.ImportDeltas.Keys).ToList();
            var exportConflicts = vanillaToModifiedDelta.ExportDeltas.Keys.Intersect(vanillaToTargetDelta.ExportDeltas.Keys).ToList();

            Log.Information($@"[{loggingPrefix}] Performing three way merge pre-check");
            //Name deltas

            if (nameConflicts.Count > 0)
            {
                //need to check if the conflicts result in same value, in this case it would not be a conflict.
                foreach (int nameIndex in nameConflicts)
                {
                    var modifiedName = modifiedVanillaPackage.Names[nameIndex];
                    var targetName   = targetPackage.Names[nameIndex];
                    if (modifiedName != targetName)
                    {
                        //Differing names in same spots.
                        Log.Information($@"[{loggingPrefix}] Cannot merge files: Name index {nameIndex} is different between modified and target.");
                        return(false);
                    }
                }
            }

            if (importConflicts.Count > 0)
            {
                //todo
            }

            if (exportConflicts.Count > 0)
            {
                //hmm... this will be a tough one.
                foreach (int exportTableIndex in exportConflicts)
                {
                    //we will have to check sizes if we ever hope to have way to merge this
                    var modifiedData = modifiedVanillaPackage.Exports[exportTableIndex].Data;
                    var targetData   = targetPackage.Exports[exportTableIndex].Data;

                    if (!modifiedData.SequenceEqual(targetData))
                    {
                        Log.Information($@"[{loggingPrefix}] Cannot merge files: Export table index {exportTableIndex} data is different between modified and target.");
                        return(false);
                    }

                    //We will have to ignore size here somehow...
                    //var modifiedHeader = modifiedVanillaPackage.Exports[exportTableIndex].Header;
                    //var targetHeader = targetPackage.Exports[exportTableIndex].Header;
                }
            }

            //Merge is OK to perform
            //Apply vanilla to modified delta to target package
            foreach (var nameDelta in vanillaToModifiedDelta.NameDeltas)
            {
                if (nameDelta.Key >= targetPackage.NameCount)
                {
                    //add it
                    Log.Information($@"[{loggingPrefix}] Adding name {nameDelta.Value}");
                    targetPackage.FindNameOrAdd(nameDelta.Value);
                }
                else
                {
                    Log.Information($@"[{loggingPrefix}] Updating name index {nameDelta.Key} to {nameDelta.Value}");
                    targetPackage.replaceName(nameDelta.Key, nameDelta.Value);
                }
            }

            foreach (var exportDelta in vanillaToModifiedDelta.ExportDeltas)
            {
                if (exportDelta.Key >= targetPackage.ExportCount)
                {
                    //add it
                    Log.Information($@"[{loggingPrefix}] Adding export {exportDelta.Value.InstancedFullPath}");
                    targetPackage.AddExport(exportDelta.Value); //not sure if this is possible
                }
                else
                {
                    //gonna need this reviewed, not entirely sure this is OK to do
                    Log.Information($@"[{loggingPrefix}] Updating export {exportDelta.Value.InstancedFullPath}");

                    targetPackage.Exports[exportDelta.Key].Data   = exportDelta.Value.Data;
                    targetPackage.Exports[exportDelta.Key].Header = exportDelta.Value.Header;
                }
            }

            foreach (var importDelta in vanillaToModifiedDelta.ImportDeltas)
            {
                if (importDelta.Key >= targetPackage.ImportCount)
                {
                    //add it
                    Log.Information($@"[{loggingPrefix}] Adding import {importDelta.Value.InstancedFullPath}");

                    targetPackage.AddImport(importDelta.Value); //not sure if this is possible
                }
                else
                {
                    Log.Information($@"[{loggingPrefix}] Updating import {importDelta.Value.InstancedFullPath}");

                    //gonna need this reviewed, not entirely sure this is OK to do
                    //targetPackage.Imports[importDelta.Key].Data = importDelta.Value.Data;
                    targetPackage.Imports[importDelta.Key].Header = importDelta.Value.Header;
                }
            }

            Log.Information($@"[{loggingPrefix}] Finished three way merge");
            return(true);
        }
        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
                }
            }