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);
        }
Beispiel #3
0
        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());
        }
Beispiel #5
0
        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());
        }