public void ParseFunction() { HeaderText = ""; HeaderText += "Childindex : " + child + "\n"; HeaderText += "Unknown1 : " + unk1 + "\n"; HeaderText += "Unknown2 : " + unk2 + "\n"; HeaderText += "Script Size : " + size + "\n"; HeaderText += GetFlags() + "\n"; HeaderText += "Native Index: " + nativeindex; var parsedData = Bytecode.ParseBytecode(script, export); ScriptBlocks = parsedData.Item1; SingularTokenList = parsedData.Item2; }
public override List <(UIndex, string)> GetUIndexes(MEGame game) { List <(UIndex, string)> uIndices = base.GetUIndexes(game); uIndices.Add((Children, "ChildListStart")); if (Export.ClassName == "Function") { if (Export.Game == MEGame.ME3) { try { (List <Token> tokens, _) = Bytecode.ParseBytecode(ScriptBytes, Export); foreach (var t in tokens) { { var refs = t.inPackageReferences.Where(x => x.type == Token.INPACKAGEREFTYPE_ENTRY); uIndices.AddRange(refs.Select(x => (new UIndex(x.value), $"Reference inside of function at 0x{x.position:X}"))); } } } catch (Exception e) { Debug.WriteLine($"Error decompiling function {Export.FullPath}: {e.Message}"); } } else { try { var func = UE3FunctionReader.ReadFunction(Export); func.Decompile(new TextBuilder(), false); //parse bytecode var entryRefs = func.EntryReferences; uIndices.AddRange(entryRefs.Select(x => (new UIndex(x.Value.UIndex), $"Reference inside of function at 0x{x.Key:X}"))); } catch (Exception e) { Debug.WriteLine($"Error decompiling function {Export.FullPath}: {e.Message}"); } } } return(uIndices); }
public static List <string> Relink(ExportEntry sourceExport, ExportEntry relinkingExport, OrderedMultiValueDictionary <IEntry, IEntry> crossPCCObjectMappingList, bool importExportDependencies = false) { var relinkFailedReport = new List <string>(); IMEPackage sourcePcc = sourceExport.FileRef; //Relink stack if (relinkingExport.HasStack) { byte[] stack = relinkingExport.GetStack(); int uIndex = BitConverter.ToInt32(stack, 0); string relinkResult = relinkUIndex(sourceExport.FileRef, relinkingExport, ref uIndex, "Stack: Node", crossPCCObjectMappingList, "", importExportDependencies); if (relinkResult is null) { stack.OverwriteRange(0, BitConverter.GetBytes(uIndex)); } else { relinkFailedReport.Add(relinkResult); } uIndex = BitConverter.ToInt32(stack, 4); relinkResult = relinkUIndex(sourceExport.FileRef, relinkingExport, ref uIndex, "Stack: StateNode", crossPCCObjectMappingList, "", importExportDependencies); if (relinkResult is null) { stack.OverwriteRange(4, BitConverter.GetBytes(uIndex)); } else { relinkFailedReport.Add(relinkResult); } relinkingExport.SetStack(stack); } //Relink Properties PropertyCollection transplantProps = sourceExport.GetProperties(); relinkFailedReport.AddRange(relinkPropertiesRecursive(sourcePcc, relinkingExport, transplantProps, crossPCCObjectMappingList, "", importExportDependencies)); relinkingExport.WriteProperties(transplantProps); //Relink Binary try { if (relinkingExport.Game != sourcePcc.Game && (relinkingExport.IsClass || relinkingExport.ClassName == "State" || relinkingExport.ClassName == "Function")) { relinkFailedReport.Add($"{relinkingExport.UIndex} {relinkingExport.FullPath} binary relinking failed. Cannot port {relinkingExport.ClassName} between games!"); return(relinkFailedReport); } if (ObjectBinary.From(relinkingExport) is ObjectBinary objBin) { List <(UIndex, string)> indices = objBin.GetUIndexes(relinkingExport.FileRef.Game); foreach ((UIndex uIndex, string propName) in indices) { string result = relinkUIndex(sourcePcc, relinkingExport, ref uIndex.value, $"(Binary Property: {propName})", crossPCCObjectMappingList, "", importExportDependencies); 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)); } } else { relinkFailedReport.Add($"{relinkingExport.UIndex} {relinkingExport.FullPath} binary relinking failed. {relinkingExport.ClassName} contains script, " + $"which cannot be relinked for {relinkingExport.Game}"); } } relinkingExport.setBinaryData(objBin.ToBytes(relinkingExport.FileRef, relinkingExport.DataOffset + relinkingExport.propsEnd())); return(relinkFailedReport); } byte[] binarydata = relinkingExport.getBinaryData(); if (binarydata.Length > 0) { switch (relinkingExport.ClassName) { //todo: make a WwiseEvent ObjectBinary class case "WwiseEvent": { void relinkAtPosition(int binaryPosition, string propertyName) { int uIndex = BitConverter.ToInt32(binarydata, binaryPosition); string relinkResult = relinkUIndex(sourcePcc, relinkingExport, ref uIndex, propertyName, crossPCCObjectMappingList, "", importExportDependencies); if (relinkResult is null) { binarydata.OverwriteRange(binaryPosition, BitConverter.GetBytes(uIndex)); } else { relinkFailedReport.Add(relinkResult); } } if (relinkingExport.FileRef.Game == MEGame.ME3) { int count = BitConverter.ToInt32(binarydata, 0); for (int j = 0; j < count; j++) { relinkAtPosition(4 + (j * 4), $"(Binary Property: WwiseStreams[{j}])"); } relinkingExport.setBinaryData(binarydata); } else if (relinkingExport.FileRef.Game == MEGame.ME2) { int parsingPos = 4; int linkCount = BitConverter.ToInt32(binarydata, parsingPos); parsingPos += 4; for (int j = 0; j < linkCount; j++) { int bankcount = BitConverter.ToInt32(binarydata, parsingPos); parsingPos += 4; for (int k = 0; k < bankcount; k++) { relinkAtPosition(parsingPos, $"(Binary Property: link[{j}].WwiseBanks[{k}])"); parsingPos += 4; } int wwisestreamcount = BitConverter.ToInt32(binarydata, parsingPos); parsingPos += 4; for (int k = 0; k < wwisestreamcount; k++) { relinkAtPosition(parsingPos, $"(Binary Property: link[{j}].WwiseStreams[{k}])"); parsingPos += 4; } } relinkingExport.setBinaryData(binarydata); } } break; case "DominantDirectionalLightComponent": case "SphericalHarmonicLightComponent": case "DominantPointLightComponent": case "StaticLightCollectionActor": case "DominantSpotLightComponent": case "DirectionalLightComponent": case "StaticMeshCollectionActor": case "TerrainWeightMapTexture": case "PhysicsAssetInstance": case "PointLightComponent": case "ShadowMapTexture2D": case "SpotLightComponent": case "LightMapTexture2D": case "SkyLightComponent": case "TextureFlipBook": case "BrushComponent": case "FaceFXAnimSet": case "TextureMovie": case "AnimSequence": case "RB_BodySetup": case "MorphTarget": case "ShadowMap1D": case "WwiseStream": case "WwiseBank": case "Texture2D": //these classes have binary but do not need relinking break; default: if (binarydata.Any(b => b != 0)) { relinkFailedReport.Add($"{relinkingExport.UIndex} {relinkingExport.FullPath} has unparsed binary. " + $"This binary may contain items that need to be relinked. Come to the Discord server " + $"(click ME3Tweaks logo in main window for invite) and ask devs to parse this class."); } break; } } } catch (Exception e) when(!App.IsDebug) { relinkFailedReport.Add($"{relinkingExport.UIndex} {relinkingExport.FullPath} binary relinking failed due to exception: {e.Message}"); } return(relinkFailedReport); }
public void ParseFunction() { HeaderText = ""; if (export.FileRef.TryGetEntry(FunctionSuperclass, out var _fs)) { HeaderText += $"Function Superclass: {_fs.UIndex} {_fs.InstancedFullPath}\n"; } if (export.FileRef.TryGetEntry(NextItemInLoadingChain, out var _ni)) { HeaderText += $"Next Item in loading chain: {_ni.UIndex} {_ni.InstancedFullPath}\n"; } if (export.FileRef.TryGetEntry(ChildProbeStart, out var _cps)) { HeaderText += $"Child Probe Start: {_cps.UIndex} {_cps.InstancedFullPath}\n"; } HeaderText += $"Script Disk Size: {DiskSize}\n"; HeaderText += $"Script Memory Size: {MemorySize}\n"; HeaderText += $"Native Index: {nativeindex}\n"; HeaderText += GetSignature(); HeaderText += "\n"; var parsedData = Bytecode.ParseBytecode(script, export); ScriptBlocks = parsedData.Item1; SingularTokenList = parsedData.Item2; // Calculate memory offsets List <int> objRefPositions = ScriptBlocks.SelectMany(tok => tok.inPackageReferences) .Where(tup => tup.type == Unreal.Token.INPACKAGEREFTYPE_ENTRY) .Select(tup => tup.position).ToList(); int calculatedLength = DiskSize + 4 * objRefPositions.Count; DiskToMemPosMap = new int[DiskSize]; int iDisk = 0; int iMem = 0; foreach (int objRefPosition in objRefPositions) { while (iDisk < objRefPosition + 4) { DiskToMemPosMap[iDisk] = iMem; iDisk++; iMem++; } iMem += 4; } while (iDisk < DiskSize) { DiskToMemPosMap[iDisk] = iMem; iDisk++; iMem++; } foreach (Token t in ScriptBlocks) { var diskPos = t.pos - 32; if (diskPos >= 0 && diskPos < DiskToMemPosMap.Length) { t.memPos = DiskToMemPosMap[diskPos]; } } }
public static int ReplaceAllReferencesToThisOne(this IEntry baseEntry, IEntry replacementEntry) { int rcount = 0; int selectedEntryUIndex = baseEntry.UIndex; int replacementUIndex = replacementEntry.UIndex; var references = baseEntry.GetEntriesThatReferenceThisOne(); foreach ((IEntry entry, List <string> propsList) in references) { if (entry is ExportEntry exp) { if (propsList.Any(l => l.StartsWith("Property:"))) { var newprops = replacePropertyReferences(exp.GetProperties(), selectedEntryUIndex, replacementUIndex, ref rcount); exp.WriteProperties(newprops); } else { if (propsList.Any(l => l.StartsWith("(Binary prop:")) && !exp.IsDefaultObject && ObjectBinary.From(exp) is ObjectBinary objBin) { List <(UIndex, string)> indices = objBin.GetUIndexes(exp.FileRef.Game); foreach ((UIndex uIndex, _) in indices) { if (uIndex.value == selectedEntryUIndex) { uIndex.value = replacementUIndex; rcount++; } } //script relinking is not covered by standard binary relinking if (objBin is UStruct uStruct && uStruct.ScriptBytes.Length > 0) { if (exp.Game == MEGame.ME3) { (List <Token> tokens, _) = Bytecode.ParseBytecode(uStruct.ScriptBytes, exp); foreach (Token token in tokens) { foreach ((int pos, int type, int value) in token.inPackageReferences) { switch (type) { case Token.INPACKAGEREFTYPE_ENTRY when value == selectedEntryUIndex: uStruct.ScriptBytes.OverwriteRange(pos, BitConverter.GetBytes(replacementUIndex)); rcount++; break; } } } } else { var func = entry.ClassName == "State" ? UE3FunctionReader.ReadState(exp) : UE3FunctionReader.ReadFunction(exp); func.Decompile(new TextBuilder(), false); foreach ((long position, IEntry ent) in func.EntryReferences) { if (ent.UIndex == selectedEntryUIndex && position < uStruct.ScriptBytes.Length) { uStruct.ScriptBytes.OverwriteRange((int)position, BitConverter.GetBytes(replacementUIndex)); rcount++; } } } } exp.WriteBinary(objBin); } } } } return(rcount);
public static void ScanStuff(PackageEditorWPF pewpf) { //var filePaths = MELoadedFiles.GetOfficialFiles(MEGame.ME3);//.Concat(MELoadedFiles.GetOfficialFiles(MEGame.ME2));//.Concat(MELoadedFiles.GetOfficialFiles(MEGame.ME1)); //var filePaths = MELoadedFiles.GetAllFiles(game); /*"Core.pcc", "Engine.pcc", "GameFramework.pcc", "GFxUI.pcc", "WwiseAudio.pcc", "SFXOnlineFoundation.pcc", "SFXGame.pcc" */ var filePaths = new[] { "Core.pcc", "Engine.pcc", "GameFramework.pcc", "GFxUI.pcc", "WwiseAudio.pcc", "SFXOnlineFoundation.pcc" }.Select(f => Path.Combine(ME3Directory.CookedPCPath, f)); var interestingExports = new List <EntryStringPair>(); var foundClasses = new HashSet <string>(); //new HashSet<string>(BinaryInterpreterWPF.ParsableBinaryClasses); var foundProps = new Dictionary <string, string>(); var unkOpcodes = new List <int>();//Enumerable.Range(0x5B, 8).ToList(); unkOpcodes.Add(0); unkOpcodes.Add(1); var unkOpcodesInfo = unkOpcodes.ToDictionary(i => i, i => new OpcodeInfo()); var comparisonDict = new Dictionary <string, (byte[] original, byte[] newData)>(); var extraInfo = new HashSet <string>(); pewpf.IsBusy = true; pewpf.BusyText = "Scanning"; Task.Run(() => { //preload base files for faster scanning using var baseFiles = MEPackageHandler.OpenMEPackages(EntryImporter.FilesSafeToImportFrom(MEGame.ME3) .Select(f => Path.Combine(ME3Directory.CookedPCPath, f))); baseFiles.Add( MEPackageHandler.OpenMEPackage(Path.Combine(ME3Directory.CookedPCPath, "BIOP_MP_COMMON.pcc"))); foreach (string filePath in filePaths) { //ScanShaderCache(filePath); //ScanMaterials(filePath); //ScanStaticMeshComponents(filePath); //ScanLightComponents(filePath); //ScanLevel(filePath); //if (findClass(filePath, "ShaderCache", true)) break; //findClassesWithBinary(filePath); ScanScripts2(filePath); //if (interestingExports.Count > 0) //{ // break; //} //if (resolveImports(filePath)) break; } }).ContinueWithOnUIThread(prevTask => { pewpf.IsBusy = false; interestingExports.Add(new EntryStringPair(null, string.Join("\n", extraInfo))); var listDlg = new ListDialog(interestingExports, "Interesting Exports", "", pewpf) { DoubleClickEntryHandler = entryItem => { if (entryItem?.Entry is IEntry entryToSelect) { PackageEditorWPF p = new PackageEditorWPF(); p.Show(); p.LoadFile(entryToSelect.FileRef.FilePath, entryToSelect.UIndex); p.Activate(); if (comparisonDict.TryGetValue($"{entryToSelect.UIndex} {entryToSelect.FileRef.FilePath}", out (byte[] original, byte[] newData)val)) { File.WriteAllBytes(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "original.bin"), val.original); File.WriteAllBytes(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "new.bin"), val.newData); } } } }; listDlg.Show(); }); #region extra scanning functions bool findClass(string filePath, string className, bool withBinary = false) { Debug.WriteLine($" {filePath}"); using (IMEPackage pcc = MEPackageHandler.OpenMEPackage(filePath)) { //if (!pcc.IsCompressed) return false; var exports = pcc.Exports.Where(exp => !exp.IsDefaultObject && exp.IsA(className)); foreach (ExportEntry exp in exports) { try { //Debug.WriteLine($"{exp.UIndex}: {filePath}"); var originalData = exp.Data; exp.WriteBinary(ObjectBinary.From(exp)); var newData = exp.Data; if (!originalData.SequenceEqual(newData)) { interestingExports.Add(exp); File.WriteAllBytes( Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "original.bin"), originalData); File.WriteAllBytes( Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "new.bin"), newData); return(true); } } catch (Exception exception) { Console.WriteLine(exception); interestingExports.Add(new EntryStringPair(exp, $"{exception}")); return(true); } } } return(false); } void findClassesWithBinary(string filePath) { using (IMEPackage pcc = MEPackageHandler.OpenMEPackage(filePath)) { foreach (ExportEntry exp in pcc.Exports.Where(exp => !exp.IsDefaultObject)) { try { if (!foundClasses.Contains(exp.ClassName) && exp.propsEnd() < exp.DataSize) { if (ObjectBinary.From(exp) != null) { foundClasses.Add(exp.ClassName); } else if (exp.GetBinaryData().Any(b => b != 0)) { foundClasses.Add(exp.ClassName); interestingExports.Add(exp); } } } catch (Exception exception) { Console.WriteLine(exception); interestingExports.Add(new EntryStringPair(exp, $"{exp.UIndex}: {filePath}\n{exception}")); } } } } void ScanShaderCache(string filePath) { using (IMEPackage pcc = MEPackageHandler.OpenMEPackage(filePath)) { ExportEntry shaderCache = pcc.Exports.FirstOrDefault(exp => exp.ClassName == "ShaderCache"); if (shaderCache == null) { return; } int oldDataOffset = shaderCache.DataOffset; try { MemoryStream binData = new MemoryStream(shaderCache.Data); binData.JumpTo(shaderCache.propsEnd() + 1); int nameList1Count = binData.ReadInt32(); binData.Skip(nameList1Count * 12); int namelist2Count = binData.ReadInt32(); //namelist2 binData.Skip(namelist2Count * 12); int shaderCount = binData.ReadInt32(); for (int i = 0; i < shaderCount; i++) { binData.Skip(24); int nextShaderOffset = binData.ReadInt32() - oldDataOffset; binData.Skip(14); if (binData.ReadInt32() != 1111577667) //CTAB { interestingExports.Add(new EntryStringPair(null, $"{binData.Position - 4}: {filePath}")); return; } binData.JumpTo(nextShaderOffset); } int vertexFactoryMapCount = binData.ReadInt32(); binData.Skip(vertexFactoryMapCount * 12); int materialShaderMapCount = binData.ReadInt32(); for (int i = 0; i < materialShaderMapCount; i++) { binData.Skip(16); int switchParamCount = binData.ReadInt32(); binData.Skip(switchParamCount * 32); int componentMaskParamCount = binData.ReadInt32(); //if (componentMaskParamCount != 0) //{ // interestingExports.Add($"{i}: {filePath}"); // return; //} binData.Skip(componentMaskParamCount * 44); int normalParams = binData.ReadInt32(); if (normalParams != 0) { interestingExports.Add(new EntryStringPair(null, $"{i}: {filePath}")); return; } binData.Skip(normalParams * 29); int unrealVersion = binData.ReadInt32(); int licenseeVersion = binData.ReadInt32(); if (unrealVersion != 684 || licenseeVersion != 194) { interestingExports.Add(new EntryStringPair(null, $"{binData.Position - 8}: {filePath}")); return; } int nextMaterialShaderMapOffset = binData.ReadInt32() - oldDataOffset; binData.JumpTo(nextMaterialShaderMapOffset); } } catch (Exception exception) { Console.WriteLine(exception); interestingExports.Add(new EntryStringPair(null, $"{filePath}\n{exception}")); } } } void ScanScripts(string filePath) { using IMEPackage pcc = MEPackageHandler.OpenMEPackage(filePath); foreach (ExportEntry exp in pcc.Exports.Where(exp => !exp.IsDefaultObject)) { try { if ((exp.ClassName == "State" || exp.ClassName == "Function") && ObjectBinary.From(exp) is UStruct uStruct) { byte[] data = exp.Data; (_, List <BytecodeSingularToken> tokens) = Bytecode.ParseBytecode(uStruct.ScriptBytes, exp); foreach (var token in tokens) { if (token.CurrentStack.Contains("UNKNOWN") || token.OpCodeString.Contains("UNKNOWN")) { interestingExports.Add(exp); } if (unkOpcodes.Contains(token.OpCode)) { int refUIndex = EndianReader.ToInt32(data, token.StartPos + 1, pcc.Endian); IEntry entry = pcc.GetEntry(refUIndex); if (entry != null && (entry.ClassName == "ByteProperty")) { var info = unkOpcodesInfo[token.OpCode]; info.Usages.Add(pcc.FilePath, exp.UIndex, token.StartPos); info.PropTypes.Add(refUIndex switch { 0 => "Null", _ when entry != null => entry.ClassName, _ => "Invalid" }); if (entry != null) { if (entry.Parent == exp) { info.PropLocations.Add("Local"); } else if (entry.Parent == (exp.Parent.ClassName == "State" ? exp.Parent.Parent : exp.Parent)) { info.PropLocations.Add("ThisClass"); } else if (entry.Parent.ClassName == "Function") { info.PropLocations.Add("OtherFunction"); } else if (exp.Parent.IsA(entry.Parent.ObjectName)) { info.PropLocations.Add("AncestorClass"); } else { info.PropLocations.Add("OtherClass"); } } } } }
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); }