public long AddFile(ArcFileEntry file) { long ptr = files.Count; if (file.id != 0xFFFF) { file.id = (ushort)cid; } cid++; files.Add(file); return(ptr); }
public static void Install() { // get gamepath and Mod folder string gamepath = Path.GetFullPath(".\\"); string ModFolder = Path.Combine(gamepath, "Mod"); ArcFileSystem fs = new ArcFileSystem(); // Iterate through each file in Mod folder and add it to the proxy ARC file foreach (string file in Directory.GetFiles(ModFolder, "*.ks", SearchOption.AllDirectories)) { string name = Path.GetFileName(file); ArcFileEntry arcFile = !fs.FileExists(file) ? fs.CreateFile(name) : fs.GetFile(file); arcFile.Pointer = new WindowsFilePointer(file); } foreach (string file in Directory.GetFiles(ModFolder, "*.ogg", SearchOption.AllDirectories)) { string name = Path.GetFileName(file); ArcFileEntry arcFile = !fs.FileExists(file) ? fs.CreateFile(name) : fs.GetFile(file); arcFile.Pointer = new WindowsFilePointer(file); } // Save the ARC file on disk because the game does not support loading ARC from meory easily // the temp ARC is saved in ML_temp folder in game's folder, so as to not get in the way of general mods if (!Directory.Exists(Path.Combine(gamepath, "ML_temp"))) { Directory.CreateDirectory(Path.Combine(gamepath, "ML_temp")); } using (FileStream fStream = File.Create(Path.Combine(gamepath, "ML_temp\\ML_temp.arc"))) { fs.Save(fStream); } // Get the game's file system and add our custom ARC file FileSystemArchive gameFileSystem = GameUty.FileSystem as FileSystemArchive; gameFileSystem.AddArchive(Path.Combine(gamepath, "ML_temp\\ML_temp.arc")); // load custom arcs, cuz yolo foreach (string arc in Directory.GetFiles(ModFolder, "*.arc", SearchOption.AllDirectories)) { gameFileSystem.AddArchive(arc); } }
private static void DumpArcNode(Stream arcstr, ArcHeader head, ArcNode node, string destroot, string nameoverride = null) { string nodeName = nameoverride; arcstr.Seek(node.filenameOffset + head.stringOffset + 0x20, SeekOrigin.Begin); if (nodeName == null) { nodeName = Data.ReadString(arcstr); } destroot += "\\" + nodeName; Directory.CreateDirectory(destroot); for (int i = 0; i < node.entryCount; ++i) { ArcFileEntry curr = new ArcFileEntry(arcstr, head, (int)(node.entryOffset + i)); if (curr.id == 0xFFFF) //subdirectory { if (curr.filenameOffset != 0 && curr.filenameOffset != 2) //don't go to "." and ".." { ArcNode dirNode = new ArcNode(arcstr, (int)curr.dataOffset); //Some arc packing programs have a glitch arcstr.Seek(curr.filenameOffset + head.stringOffset + 0x20, SeekOrigin.Begin); //People use them so just work around it DumpArcNode(arcstr, head, dirNode, destroot, Data.ReadString(arcstr)); } } else //file { arcstr.Seek(curr.filenameOffset + head.stringOffset + 0x20, SeekOrigin.Begin); string currName = Data.ReadString(arcstr); FileStream dest = new FileStream(destroot + "\\" + currName, FileMode.Create); int read = 0; byte[] buff = new byte[1024]; arcstr.Seek(curr.dataOffset + head.dataStart + 0x20, SeekOrigin.Begin); while (read < curr.dataSize) { int r = arcstr.Read(buff, 0, (int)Math.Min(1024, curr.dataSize - read)); dest.Write(buff, 0, r); read += r; } dest.Close(); } } }
private static ArcInfo BuildArcInfo(string dir, string arcdir, long parent, Dictionary <string, ushort> dirStrings, ArcInfo ai) { DirectoryInfo di = new DirectoryInfo(dir); string curdir; if (arcdir != "") { curdir = arcdir + "/" + di.Name; } else { curdir = di.Name; } ArcNode dirNode = new ArcNode(); if (!dirStrings.ContainsKey(dir)) { dirNode.filenameOffset = (uint)ai.AddString(di.Name); } else { dirNode.filenameOffset = dirStrings[dir]; } dirNode.unknown = GCN.CreateHash(di.Name); dirNode.entryOffset = (uint)(ai.files.Count); dirNode.entryCount = 0; dirNode.WritePath = curdir; if (ai.nodes.Count == 0) { dirNode.type = BitConverter.ToUInt32(new byte[4] { (byte)'T', (byte)'O', (byte)'O', (byte)'R' }, 0); } else { byte[] type = new byte[4]; for (int i = 0; i < 4; i++) { if (i < di.Name.Length) { type[3 - i] = (byte)(di.Name.ToUpper())[i]; } else { type[3 - i] = 0x20; } } dirNode.type = BitConverter.ToUInt32(type, 0); } long coffset = ai.AddNode(dirNode); string[] files = Directory.EnumerateFiles(dir, "*", SearchOption.TopDirectoryOnly).ToArray(); foreach (string file in files) { FileInfo fi = new FileInfo(file); ArcFileEntry fentry = new ArcFileEntry(); fentry.id = 0; if (dirStrings.ContainsKey(file)) { fentry.filenameOffset = dirStrings[file]; } else { fentry.filenameOffset = (ushort)ai.AddString(fi.Name); } fentry.dataOffset = (uint)ai.CountData(file, out fentry.dataSize); fentry.WritePath = curdir + "/" + fi.Name; fentry.unknown = GCN.CreateHash(fi.Name); fentry.unknown2 = 0x1100; ai.AddFile(fentry); dirNode.entryCount++; } long fileoff = coffset; string[] dirs = Directory.EnumerateDirectories(dir, "*", SearchOption.TopDirectoryOnly).ToArray(); foreach (string idir in dirs) { DirectoryInfo idi = new DirectoryInfo(idir); ArcFileEntry dentry = new ArcFileEntry(); dentry.id = 0xFFFF; dentry.filenameOffset = (ushort)ai.AddString(idi.Name); dirStrings.Add(idir, dentry.filenameOffset); dentry.dataOffset = (uint)(++fileoff); fileoff += Directory.EnumerateDirectories(idir, "*", SearchOption.AllDirectories).Count(); dentry.dataSize = 16; dentry.WritePath = curdir; dentry.unknown = GCN.CreateHash(idi.Name); dentry.unknown2 = 0x0200; ai.AddFile(dentry); dirNode.entryCount++; } ArcFileEntry cEntry = new ArcFileEntry(); cEntry.id = 0xFFFF; cEntry.filenameOffset = 0; cEntry.WritePath = curdir; cEntry.dataOffset = (uint)coffset; cEntry.dataSize = 16; cEntry.unknown = 0x2E; cEntry.unknown2 = 0x0200; ai.AddFile(cEntry); ArcFileEntry pEntry = new ArcFileEntry(); pEntry.filenameOffset = 2; pEntry.id = 0xFFFF; pEntry.WritePath = arcdir; pEntry.dataOffset = (uint)parent; pEntry.dataSize = 16; pEntry.unknown = 0xB8; pEntry.unknown2 = 0x0200; ai.AddFile(pEntry); dirNode.entryCount += 2; ai.nodes[ai.nodes.Count - 1] = dirNode; foreach (string idir in dirs) { ai = BuildArcInfo(idir, curdir, coffset, dirStrings, ai); } return(ai); }