Esempio n. 1
0
        public void RepackTexturesTFC(List <FoundTexture> textures, MainWindow mainWindow, CachePackageMgr cachePackageMgr)
        {
            if (GameData.gameType == MeType.ME2_TYPE)
            {
                for (int i = 0; i < textures.Count; i++)
                {
                    FoundTexture foundTexture = textures[i];
                    if (mainWindow != null)
                    {
                        mainWindow.updateStatusLabel("Texture: " + (i + 1) + " of " + textures.Count);
                        mainWindow.updateStatusLabel2("");
                    }
                    string  TFCfilename = "", TFCfilenameTemp, prevTFCfilename = "";
                    Texture prevTexture = null;
                    for (int index2 = 0; index2 < foundTexture.list.Count; index2++)
                    {
                        MatchedTexture matchedTexture = foundTexture.list[index2];
                        string         packagePath    = GameData.GamePath + matchedTexture.path;
                        Package        package        = cachePackageMgr.OpenPackage(packagePath);
                        Texture        texture        = new Texture(package, matchedTexture.exportID, package.getExportData(matchedTexture.exportID));
                        if (!texture.mipMapsList.Exists(b => b.storageType == Texture.StorageTypes.extLZO || b.storageType == Texture.StorageTypes.extUnc || b.storageType == Texture.StorageTypes.extZlib))
                        {
                            continue;
                        }

                        bool modified = false;
                        for (int l = 0; l < texture.mipMapsList.Count; l++)
                        {
                            Texture.MipMap mipmap = texture.mipMapsList[l];
                            if (((int)mipmap.storageType & (int)Texture.StorageFlags.externalFile) != 0)
                            {
                                string archive = texture.properties.getProperty("TextureFileCacheName").valueName;
                                TFCfilename = Path.Combine(GameData.MainData, archive + ".tfc");
                                if (packagePath.ToLowerInvariant().Contains("\\dlc"))
                                {
                                    string DLCArchiveFile = Path.Combine(Path.GetDirectoryName(packagePath), archive + ".tfc");
                                    if (File.Exists(DLCArchiveFile))
                                    {
                                        TFCfilename = DLCArchiveFile;
                                    }
                                    else if (GameData.gameType == MeType.ME2_TYPE)
                                    {
                                        TFCfilename = Path.Combine(GameData.MainData, "Textures.tfc");
                                    }
                                }

                                TFCfilenameTemp = TFCfilename + ".TempTFC";
                                if (!File.Exists(TFCfilenameTemp))
                                {
                                    using (FileStream fs = new FileStream(TFCfilenameTemp, FileMode.CreateNew, FileAccess.Write))
                                    {
                                        byte[] guid = new byte[16];
                                        Array.Copy(texture.properties.getProperty("TFCFileGuid").valueStruct, guid, 16);
                                        fs.WriteFromBuffer(guid);
                                    }
                                }

                                if (TFCfilename != prevTFCfilename)
                                {
                                    using (FileStream fs = new FileStream(TFCfilename, FileMode.Open, FileAccess.Read))
                                    {
                                        fs.JumpTo(mipmap.dataOffset);
                                        using (FileStream fsNew = new FileStream(TFCfilenameTemp, FileMode.Append, FileAccess.Write))
                                        {
                                            fsNew.SeekEnd();
                                            mipmap.dataOffset = (uint)fsNew.Position;
                                            if (mipmap.storageType == Texture.StorageTypes.extLZO ||
                                                mipmap.storageType == Texture.StorageTypes.extZlib)
                                            {
                                                fsNew.WriteFromStream(fs, mipmap.compressedSize);
                                            }
                                            else
                                            {
                                                fsNew.WriteFromStream(fs, mipmap.uncompressedSize);
                                            }
                                        }
                                    }
                                }
                                else
                                {
                                    Texture.MipMap tmpMipmap = prevTexture.getMipmap(mipmap.width, mipmap.height);
                                    if (mipmap.storageType != tmpMipmap.storageType)
                                    {
                                        throw new Exception("");
                                    }
                                    mipmap.dataOffset = tmpMipmap.dataOffset;
                                }
                                texture.mipMapsList[l] = mipmap;
                                modified = true;
                            }
                        }

                        if (modified)
                        {
                            prevTFCfilename = TFCfilename;
                            prevTexture     = texture;
                            using (MemoryStream newData = new MemoryStream())
                            {
                                newData.WriteFromBuffer(texture.properties.toArray());
                                newData.WriteFromBuffer(texture.toArray(package.exportsTable[matchedTexture.exportID].dataOffset + (uint)newData.Position));
                                //package.setExportData(matchedTexture.exportID, newData.ToArray());
                            }
                        }
                    }
                }
            }
            if (mainWindow != null)
            {
                mainWindow.updateStatusLabel("");
            }

            List <string> tfcFles = Directory.GetFiles(GameData.GamePath, "*.TempTFC", SearchOption.AllDirectories).Where(item => item.EndsWith(".TempTFC", StringComparison.OrdinalIgnoreCase)).ToList();

            for (int i = 0; i < tfcFles.Count; i++)
            {
                string newname = tfcFles[i].Substring(0, tfcFles[i].IndexOf(".TempTFC"));
                File.Delete(newname);
                File.Move(tfcFles[i], newname);
            }
            //cachePackageMgr.CloseAllWithSave();

            if (mainWindow != null)
            {
                mainWindow.updateStatusLabel("Done.");
                mainWindow.updateStatusLabel("");
            }
        }
        public string replaceTexture(DDSImage image, List <MatchedTexture> list, CachePackageMgr cachePackageMgr, string textureName, uint crc)
        {
            List <Texture> masterTextures = new List <Texture>();
            Texture        arcTexture = null, cprTexture = null;
            string         errors = "";

            for (int n = 0; n < list.Count; n++)
            {
                MatchedTexture nodeTexture = list[n];
                Package        package     = cachePackageMgr.OpenPackage(GameData.GamePath + nodeTexture.path);
                Texture        texture     = new Texture(package, nodeTexture.exportID, package.getExportData(nodeTexture.exportID));
                while (texture.mipMapsList.Exists(s => s.storageType == Texture.StorageTypes.empty))
                {
                    texture.mipMapsList.Remove(texture.mipMapsList.First(s => s.storageType == Texture.StorageTypes.empty));
                }
                bool master = true;
                if (GameData.gameType == MeType.ME1_TYPE)
                {
                    if (texture.packageName.ToLowerInvariant() != Path.GetFileNameWithoutExtension(package.packageFile.Name).ToLowerInvariant())
                    {
                        master = false;
                        if (!masterTextures.Exists(s => s.packageName.ToLowerInvariant() == texture.packageName.ToLowerInvariant()))
                        {
                            errors += "Error in texture: " + textureName + " Broken game file: " + nodeTexture.path + ", skipping texture..." + Environment.NewLine;
                            continue;
                        }
                    }
                }

                if (texture.mipMapsList.Count > 1 && image.mipMaps.Count() <= 1)
                {
                    errors += "Error in texture: " + textureName + " This texture has not all the required mipmaps, skipping texture..." + Environment.NewLine;
                    break;
                }

                string    fmt       = texture.properties.getProperty("Format").valueName;
                DDSFormat ddsFormat = DDSImage.convertFormat(fmt);
                if (image.ddsFormat != ddsFormat)
                {
                    errors += "Error in texture: " + textureName + " This texture has wrong texture format, should be: " + ddsFormat + ", skipping texture..." + Environment.NewLine;
                    break;
                }

                if (image.mipMaps[0].origWidth / image.mipMaps[0].origHeight !=
                    texture.mipMapsList[0].width / texture.mipMapsList[0].height)
                {
                    errors += "Error in texture: " + textureName + " This texture has wrong aspect ratio, skipping texture..." + Environment.NewLine;
                    break;
                }

                // remove lower mipmaps from source image which not exist in game data
                for (int t = 0; t < image.mipMaps.Count(); t++)
                {
                    if (image.mipMaps[t].origWidth <= texture.mipMapsList[0].width &&
                        image.mipMaps[t].origHeight <= texture.mipMapsList[0].height &&
                        texture.mipMapsList.Count > 1)
                    {
                        if (!texture.mipMapsList.Exists(m => m.width == image.mipMaps[t].origWidth && m.height == image.mipMaps[t].origHeight))
                        {
                            image.mipMaps.RemoveAt(t--);
                        }
                    }
                }

                bool skip = false;
                // reuse lower mipmaps from game data which not exist in source image
                for (int t = 0; t < texture.mipMapsList.Count; t++)
                {
                    if (texture.mipMapsList[t].width <= image.mipMaps[0].origWidth &&
                        texture.mipMapsList[t].height <= image.mipMaps[0].origHeight)
                    {
                        if (!image.mipMaps.Exists(m => m.origWidth == texture.mipMapsList[t].width && m.origHeight == texture.mipMapsList[t].height))
                        {
                            byte[] data = texture.getMipMapData(texture.mipMapsList[t]);
                            if (data == null)
                            {
                                errors += "Error in game data: " + nodeTexture.path + ", skipping texture..." + Environment.NewLine;
                                skip    = true;
                                break;
                            }
                            DDSImage.MipMap mipmap = new DDSImage.MipMap(data, ddsFormat, texture.mipMapsList[t].width, texture.mipMapsList[t].height);
                            image.mipMaps.Add(mipmap);
                        }
                    }
                }
                if (skip)
                {
                    continue;
                }

                package.DisposeCache();

                bool   triggerCacheArc = false, triggerCacheCpr = false;
                string archiveFile = "";
                byte[] origGuid    = new byte[16];
                if (texture.properties.exists("TextureFileCacheName"))
                {
                    Array.Copy(texture.properties.getProperty("TFCFileGuid").valueStruct, origGuid, 16);
                    string archive = texture.properties.getProperty("TextureFileCacheName").valueName;
                    archiveFile = Path.Combine(GameData.MainData, archive + ".tfc");
                    if (nodeTexture.path.ToLowerInvariant().Contains("\\dlc"))
                    {
                        string DLCArchiveFile = Path.Combine(Path.GetDirectoryName(GameData.GamePath + nodeTexture.path), archive + ".tfc");
                        if (File.Exists(DLCArchiveFile))
                        {
                            archiveFile = DLCArchiveFile;
                        }
                        else if (!File.Exists(archiveFile))
                        {
                            List <string> files = Directory.GetFiles(GameData.bioGamePath, archive + ".tfc",
                                                                     SearchOption.AllDirectories).Where(item => item.EndsWith(".tfc", StringComparison.OrdinalIgnoreCase)).ToList();
                            if (files.Count == 0)
                            {
                                archiveFile = Path.Combine(GameData.MainData, "Textures.tfc");
                            }
                            else if (files.Count == 1)
                            {
                                archiveFile = files[0];
                            }
                            else
                            {
                                throw new Exception("");
                            }
                        }
                    }
                    long fileLength = new FileInfo(archiveFile).Length;
                    if (fileLength + 0x5000000 > 0x80000000)
                    {
                        archiveFile = "";
                        foreach (TFCTexture newGuid in guids)
                        {
                            archiveFile = Path.Combine(GameData.MainData, newGuid.name + ".tfc");
                            if (!File.Exists(archiveFile))
                            {
                                texture.properties.setNameValue("TextureFileCacheName", newGuid.name);
                                texture.properties.setStructValue("TFCFileGuid", "Guid", newGuid.guid);
                                using (FileStream fs = new FileStream(archiveFile, FileMode.CreateNew, FileAccess.Write))
                                {
                                    fs.WriteFromBuffer(newGuid.guid);
                                }
                                break;
                            }
                            else
                            {
                                fileLength = new FileInfo(archiveFile).Length;
                                if (fileLength + 0x5000000 < 0x80000000)
                                {
                                    texture.properties.setNameValue("TextureFileCacheName", newGuid.name);
                                    texture.properties.setStructValue("TFCFileGuid", "Guid", newGuid.guid);
                                    break;
                                }
                            }
                            archiveFile = "";
                        }
                        if (archiveFile == "")
                        {
                            throw new Exception("No free TFC texture file!");
                        }
                    }
                }

                List <Texture.MipMap> mipmaps = new List <Texture.MipMap>();
                for (int m = 0; m < image.mipMaps.Count(); m++)
                {
                    Texture.MipMap mipmap = new Texture.MipMap();
                    mipmap.width  = image.mipMaps[m].origWidth;
                    mipmap.height = image.mipMaps[m].origHeight;
                    if (texture.existMipmap(mipmap.width, mipmap.height))
                    {
                        mipmap.storageType = texture.getMipmap(mipmap.width, mipmap.height).storageType;
                    }
                    else
                    {
                        mipmap.storageType = texture.getTopMipmap().storageType;
                        if (GameData.gameType == MeType.ME1_TYPE && master == false)
                        {
                            if (mipmap.storageType == Texture.StorageTypes.pccUnc ||
                                mipmap.storageType == Texture.StorageTypes.pccLZO ||
                                mipmap.storageType == Texture.StorageTypes.pccZlib)
                            {
                                mipmap.storageType = Texture.StorageTypes.extLZO;
                            }
                        }
                        else if (GameData.gameType == MeType.ME2_TYPE || GameData.gameType == MeType.ME3_TYPE)
                        {
                            if (texture.properties.exists("TextureFileCacheName") && texture.mipMapsList.Count > 1)
                            {
                                if (texture.mipMapsList.Count < 6)
                                {
                                    mipmap.storageType = Texture.StorageTypes.pccUnc;
                                    if (!texture.properties.exists("NeverStream"))
                                    {
                                        if (package.existsNameId("NeverStream"))
                                        {
                                            texture.properties.addBoolValue("NeverStream", true);
                                        }
                                        else
                                        {
                                            goto skip;
                                        }
                                    }
                                }
                                else
                                {
                                    if (GameData.gameType == MeType.ME2_TYPE)
                                    {
                                        mipmap.storageType = Texture.StorageTypes.extLZO;
                                    }
                                    else
                                    {
                                        mipmap.storageType = Texture.StorageTypes.extZlib;
                                    }
                                }
                            }
                        }
                    }

                    if (mipmap.storageType == Texture.StorageTypes.extLZO)
                    {
                        mipmap.storageType = Texture.StorageTypes.extZlib;
                    }
                    if (mipmap.storageType == Texture.StorageTypes.pccLZO)
                    {
                        mipmap.storageType = Texture.StorageTypes.pccZlib;
                    }

                    mipmap.uncompressedSize = image.mipMaps[m].data.Length;
                    if (GameData.gameType == MeType.ME1_TYPE)
                    {
                        if (mipmap.storageType == Texture.StorageTypes.pccLZO ||
                            mipmap.storageType == Texture.StorageTypes.pccZlib)
                        {
                            if (master)
                            {
                                mipmap.newData = texture.compressTexture(image.mipMaps[m].data, mipmap.storageType);
                            }
                            else
                            {
                                mipmap.newData = masterTextures.Find(s => s.packageName.ToLowerInvariant() == texture.packageName.ToLowerInvariant()).mipMapsList[m].newData;
                            }
                            mipmap.compressedSize = mipmap.newData.Length;
                        }
                        if (mipmap.storageType == Texture.StorageTypes.pccUnc)
                        {
                            mipmap.compressedSize = mipmap.uncompressedSize;
                            mipmap.newData        = image.mipMaps[m].data;
                        }
                        if ((mipmap.storageType == Texture.StorageTypes.extLZO ||
                             mipmap.storageType == Texture.StorageTypes.extZlib) && master == false)
                        {
                            mipmap.compressedSize = masterTextures.Find(s => s.packageName.ToLowerInvariant() == texture.packageName.ToLowerInvariant()).mipMapsList[m].compressedSize;
                            mipmap.dataOffset     = masterTextures.Find(s => s.packageName.ToLowerInvariant() == texture.packageName.ToLowerInvariant()).mipMapsList[m].dataOffset;
                        }
                    }
                    else
                    {
                        if (mipmap.storageType == Texture.StorageTypes.extZlib ||
                            mipmap.storageType == Texture.StorageTypes.extLZO)
                        {
                            if (cprTexture == null || (cprTexture != null && mipmap.storageType != cprTexture.mipMapsList[m].storageType))
                            {
                                mipmap.newData  = texture.compressTexture(image.mipMaps[m].data, mipmap.storageType);
                                triggerCacheCpr = true;
                            }
                            else
                            {
                                if (cprTexture.mipMapsList[m].width != mipmap.width ||
                                    cprTexture.mipMapsList[m].height != mipmap.height)
                                {
                                    throw new Exception();
                                }
                                mipmap.newData = cprTexture.mipMapsList[m].newData;
                            }
                            mipmap.compressedSize = mipmap.newData.Length;
                        }
                        if (mipmap.storageType == Texture.StorageTypes.pccUnc ||
                            mipmap.storageType == Texture.StorageTypes.extUnc)
                        {
                            mipmap.compressedSize = mipmap.uncompressedSize;
                            mipmap.newData        = image.mipMaps[m].data;
                        }
                        if (mipmap.storageType == Texture.StorageTypes.extZlib ||
                            mipmap.storageType == Texture.StorageTypes.extLZO ||
                            mipmap.storageType == Texture.StorageTypes.extUnc)
                        {
                            if (arcTexture == null ||
                                !StructuralComparisons.StructuralEqualityComparer.Equals(
                                    arcTexture.properties.getProperty("TFCFileGuid").valueStruct,
                                    texture.properties.getProperty("TFCFileGuid").valueStruct))
                            {
                                triggerCacheArc = true;
                                Texture.MipMap oldMipmap = texture.getMipmap(mipmap.width, mipmap.height);
                                if (StructuralComparisons.StructuralEqualityComparer.Equals(origGuid,
                                                                                            texture.properties.getProperty("TFCFileGuid").valueStruct) &&
                                    oldMipmap.width != 0 && mipmap.newData.Length <= oldMipmap.compressedSize)
                                {
                                    try
                                    {
                                        using (FileStream fs = new FileStream(archiveFile, FileMode.Open, FileAccess.Write))
                                        {
                                            fs.JumpTo(oldMipmap.dataOffset);
                                            mipmap.dataOffset = oldMipmap.dataOffset;
                                            fs.WriteFromBuffer(mipmap.newData);
                                        }
                                    }
                                    catch
                                    {
                                        throw new Exception("Problem with access to TFC file: " + archiveFile);
                                    }
                                }
                                else
                                {
                                    try
                                    {
                                        using (FileStream fs = new FileStream(archiveFile, FileMode.Open, FileAccess.Write))
                                        {
                                            fs.SeekEnd();
                                            mipmap.dataOffset = (uint)fs.Position;
                                            fs.WriteFromBuffer(mipmap.newData);
                                        }
                                    }
                                    catch
                                    {
                                        throw new Exception("Problem with access to TFC file: " + archiveFile);
                                    }
                                }
                            }
                            else
                            {
                                if (arcTexture.mipMapsList[m].width != mipmap.width ||
                                    arcTexture.mipMapsList[m].height != mipmap.height)
                                {
                                    throw new Exception();
                                }
                                mipmap.dataOffset = arcTexture.mipMapsList[m].dataOffset;
                            }
                        }
                    }

                    mipmap.width  = image.mipMaps[m].width;
                    mipmap.height = image.mipMaps[m].height;
                    mipmaps.Add(mipmap);
                    if (texture.mipMapsList.Count() == 1)
                    {
                        break;
                    }
                }
                texture.replaceMipMaps(mipmaps);
                texture.properties.setIntValue("SizeX", texture.mipMapsList.First().width);
                texture.properties.setIntValue("SizeY", texture.mipMapsList.First().height);
                if (texture.properties.exists("MipTailBaseIdx"))
                {
                    texture.properties.setIntValue("MipTailBaseIdx", texture.mipMapsList.Count() - 1);
                }
                if (GameData.gameType == MeType.ME1_TYPE && crc == 0x39A26907)
                {
                    if (!texture.properties.exists("LODGroup"))
                    {
                        texture.properties.addByteValue("LODGroup", "TEXTUREGROUP_Character", 1025);
                    }
                    else
                    {
                        texture.properties.setByteValue("LODGroup", "TEXTUREGROUP_Character", 1025);
                    }
                }

                using (MemoryStream newData = new MemoryStream())
                {
                    newData.WriteFromBuffer(texture.properties.toArray());
                    newData.WriteFromBuffer(texture.toArray(0)); // filled later
                    package.setExportData(nodeTexture.exportID, newData.ToArray());
                }

                using (MemoryStream newData = new MemoryStream())
                {
                    newData.WriteFromBuffer(texture.properties.toArray());
                    newData.WriteFromBuffer(texture.toArray(package.exportsTable[nodeTexture.exportID].dataOffset + (uint)newData.Position));
                    package.setExportData(nodeTexture.exportID, newData.ToArray());
                }

                if (GameData.gameType == MeType.ME1_TYPE)
                {
                    if (master)
                    {
                        masterTextures.Add(texture);
                    }
                }
                else
                {
                    if (triggerCacheCpr)
                    {
                        cprTexture = texture;
                    }
                    if (triggerCacheArc)
                    {
                        arcTexture = texture;
                    }
                }
skip:
                package = null;
            }
            masterTextures = null;
            arcTexture     = cprTexture = null;

            return(errors);
        }