public static List <EntryStringPair> Relink(ExportEntry sourceExport, ExportEntry relinkingExport, OrderedMultiValueDictionary <IEntry, IEntry> crossPCCObjectMappingList, bool importExportDependencies = false, RelinkerCache relinkerCache = null) { var relinkFailedReport = new List <EntryStringPair>(); IMEPackage sourcePcc = sourceExport.FileRef; byte[] prePropBinary = relinkingExport.GetPrePropBinary(); //Relink stack if (relinkingExport.HasStack) { int uIndex = BitConverter.ToInt32(prePropBinary, 0); var relinkResult = relinkUIndex(sourceExport.FileRef, relinkingExport, ref uIndex, "Stack: Node", crossPCCObjectMappingList, "", importExportDependencies, relinkerCache); if (relinkResult is null) { prePropBinary.OverwriteRange(0, BitConverter.GetBytes(uIndex)); } else { relinkFailedReport.Add(relinkResult); } uIndex = BitConverter.ToInt32(prePropBinary, 4); relinkResult = relinkUIndex(sourceExport.FileRef, relinkingExport, ref uIndex, "Stack: StateNode", crossPCCObjectMappingList, "", importExportDependencies, relinkerCache); if (relinkResult is null) { prePropBinary.OverwriteRange(4, BitConverter.GetBytes(uIndex)); } else { relinkFailedReport.Add(relinkResult); } } //Relink Component's TemplateOwnerClass else if (relinkingExport.TemplateOwnerClassIdx is var toci && toci >= 0) { int uIndex = BitConverter.ToInt32(prePropBinary, toci); var relinkResult = relinkUIndex(sourceExport.FileRef, relinkingExport, ref uIndex, "TemplateOwnerClass", crossPCCObjectMappingList, "", importExportDependencies, relinkerCache); if (relinkResult is null) { prePropBinary.OverwriteRange(toci, BitConverter.GetBytes(uIndex)); } else { relinkFailedReport.Add(relinkResult); } } //Relink Properties PropertyCollection props = relinkingExport.GetProperties(); relinkFailedReport.AddRange(relinkPropertiesRecursive(sourcePcc, relinkingExport, props, crossPCCObjectMappingList, "", importExportDependencies, relinkerCache)); //Relink Binary try { if (relinkingExport.Game != sourcePcc.Game && (relinkingExport.IsClass || relinkingExport.ClassName == "State" || relinkingExport.ClassName == "Function")) { relinkFailedReport.Add(new EntryStringPair(relinkingExport, $"{relinkingExport.UIndex} {relinkingExport.FullPath} binary relinking failed. Cannot port {relinkingExport.ClassName} between games!")); } else if (ObjectBinary.From(relinkingExport) is ObjectBinary objBin) { List <(UIndex, string)> indices = objBin.GetUIndexes(relinkingExport.FileRef.Game); foreach ((UIndex uIndex, string propName) in indices) { var result = relinkUIndex(sourcePcc, relinkingExport, ref uIndex.value, $"(Binary Property: {propName})", crossPCCObjectMappingList, "", importExportDependencies, relinkerCache); if (result != null) { relinkFailedReport.Add(result); } } //UStruct is abstract baseclass for Class, State, and Function, and can have script in it if (objBin is UStruct uStructBinary && uStructBinary.ScriptBytes.Length > 0) { if (relinkingExport.Game == MEGame.ME3) { (List <Token> tokens, _) = Bytecode.ParseBytecode(uStructBinary.ScriptBytes, sourceExport); foreach (Token token in tokens) { relinkFailedReport.AddRange(RelinkToken(token, uStructBinary.ScriptBytes, sourceExport, relinkingExport, crossPCCObjectMappingList, importExportDependencies, relinkerCache)); } } else { var func = sourceExport.ClassName == "State" ? UE3FunctionReader.ReadState(sourceExport) : UE3FunctionReader.ReadFunction(sourceExport); func.Decompile(new TextBuilder(), false); //parse bytecode var nameRefs = func.NameReferences; var entryRefs = func.EntryReferences; foreach ((long position, NameReference nameRef) in nameRefs) { if (position < uStructBinary.ScriptBytes.Length) { RelinkNameReference(nameRef.Name, position, uStructBinary.ScriptBytes, relinkingExport); } } foreach ((long position, IEntry entry) in entryRefs) { if (position < uStructBinary.ScriptBytes.Length) { relinkFailedReport.AddRange(RelinkUnhoodEntryReference(entry, position, uStructBinary.ScriptBytes, sourceExport, relinkingExport, crossPCCObjectMappingList, importExportDependencies, relinkerCache)); } } } } relinkingExport.WritePrePropsAndPropertiesAndBinary(prePropBinary, props, objBin); return(relinkFailedReport); } } catch (Exception e) when(!CoreLib.IsDebug) { relinkFailedReport.Add(new EntryStringPair(relinkingExport, $"{relinkingExport.UIndex} {relinkingExport.FullPath} binary relinking failed due to exception: {e.Message}")); } relinkingExport.WritePrePropsAndProperties(prePropBinary, props); return(relinkFailedReport); }