public string ReadTextureEntry(ResourceEntry entry, XmlWriter resourceXML, string name) { TextureResource resource = new TextureResource(); using (MemoryStream stream = new MemoryStream(entry.Data)) { resource.Deserialize(entry.Version, stream, Endian); } string FetchedName = ""; if (_TextureNames.ContainsKey(resource.NameHash)) { FetchedName = _TextureNames[resource.NameHash]; if (!string.IsNullOrEmpty(FetchedName)) { name = FetchedName; } } resourceXML.WriteElementString("File", name); // We lack the file hash in M3 and M1: DE. So we have to add it to the file. var game = GameStorage.Instance.GetSelectedGame(); if (game.GameType == GamesEnumerator.MafiaI_DE || game.GameType == GamesEnumerator.MafiaIII) { resourceXML.WriteElementString("FileHash", resource.NameHash.ToString()); } resourceXML.WriteElementString("HasMIP", resource.HasMIP.ToString()); entry.Data = resource.Data; return(name); }
public ResourceEntry ReadTextureEntry(ResourceEntry entry, XmlWriter resourceXML, string name) { TextureResource resource = new TextureResource(); resource.Deserialize(entry.Version, new MemoryStream(entry.Data), Endian.Little); resourceXML.WriteElementString("File", name); resourceXML.WriteElementString("HasMIP", resource.HasMIP.ToString()); entry.Data = resource.Data; return(entry); }
public void ExtractPatch(FileInfo file) { XmlWriterSettings settings = new XmlWriterSettings(); settings.Indent = true; settings.IndentChars = ("\t"); settings.OmitXmlDeclaration = true; string extractedPath = Path.Combine(file.Directory.FullName, "extracted"); if (!Directory.Exists(extractedPath)) { Directory.CreateDirectory(extractedPath); } string finalPath = Path.Combine(extractedPath, file.Name); Directory.CreateDirectory(finalPath); Log.WriteLine("Begin unpacking and saving files.."); XmlWriter resourceXML = XmlWriter.Create(finalPath + "/SDSContent.xml", settings); resourceXML.WriteStartElement("SDSResource"); PatchFile patchFile = null; using (var input = File.OpenRead(file.FullName)) { using (Stream data = ArchiveEncryption.Unwrap(input)) { patchFile = new PatchFile(); patchFile.file = new FileInfo(file.FullName + ".patch"); patchFile.Deserialize(data ?? input, Endian.Little); } } Dictionary <string, Dictionary <int, string> > sortedResources = new Dictionary <string, Dictionary <int, string> >(); Dictionary <string, List <KeyValuePair <int, bool> > > resPatchAvailable = new Dictionary <string, List <KeyValuePair <int, bool> > >(); for (int i = 0; i < ResourceTypes.Count; i++) { sortedResources.Add(ResourceTypes[i].Name, new Dictionary <int, string>()); resPatchAvailable.Add(ResourceTypes[i].Name, new List <KeyValuePair <int, bool> >()); } for (int i = 0; i < ResourceEntries.Count; i++) { var type = ResourceTypes[_ResourceEntries[i].TypeId].Name; var name = (type == "Mipmap" ? ResourceNames[i].Remove(0, 4) : ResourceNames[i]); if (sortedResources.ContainsKey(type)) { sortedResources[type].Add(i, name); if (patchFile.UnkInts1.Contains(i)) { resPatchAvailable[type].Add(new KeyValuePair <int, bool>(i, false)); } } } for (int i = 0; i < patchFile.resources.Length; i++) { var entry = patchFile.resources[i]; string type = ""; if (entry.TypeId < ResourceTypes.Count) { type = ResourceTypes[entry.TypeId].Name; } else { // NB: M2DE's midtown.sds.patch seems to have a bogus type. I think its a MipMap, but // I've had to implement a huge-ass fallback hack just to accomodate this bogus entry. type = "Unknown"; } string name = string.Format("{0}_{1}", type, i); if (resPatchAvailable.ContainsKey(type)) { for (int z = 0; z < resPatchAvailable[type].Count; z++) { var res = resPatchAvailable[type][z]; if (type == "Texture" || type == "Mipmap") { TextureResource tRes = new TextureResource(); tRes.Deserialize(entry.Version, new MemoryStream(entry.Data), Endian.Little); var resName = sortedResources[type][res.Key]; var hash = FNV64.Hash(resName); if (tRes.NameHash == hash) { Console.WriteLine("Detected possible candidate: {0}", resName); name = resName; break; } } else { if (!res.Value) { string StoredName = sortedResources[type][res.Key]; if (!StoredName.Equals("not available")) { name = StoredName; } resPatchAvailable[type][z] = new KeyValuePair <int, bool>(res.Key, true); break; } } } } bool bContainsDDS = (name.Contains(".dds")); var saveName = ""; resourceXML.WriteStartElement("ResourceEntry"); resourceXML.WriteElementString("Type", type); switch (type) { case "Texture": var textureName = (!bContainsDDS) ? name + ".dds" : name; ReadTextureEntry(entry, resourceXML, name); saveName = textureName; break; case "Mipmap": var mipName = (!bContainsDDS) ? "MIP_ " + name + ".dds" : "MIP_ " + name; ReadMipmapEntry(entry, resourceXML, name); saveName = mipName; break; case "IndexBufferPool": saveName = ReadBasicEntry(resourceXML, name); break; case "VertexBufferPool": saveName = ReadBasicEntry(resourceXML, name); break; case "AnimalTrafficPaths": saveName = ReadBasicEntry(resourceXML, name); break; case "FrameResource": saveName = ReadBasicEntry(resourceXML, name); break; case "Translokator": saveName = ReadBasicEntry(resourceXML, name); break; case "Effects": saveName = ReadBasicEntry(resourceXML, name); break; case "FrameNameTable": saveName = ReadBasicEntry(resourceXML, name); break; case "EntityDataStorage": saveName = ReadBasicEntry(resourceXML, name); break; case "PREFAB": saveName = ReadBasicEntry(resourceXML, name); break; case "ItemDesc": saveName = ReadBasicEntry(resourceXML, name); break; case "Actors": saveName = ReadBasicEntry(resourceXML, name); break; case "Collisions": saveName = ReadBasicEntry(resourceXML, name); break; case "Animation2": saveName = ReadBasicEntry(resourceXML, name); break; case "NAV_AIWORLD_DATA": saveName = ReadBasicEntry(resourceXML, name); break; case "NAV_OBJ_DATA": saveName = ReadBasicEntry(resourceXML, name); break; case "NAV_HPD_DATA": saveName = ReadBasicEntry(resourceXML, name); break; case "FxAnimSet": saveName = ReadBasicEntry(resourceXML, name); break; case "FxActor": saveName = ReadBasicEntry(resourceXML, name); break; case "Sound": ReadSoundEntry(entry, resourceXML, name, finalPath); saveName = name + ".fsb"; break; case "Script": ReadScriptEntry(entry, resourceXML, finalPath); continue; case "AudioSectors": ReadAudioSectorEntry(entry, resourceXML, name, finalPath); saveName = name; break; default: saveName = name; Console.WriteLine("Unhandled Resource Type {0}", type); break; } resourceXML.WriteElementString("Version", entry.Version.ToString()); File.WriteAllBytes(finalPath + "/" + saveName, entry.Data); resourceXML.WriteEndElement(); } resourceXML.WriteEndElement(); resourceXML.Flush(); resourceXML.Dispose(); }