public static byte[] ConvertPrePropBinary(ExportEntry export, MEGame newGame) { if (export.HasStack) { var ms = new MemoryStream(export.Data); int node = ms.ReadInt32(); int stateNode = ms.ReadInt32(); ulong probeMask = ms.ReadUInt64(); if (export.Game == MEGame.ME3) { ms.SkipInt16(); } else { ms.SkipInt32(); } int count = ms.ReadInt32(); byte[] stateStack = ms.ReadToBuffer(count * 12); int offset = 0; if (node != 0) { offset = ms.ReadInt32(); } int netIndex = ms.ReadInt32(); var os = new MemoryStream(); os.WriteInt32(node); os.WriteInt32(stateNode); os.WriteUInt64(probeMask); if (newGame == MEGame.ME3) { os.WriteUInt16(0); } else { os.WriteUInt32(0); } os.WriteInt32(count); os.WriteFromBuffer(stateStack); if (node != 0) { os.WriteInt32(offset); } os.WriteInt32(netIndex); return(os.ToArray()); } switch (export.ClassName) { case "DominantSpotLightComponent": case "DominantDirectionalLightComponent": //todo: do conversion for these break; } return(export.Data.Slice(0, export.GetPropertyStart())); }
/// <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); }
public void Write2DAToExport() { using (var stream = new MemoryStream()) { //Cell count if (IsIndexed) { //Indexed ones seem to have 0 at start stream.WriteBytes(BitConverter.GetBytes(0)); } stream.WriteBytes(BitConverter.GetBytes(PopulatedCellCount)); //Write cell data for (int rowindex = 0; rowindex < RowCount; rowindex++) { for (int colindex = 0; colindex < ColumnCount; colindex++) { Bio2DACell cell = Cells[rowindex, colindex]; if (cell != null) { if (IsIndexed) { //write index int index = (rowindex * ColumnCount) + colindex; //+1 because they are not zero based indexes since they are numerals stream.WriteBytes(BitConverter.GetBytes(index)); } stream.WriteByte((byte)cell.Type); stream.WriteBytes(cell.Data); } else { if (IsIndexed) { //this is a blank cell. It is not present in the table. continue; } else { Debug.WriteLine("THIS SHOULDN'T OCCUR!"); Debugger.Break(); throw new Exception("A non-indexed Bio2DA cannot have null cells."); } } } } //Write Columns if (!IsIndexed) { stream.WriteBytes(BitConverter.GetBytes(0)); //seems to be a 0 before column definitions } //Console.WriteLine("Columns defs start at " + stream.Position.ToString("X6")); stream.WriteBytes(BitConverter.GetBytes(ColumnCount)); for (int colindex = 0; colindex < ColumnCount; colindex++) { //Console.WriteLine("Writing column definition " + columnNames[colindex]); int nameIndexForCol = export.FileRef.FindNameOrAdd(ColumnNames[colindex]); stream.WriteBytes(BitConverter.GetBytes(nameIndexForCol)); stream.WriteBytes(BitConverter.GetBytes(0)); //second half of name reference in 2da is always zero since they're always indexed at 0 stream.WriteBytes(BitConverter.GetBytes(colindex)); } int propsEnd = export.propsEnd(); byte[] binarydata = stream.ToArray(); //Todo: Rewrite properties here PropertyCollection props = new PropertyCollection(); if (export.ClassName == "Bio2DA") { var indicies = new ArrayProperty <NameProperty>("m_sRowLabel"); foreach (var rowname in RowNames) { indicies.Add(new NameProperty(rowname)); } props.Add(indicies); } else { var indices = new ArrayProperty <IntProperty>("m_lstRowNumbers"); foreach (var rowname in RowNames) { indices.Add(new IntProperty(int.Parse(rowname))); } props.Add(indices); } MemoryStream propsStream = new MemoryStream(); props.WriteTo(propsStream, export.FileRef); MemoryStream currentDataStream = new MemoryStream(export.Data); byte[] propertydata = propsStream.ToArray(); int propertyStartOffset = export.GetPropertyStart(); var newExportData = new byte[propertyStartOffset + propertydata.Length + binarydata.Length]; Buffer.BlockCopy(export.Data, 0, newExportData, 0, propertyStartOffset); propertydata.CopyTo(newExportData, propertyStartOffset); binarydata.CopyTo(newExportData, propertyStartOffset + propertydata.Length); //Console.WriteLine("Old data size: " + export.Data.Length); //Console.WriteLine("NEw data size: " + newExportData.Length); //This assumes the input and output data sizes are the same. We should not assume this with new functionality //if (export.Data.Length != newExportData.Length) //{ // Debug.WriteLine("FILES ARE WRONG SIZE"); // Debugger.Break(); //} export.Data = newExportData; } }