private void dumpBinaryToolStripMenuItem_Click_1(object sender, EventArgs e) { int n; if (stm != null) { n = stm.Export.UIndex; //TODO: CHANGE FOR UINDEXING } else if (skm != null) { n = skm.Export.UIndex; } else { return; } ExportEntry export = Pcc.GetUExport(n); if (export.ClassName == "StaticMesh") { SaveFileDialog d = new SaveFileDialog(); d.Filter = "*.bin|*.bin"; d.FileName = export.ObjectName.Instanced + ".bin"; if (d.ShowDialog() == DialogResult.OK) { FileStream fs = new FileStream(d.FileName, FileMode.Create, FileAccess.Write); fs.WriteFromBuffer(export.getBinaryData()); fs.Close(); MessageBox.Show("Done.", "Meshplorer", MessageBoxButtons.OK, MessageBoxIcon.None, MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly); } } if (export.ClassName == "SkeletalMesh") { SaveFileDialog d = new SaveFileDialog(); d.Filter = "*.bin|*.bin"; d.FileName = export.ObjectName.Instanced + ".bin"; if (d.ShowDialog() == DialogResult.OK) { using (FileStream fs = new FileStream(d.FileName, FileMode.Create, FileAccess.Write)) { var data = export.getBinaryData(); fs.Write(data, 0, data.Length); } MessageBox.Show("Done.", "Meshplorer", MessageBoxButtons.OK, MessageBoxIcon.None, MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly); } } }
public static T From <T>(ExportEntry export) where T : ObjectBinary, new() { var t = new T { Export = export }; t.Serialize(new SerializingContainer2(new MemoryStream(export.getBinaryData()), export.FileRef, true, export.DataOffset + export.propsEnd())); return(t); }
public static ObjectBinary ConvertPostPropBinary(ExportEntry export, MEGame newGame) { if (export.getBinaryData().Length == 0) { return(new GenericObjectBinary(new byte[0])); } if (From(export) is ObjectBinary objbin) { return(objbin); } if (export.IsTexture()) { return(new GenericObjectBinary(ConvertTexture2D(export, newGame))); } //no conversion neccesary return(new GenericObjectBinary(export.getBinaryData())); }
public static ObjectBinary ConvertPostPropBinary(ExportEntry export, MEGame newGame) { if (export.getBinaryData().Length == 0) { return(Array.Empty <byte>()); } if (From(export) is ObjectBinary objbin) { return(objbin); } if (export.IsTexture()) { return(ConvertTexture2D(export, newGame)); } switch (export.ClassName) { case "DirectionalLightComponent": case "PointLightComponent": case "SkyLightComponent": case "SphericalHarmonicLightComponent": case "SpotLightComponent": case "DominantSpotLightComponent": case "DominantPointLightComponent": case "DominantDirectionalLightComponent": if (newGame == MEGame.UDK) { return(Array.Empty <byte>()); } else if (export.Game == MEGame.UDK && newGame != MEGame.UDK) { return(new byte[8]); } break; } //no conversion neccesary return(export.getBinaryData()); }
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 static byte[] ConvertTexture2D(ExportEntry export, MEGame newGame, List <int> offsets = null, StorageTypes newStorageType = StorageTypes.empty) { MemoryStream bin = new MemoryStream(export.getBinaryData()); if (bin.Length == 0) { return(bin.ToArray()); } var os = new MemoryStream(); if (export.Game != MEGame.ME3) { bin.Skip(16); } if (newGame != MEGame.ME3) { os.WriteZeros(16);//includes fileOffset, but that will be set during save } int mipCount = bin.ReadInt32(); long mipCountPosition = os.Position; os.WriteInt32(mipCount); List <Texture2DMipInfo> mips = Texture2D.GetTexture2DMipInfos(export, export.GetProperty <NameProperty>("TextureFileCacheName")?.Value); int offsetIdx = 0; int trueMipCount = 0; for (int i = 0; i < mipCount; i++) { var storageType = (StorageTypes)bin.ReadInt32(); int uncompressedSize = bin.ReadInt32(); int compressedSize = bin.ReadInt32(); int fileOffset = bin.ReadInt32(); byte[] texture; switch (storageType) { case StorageTypes.pccUnc: texture = bin.ReadToBuffer(uncompressedSize); break; case StorageTypes.pccLZO: case StorageTypes.pccZlib: texture = bin.ReadToBuffer(compressedSize); if (offsets != null) { texture = Array.Empty <byte>(); fileOffset = offsets[offsetIdx++]; compressedSize = offsets[offsetIdx] - fileOffset; if (newStorageType != StorageTypes.empty) { storageType = newStorageType; } } break; case StorageTypes.empty: texture = new byte[0]; break; default: if (export.Game != newGame) { storageType &= (StorageTypes) ~StorageFlags.externalFile; texture = Texture2D.GetTextureData(mips[i], false); //copy in external textures } else { texture = Array.Empty <byte>(); } break; } int width = bin.ReadInt32(); int height = bin.ReadInt32(); if (newGame == MEGame.UDK && storageType == StorageTypes.empty) { continue; } trueMipCount++; os.WriteInt32((int)storageType); os.WriteInt32(uncompressedSize); os.WriteInt32(compressedSize); os.WriteInt32(fileOffset);//fileOffset will be fixed during save os.WriteFromBuffer(texture); os.WriteInt32(width); os.WriteInt32(height); } long postMipPosition = os.Position; os.JumpTo(mipCountPosition); os.WriteInt32(trueMipCount); os.JumpTo(postMipPosition); int unk1 = 0; if (export.Game != MEGame.UDK) { unk1 = bin.ReadInt32(); } if (newGame != MEGame.UDK) { os.WriteInt32(unk1); } Guid textureGuid = export.Game != MEGame.ME1 ? bin.ReadGuid() : Guid.NewGuid(); if (newGame != MEGame.ME1) { os.WriteGuid(textureGuid); } if (export.Game == MEGame.UDK) { bin.Skip(32); } if (newGame == MEGame.UDK) { os.WriteZeros(4 * 8); } if (export.Game == MEGame.ME3) { bin.Skip(4); } if (newGame == MEGame.ME3) { os.WriteInt32(0); } if (export.ClassName == "LightMapTexture2D") { int lightMapFlags = 0; if (export.Game >= MEGame.ME3) { lightMapFlags = bin.ReadInt32(); } if (newGame >= MEGame.ME3) { os.WriteInt32(0);//LightMapFlags noflag } } return(os.ToArray()); }