/// <summary> /// Trashes an entry. /// </summary> /// <param name="entry">Entry to trash</param> /// <param name="trashContainer">Container for trash. Pass null if you want to create the trash container from the passed in value.</param> /// <param name="packageClassIdx">Idx for package class. Prevents multiple calls to find it</param> /// <returns>New trash container, otherwise will be null</returns> public static ExportEntry TrashEntry(IEntry entry, ExportEntry trashContainer, int packageClassIdx) { IMEPackage pcc = entry.FileRef; if (entry is ImportEntry imp) { if (trashContainer == null) { trashContainer = TrashEntry(new ExportEntry(pcc), null, packageClassIdx); pcc.addExport(trashContainer); trashContainer.indexValue = 0; } imp.idxClassName = pcc.FindNameOrAdd("Package"); imp.idxPackageFile = pcc.FindNameOrAdd("Core"); imp.idxLink = trashContainer.UIndex; imp.idxObjectName = pcc.FindNameOrAdd("Trash"); imp.indexValue = 0; } else if (entry is ExportEntry exp) { MemoryStream trashData = new MemoryStream(); trashData.WriteInt32(-1); trashData.WriteInt32(pcc.findName("None")); trashData.WriteInt32(0); exp.Data = trashData.ToArray(); exp.idxArchtype = 0; exp.idxSuperClass = 0; exp.indexValue = 0; exp.idxClass = packageClassIdx; exp.ObjectFlags &= ~UnrealFlags.EObjectFlags.HasStack; if (trashContainer == null) { exp.idxObjectName = pcc.FindNameOrAdd(UnrealPackageFile.TrashPackageName); exp.idxLink = 0; if (exp.idxLink == exp.UIndex) { Debugger.Break(); } exp.PackageGUID = UnrealPackageFile.TrashPackageGuid; trashContainer = exp; } else { exp.idxLink = trashContainer.UIndex; if (exp.idxLink == exp.UIndex) { //This should not occur Debugger.Break(); } exp.idxObjectName = pcc.FindNameOrAdd("Trash"); exp.PackageGUID = Guid.Empty; } } return(trashContainer); }
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); } } }
/// <summary> /// Imports an export from another package file. /// </summary> /// <param name="mePackage"></param> /// <param name="ex">Export object from the other package to import</param> /// <param name="link">Local parent node UIndex</param> /// <param name="outputEntry">Newly generated export entry reference</param> /// <returns></returns> private static bool importExport(IMEPackage mePackage, ExportEntry ex, int link, out ExportEntry outputEntry) { byte[] prePropBinary; if (ex.HasStack) { if (mePackage.Game < MEGame.ME3) { prePropBinary = new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00 }; } else { prePropBinary = new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00 }; } } else { int start = ex.GetPropertyStart(); prePropBinary = new byte[start]; } PropertyCollection props = ex.GetProperties(); //store copy of names list in case something goes wrong List <string> names = mePackage.Names.ToList(); try { if (ex.Game != mePackage.Game) { props = EntryPruner.RemoveIncompatibleProperties(ex.FileRef, props, ex.ClassName, mePackage.Game); } } catch (Exception exception) { //restore namelist in event of failure. mePackage.setNames(names); Console.WriteLine($"Error occured while trying to import {ex.ObjectName} : {exception.Message}"); //MessageBox.Show($"Error occured while trying to import {ex.ObjectName} : {exception.Message}"); outputEntry = null; return(false); } //takes care of slight header differences between ME1/2 and ME3 byte[] newHeader = ex.GenerateHeader(mePackage.Game); //for supported classes, this will add any names in binary to the Name table, as well as take care of binary differences for cross-game importing //for unsupported classes, this will just copy over the binary byte[] binaryData = ExportBinaryConverter.ConvertPostPropBinary(ex, mePackage.Game).ToArray(mePackage); int classValue = 0; int archetype = 0; int superclass = 0; //Set class. This will only work if the class is an import, as we can't reliably pull in exports without lots of other stuff. if (ex.idxClass < 0) { //The class of the export we are importing is an import. We should attempt to relink this. ImportEntry portingFromClassImport = ex.FileRef.getImport(ex.idxClass); IEntry newClassImport = getOrAddCrossImportOrPackage(portingFromClassImport.GetFullPath, ex.FileRef, mePackage); classValue = newClassImport.UIndex; } else if (ex.idxClass > 0) { //Todo: Add cross mapping support as multi-mode will allow this to work now ExportEntry portingInClass = ex.FileRef.getUExport(ex.idxClass); ExportEntry matchingExport = mePackage.Exports.FirstOrDefault(x => x.GetIndexedFullPath == portingInClass.GetIndexedFullPath); if (matchingExport != null) { classValue = matchingExport.UIndex; } } //Set superclass if (ex.idxSuperClass < 0) { //The class of the export we are importing is an import. We should attempt to relink this. ImportEntry portingFromClassImport = ex.FileRef.getImport(ex.idxSuperClass); IEntry newClassImport = getOrAddCrossImportOrPackage(portingFromClassImport.GetFullPath, ex.FileRef, mePackage); superclass = newClassImport.UIndex; } else if (ex.idxSuperClass > 0) { //Todo: Add cross mapping support as multi-mode will allow this to work now ExportEntry portingInClass = ex.FileRef.getUExport(ex.idxSuperClass); ExportEntry matchingExport = mePackage.Exports.FirstOrDefault(x => x.GetIndexedFullPath == portingInClass.GetIndexedFullPath); if (matchingExport != null) { superclass = matchingExport.UIndex; } } //Check archetype. if (ex.idxArchtype < 0) { ImportEntry portingFromClassImport = ex.FileRef.getImport(ex.idxArchtype); IEntry newClassImport = getOrAddCrossImportOrPackage(portingFromClassImport.GetFullPath, ex.FileRef, mePackage); archetype = newClassImport.UIndex; } else if (ex.idxArchtype > 0) { ExportEntry portingInClass = ex.FileRef.getUExport(ex.idxArchtype); ExportEntry matchingExport = mePackage.Exports.FirstOrDefault(x => x.GetIndexedFullPath == portingInClass.GetIndexedFullPath); if (matchingExport != null) { archetype = matchingExport.UIndex; } } outputEntry = new ExportEntry(mePackage, prePropBinary, props, binaryData) { Header = newHeader, idxClass = classValue, idxObjectName = mePackage.FindNameOrAdd(ex.FileRef.getNameEntry(ex.idxObjectName)), idxLink = link, idxSuperClass = superclass, idxArchtype = archetype }; mePackage.addExport(outputEntry); return(true); }