public static void ExportINI(DllIniData IniData, Dictionary <string, bool> itemsToExport, string fileName) { string dstfol = Path.GetDirectoryName(fileName); DllIniData output = new DllIniData() { Name = IniData.Name, Game = IniData.Game, Exports = IniData.Exports, TexLists = IniData.TexLists }; List <string> labels = new List <string>(); foreach (KeyValuePair <string, FileTypeHash> item in IniData.Files.Where(i => itemsToExport[i.Key])) { Directory.CreateDirectory(Path.GetDirectoryName(Path.Combine(dstfol, item.Key))); File.Copy(item.Key, Path.Combine(dstfol, item.Key), true); switch (item.Value.Type) { case "landtable": LandTable tbl = LandTable.LoadFromFile(item.Key); labels.AddRange(tbl.GetLabels()); break; case "model": case "basicmodel": case "chunkmodel": case "gcmodel": case "basicdxmodel": NJS_OBJECT mdl = new ModelFile(item.Key).Model; labels.AddRange(mdl.GetLabels()); break; case "animation": NJS_MOTION ani = NJS_MOTION.Load(item.Key); labels.Add(ani.Name); break; } output.Files.Add(item.Key, new FileTypeHash(item.Value.Type, null)); } output.Items = new List <DllItemInfo>(IniData.Items.Where(a => labels.Contains(a.Label))); foreach (var item in IniData.DataItems.Where(i => itemsToExport[i.Filename])) { Directory.CreateDirectory(Path.Combine(dstfol, item.Filename)); CopyDirectory(new DirectoryInfo(item.Filename), Path.Combine(dstfol, item.Filename)); output.DataItems.Add(item); } IniSerializer.Serialize(output, fileName); }
private void button6_Click(object sender, EventArgs e) { using (SaveFileDialog fd = new SaveFileDialog() { DefaultExt = "ini", Filter = "INI files|*.ini", InitialDirectory = Environment.CurrentDirectory, RestoreDirectory = true }) if (fd.ShowDialog(this) == DialogResult.OK) { string dstfol = Path.GetDirectoryName(fd.FileName); DllIniData output = new DllIniData() { Name = IniData.Name, Game = IniData.Game, Exports = IniData.Exports, TexLists = IniData.TexLists, Files = new DictionaryContainer <FileTypeHash>() }; List <string> labels = new List <string>(); foreach (KeyValuePair <string, FileTypeHash> item in IniData.Files.Where((a, i) => listView1.CheckedIndices.Contains(i))) { Directory.CreateDirectory(Path.GetDirectoryName(Path.Combine(dstfol, item.Key))); File.Copy(item.Key, Path.Combine(dstfol, item.Key), true); switch (item.Value.Type) { case "landtable": LandTable tbl = LandTable.LoadFromFile(item.Key); labels.AddRange(tbl.GetLabels()); break; case "model": case "basicmodel": case "chunkmodel": case "basicdxmodel": NJS_OBJECT mdl = new ModelFile(item.Key).Model; labels.AddRange(mdl.GetLabels()); break; case "animation": Animation ani = Animation.Load(item.Key); labels.Add(ani.Name); break; } output.Files.Add(item.Key, new FileTypeHash(item.Value.Type, null)); } output.Items = new List <DllItemInfo>(IniData.Items.Where(a => labels.Contains(a.Label))); IniSerializer.Serialize(output, fd.FileName); } }
public static void ExportCPP(DllIniData IniData, Dictionary <string, bool> itemsToExport, string fileName) { using (TextWriter writer = File.CreateText(fileName)) { bool SA2 = IniData.Game == SA_Tools.SplitDLL.Game.SA2B; ModelFormat modelfmt = SA2 ? ModelFormat.Chunk : ModelFormat.BasicDX; LandTableFormat landfmt = SA2 ? LandTableFormat.SA2 : LandTableFormat.SADX; writer.WriteLine("// Generated by SA Tools DLL Mod Generator"); writer.WriteLine(); if (SA2) { writer.WriteLine("#include \"SA2ModLoader.h\""); } else { writer.WriteLine("#include \"SADXModLoader.h\""); } writer.WriteLine(); List <string> labels = new List <string>(); Dictionary <string, uint> texlists = new Dictionary <string, uint>(); foreach (KeyValuePair <string, FileTypeHash> item in IniData.Files.Where(i => itemsToExport[i.Key])) { switch (item.Value.Type) { case "landtable": LandTable tbl = LandTable.LoadFromFile(item.Key); texlists.Add(tbl.Name, tbl.TextureList); tbl.ToStructVariables(writer, landfmt, new List <string>()); labels.AddRange(tbl.GetLabels()); break; case "model": NJS_OBJECT mdl = new ModelFile(item.Key).Model; mdl.ToStructVariables(writer, modelfmt == ModelFormat.BasicDX, new List <string>()); labels.AddRange(mdl.GetLabels()); break; case "basicmodel": case "chunkmodel": case "gcmodel": mdl = new ModelFile(item.Key).Model; mdl.ToStructVariables(writer, false, new List <string>()); labels.AddRange(mdl.GetLabels()); break; case "basicdxmodel": mdl = new ModelFile(item.Key).Model; mdl.ToStructVariables(writer, true, new List <string>()); labels.AddRange(mdl.GetLabels()); break; case "animation": NJS_MOTION ani = NJS_MOTION.Load(item.Key); ani.ToStructVariables(writer); labels.Add(ani.Name); break; } writer.WriteLine(); } foreach (var item in IniData.DataItems.Where(i => itemsToExport[i.Filename])) { switch (item.Type) { case "animindexlist": { SortedDictionary <short, NJS_MOTION> anims = new SortedDictionary <short, NJS_MOTION>(); foreach (string file in Directory.GetFiles(item.Filename, "*.saanim")) { if (short.TryParse(Path.GetFileNameWithoutExtension(file), NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out short i)) { anims.Add(i, NJS_MOTION.Load(file)); } } foreach (KeyValuePair <short, NJS_MOTION> obj in anims) { obj.Value.ToStructVariables(writer); writer.WriteLine(); } writer.WriteLine("AnimationIndex {0}[] = {{", item.Export); List <string> objs = new List <string>(anims.Count); foreach (KeyValuePair <short, NJS_MOTION> obj in anims) { objs.Add($"{{ {obj.Key}, {obj.Value.ModelParts}, &{obj.Value.Name} }}"); } objs.Add("{ -1 }"); writer.WriteLine("\t" + string.Join("," + Environment.NewLine + "\t", objs.ToArray())); writer.WriteLine("};"); } break; case "charaobjectdatalist": { foreach (string file in Directory.GetFiles(item.Filename, "*.sa2mdl")) { new ModelFile(file).Model.ToStructVariables(writer, false, new List <string>()); writer.WriteLine(); } foreach (string file in Directory.GetFiles(item.Filename, "*.saanim")) { NJS_MOTION.Load(file).ToStructVariables(writer); writer.WriteLine(); } var data = IniSerializer.Deserialize <CharaObjectData[]>(Path.Combine(item.Filename, "info.ini")); writer.WriteLine("CharaObjectData {0}[] = {{", item.Export); List <string> objs = new List <string>(data.Length); foreach (var obj in data) { objs.Add(obj.ToStruct()); } writer.WriteLine("\t" + string.Join("," + Environment.NewLine + "\t", objs.ToArray())); writer.WriteLine("};"); } break; case "kartspecialinfolist": { foreach (string file in Directory.GetFiles(item.Filename, "*.sa2mdl")) { new ModelFile(file).Model.ToStructVariables(writer, false, new List <string>()); writer.WriteLine(); } var data = IniSerializer.Deserialize <KartSpecialInfo[]>(Path.Combine(item.Filename, "info.ini")); writer.WriteLine("KartSpecialInfo {0}[] = {{", item.Export); List <string> objs = new List <string>(data.Length); for (int i = 0; i < data.Length; i++) { KartSpecialInfo obj = data[i]; objs.Add(obj.ToStruct()); texlists.Add($"{item.Export}[{i}]", obj.TexList); } writer.WriteLine("\t" + string.Join("," + Environment.NewLine + "\t", objs.ToArray())); writer.WriteLine("};"); } break; case "kartmodelsarray": { foreach (string file in Directory.GetFiles(item.Filename, "*.sa2bmdl")) { new ModelFile(file).Model.ToStructVariables(writer, false, new List <string>()); writer.WriteLine(); } foreach (string file in Directory.GetFiles(item.Filename, "*.sa1mdl")) { new ModelFile(file).Model.ToStructVariables(writer, false, new List <string>()); writer.WriteLine(); } var data = IniSerializer.Deserialize <CharaObjectData[]>(Path.Combine(item.Filename, "info.ini")); writer.WriteLine("KartModelsArray {0}[] = {{", item.Export); List <string> objs = new List <string>(data.Length); foreach (var obj in data) { objs.Add(obj.ToStruct()); } writer.WriteLine("\t" + string.Join("," + Environment.NewLine + "\t", objs.ToArray())); writer.WriteLine("};"); } break; case "motiontable": { foreach (string file in Directory.GetFiles(item.Filename, "*.saanim")) { NJS_MOTION.Load(file).ToStructVariables(writer); writer.WriteLine(); } var data = IniSerializer.Deserialize <MotionTableEntry[]>(Path.Combine(item.Filename, "info.ini")); writer.WriteLine("MotionTableEntry {0}[] = {{", item.Export); List <string> objs = new List <string>(data.Length); foreach (var obj in data) { objs.Add(obj.ToStruct()); } writer.WriteLine("\t" + string.Join("," + Environment.NewLine + "\t", objs.ToArray())); writer.WriteLine("};"); } break; } } writer.WriteLine("extern \"C\" __declspec(dllexport) void __cdecl Init(const char *path, const HelperFunctions &helperFunctions)"); writer.WriteLine("{"); writer.WriteLine("\tHMODULE handle = GetModuleHandle(L\"{0}\");", IniData.Name); List <string> exports = new List <string>(IniData.Items.Where(item => labels.Contains(item.Label)).Select(item => item.Export).Distinct()); foreach (KeyValuePair <string, string> item in IniData.Exports.Where(item => exports.Contains(item.Key))) { writer.WriteLine("\t{0}{1} = ({0})GetProcAddress(handle, \"{1}\");", typemap[item.Value], item.Key); } foreach (DllItemInfo item in IniData.Items.Where(item => labels.Contains(item.Label))) { if (typemap[IniData.Exports[item.Export]].EndsWith("**")) { writer.WriteLine("\t{0} = &{1};", item.ToString(), item.Label); } else { writer.WriteLine("\t*{0} = {1};", item.ToString(), item.Label); } } foreach (var item in IniData.DataItems.Where(item => itemsToExport[item.Filename])) { switch (item.Type) { case "animindexlist": case "charaobjectdatalist": case "kartspecialinfolist": case "kartmodelsarray": writer.WriteLine("\tHookExport(handle, \"{0}\", {0});", item.Export); break; default: writer.WriteLine("\t{0}{1}_exp = ({0})GetProcAddress(handle, \"{1}\");", typemap[item.Type], item.Export); writer.WriteLine("\t*{0}_exp = {0};", item.Export); break; } } if (texlists.Count > 0 && IniData.TexLists != null && IniData.TexLists.Items != null) { exports = new List <string>(IniData.TexLists.Where(item => texlists.Values.Contains(item.Key)).Select(item => item.Value.Export).Distinct()); foreach (KeyValuePair <string, string> item in IniData.Exports.Where(item => exports.Contains(item.Key))) { writer.WriteLine("\t{0}{1} = ({0})GetProcAddress(handle, \"{1}\");", typemap[item.Value], item.Key); } foreach (KeyValuePair <string, uint> item in texlists.Where(item => IniData.TexLists.ContainsKey(item.Value))) { DllTexListInfo tex = IniData.TexLists[item.Value]; string str; if (tex.Index.HasValue) { str = $"{tex.Export}[{tex.Index.Value}]"; } else { str = tex.Export; } writer.WriteLine("\t{0}.TexList = {1};", item.Key, str); } } writer.WriteLine("}"); writer.WriteLine(); writer.WriteLine("extern \"C\" __declspec(dllexport) const ModInfo {0}ModInfo = {{ ModLoaderVer }};", SA2 ? "SA2" : "SADX"); } }
public static int SplitDLLFile(string datafilename, string inifilename, string projectFolderName) { #if !DEBUG try { #endif byte[] datafile = File.ReadAllBytes(datafilename); IniData inifile = IniSerializer.Deserialize <IniData>(inifilename); uint imageBase = HelperFunctions.SetupEXE(ref datafile).Value; Dictionary <string, int> exports; { int ptr = BitConverter.ToInt32(datafile, BitConverter.ToInt32(datafile, 0x3c) + 4 + 20 + 96); GCHandle handle = GCHandle.Alloc(datafile, GCHandleType.Pinned); IMAGE_EXPORT_DIRECTORY dir = (IMAGE_EXPORT_DIRECTORY)Marshal.PtrToStructure( Marshal.UnsafeAddrOfPinnedArrayElement(datafile, ptr), typeof(IMAGE_EXPORT_DIRECTORY)); handle.Free(); exports = new Dictionary <string, int>(dir.NumberOfFunctions); int nameaddr = dir.AddressOfNames; int ordaddr = dir.AddressOfNameOrdinals; for (int i = 0; i < dir.NumberOfNames; i++) { string name = datafile.GetCString(BitConverter.ToInt32(datafile, nameaddr), System.Text.Encoding.ASCII); int addr = BitConverter.ToInt32(datafile, dir.AddressOfFunctions + (BitConverter.ToInt16(datafile, ordaddr) * 4)); exports.Add(name, addr); nameaddr += 4; ordaddr += 2; } } ModelFormat modelfmt = 0; LandTableFormat landfmt = 0; string modelext = null; string landext = null; switch (inifile.Game) { case Game.SADX: modelfmt = ModelFormat.BasicDX; landfmt = LandTableFormat.SADX; modelext = ".sa1mdl"; landext = ".sa1lvl"; break; case Game.SA2B: modelfmt = ModelFormat.Chunk; landfmt = LandTableFormat.SA2; modelext = ".sa2mdl"; landext = ".sa2lvl"; break; } int itemcount = 0; List <string> labels = new List <string>(); ModelAnimationsDictionary models = new ModelAnimationsDictionary(); DllIniData output = new DllIniData() { Name = inifile.ModuleName, Game = inifile.Game }; Stopwatch timer = new Stopwatch(); timer.Start(); foreach (KeyValuePair <string, FileInfo> item in inifile.Files) { if (string.IsNullOrEmpty(item.Key)) { continue; } FileInfo data = item.Value; string type = data.Type; string name = item.Key; output.Exports[name] = type; int address = exports[name]; string fileOutputPath = ""; if (data.Filename != null) { fileOutputPath = string.Concat(projectFolderName, data.Filename); Console.WriteLine(name + " -> " + fileOutputPath); Directory.CreateDirectory(Path.GetDirectoryName(fileOutputPath)); } else { Console.WriteLine(name); } switch (type) { case "landtable": { LandTable land = new LandTable(datafile, address, imageBase, landfmt) { Description = name }; DllItemInfo info = new DllItemInfo() { Export = name, Label = land.Name }; output.Items.Add(info); if (!labels.Contains(land.Name)) { land.SaveToFile(fileOutputPath, landfmt); output.Files[data.Filename] = new FileTypeHash("landtable", HelperFunctions.FileHash(fileOutputPath)); labels.AddRange(land.GetLabels()); } } break; case "battlelandtable": { LandTable land = new LandTable(datafile, address, imageBase, LandTableFormat.SA2B) { Description = name }; DllItemInfo info = new DllItemInfo() { Export = name, Label = land.Name }; output.Items.Add(info); if (!labels.Contains(land.Name)) { land.SaveToFile(fileOutputPath, LandTableFormat.SA2B); output.Files[data.Filename] = new FileTypeHash("landtable", HelperFunctions.FileHash(fileOutputPath)); labels.AddRange(land.GetLabels()); } } break; case "landtablearray": for (int i = 0; i < data.Length; i++) { int ptr = BitConverter.ToInt32(datafile, address); if (ptr != 0) { ptr = (int)(ptr - imageBase); string idx = name + "[" + i.ToString(NumberFormatInfo.InvariantInfo) + "]"; LandTable land = new LandTable(datafile, ptr, imageBase, landfmt) { Description = idx }; DllItemInfo info = new DllItemInfo() { Export = name, Index = i, Label = land.Name }; output.Items.Add(info); if (!labels.Contains(land.Name)) { string outputFN = Path.Combine(fileOutputPath, i.ToString(NumberFormatInfo.InvariantInfo) + landext); string fileName = Path.Combine(data.Filename, i.ToString(NumberFormatInfo.InvariantInfo) + landext); land.SaveToFile(outputFN, landfmt); output.Files[fileName] = new FileTypeHash("landtable", HelperFunctions.FileHash(outputFN)); labels.AddRange(land.GetLabels()); } } address += 4; } break; case "model": { NJS_OBJECT mdl = new NJS_OBJECT(datafile, address, imageBase, modelfmt, new Dictionary <int, Attach>()); DllItemInfo info = new DllItemInfo() { Export = name, Label = mdl.Name }; output.Items.Add(info); if (!labels.Contains(mdl.Name)) { models.Add(new ModelAnimations(data.Filename, name, mdl, modelfmt)); labels.AddRange(mdl.GetLabels()); } } break; case "morph": { BasicAttach dummy = new BasicAttach(datafile, address, imageBase, modelfmt == ModelFormat.BasicDX); NJS_OBJECT mdl = new NJS_OBJECT() { Attach = dummy }; DllItemInfo info = new DllItemInfo() { Export = name, Label = dummy.Name }; output.Items.Add(info); if (!labels.Contains(dummy.Name)) { models.Add(new ModelAnimations(data.Filename, name, mdl, modelfmt)); labels.AddRange(mdl.GetLabels()); } } break; case "modelarray": for (int i = 0; i < data.Length; i++) { int ptr = BitConverter.ToInt32(datafile, address); if (ptr != 0) { ptr = (int)(ptr - imageBase); NJS_OBJECT mdl = new NJS_OBJECT(datafile, ptr, imageBase, modelfmt, new Dictionary <int, Attach>()); string idx = name + "[" + i.ToString(NumberFormatInfo.InvariantInfo) + "]"; DllItemInfo info = new DllItemInfo() { Export = name, Index = i, Label = mdl.Name }; output.Items.Add(info); if (!labels.Contains(mdl.Name)) { string fn = Path.Combine(data.Filename, i.ToString(NumberFormatInfo.InvariantInfo) + modelext); models.Add(new ModelAnimations(fn, idx, mdl, modelfmt)); labels.AddRange(mdl.GetLabels()); } } address += 4; } break; case "modelsarray": for (int i = 0; i < data.Length; i++) { int ptr = BitConverter.ToInt32(datafile, address); if (ptr != 0) { ptr = (int)(ptr - imageBase); BasicAttach dummy = new BasicAttach(datafile, ptr, imageBase, modelfmt == ModelFormat.BasicDX); NJS_OBJECT mdl = new NJS_OBJECT() { Attach = dummy }; string idx = name + "[" + i.ToString(NumberFormatInfo.InvariantInfo) + "]"; DllItemInfo info = new DllItemInfo() { Export = name, Index = i, Label = dummy.Name }; output.Items.Add(info); if (!labels.Contains(dummy.Name)) { string fn = Path.Combine(data.Filename, i.ToString(NumberFormatInfo.InvariantInfo) + modelext); models.Add(new ModelAnimations(fn, idx, mdl, ModelFormat.BasicDX)); labels.AddRange(mdl.GetLabels()); } } address += 4; } break; case "basicmodel": { NJS_OBJECT mdl = new NJS_OBJECT(datafile, address, imageBase, ModelFormat.Basic, new Dictionary <int, Attach>()); DllItemInfo info = new DllItemInfo() { Export = name, Label = mdl.Name }; output.Items.Add(info); if (!labels.Contains(mdl.Name)) { models.Add(new ModelAnimations(data.Filename, name, mdl, ModelFormat.Basic)); labels.AddRange(mdl.GetLabels()); } } break; case "basicmodelarray": for (int i = 0; i < data.Length; i++) { int ptr = BitConverter.ToInt32(datafile, address); if (ptr != 0) { ptr = (int)(ptr - imageBase); NJS_OBJECT mdl = new NJS_OBJECT(datafile, ptr, imageBase, ModelFormat.Basic, new Dictionary <int, Attach>()); string idx = name + "[" + i.ToString(NumberFormatInfo.InvariantInfo) + "]"; DllItemInfo info = new DllItemInfo() { Export = name, Index = i, Label = mdl.Name }; output.Items.Add(info); if (!labels.Contains(mdl.Name)) { string fn = Path.Combine(data.Filename, i.ToString(NumberFormatInfo.InvariantInfo) + ".sa1mdl"); models.Add(new ModelAnimations(fn, idx, mdl, ModelFormat.Basic)); labels.AddRange(mdl.GetLabels()); } } address += 4; } break; case "basicdxmodel": { NJS_OBJECT mdl = new NJS_OBJECT(datafile, address, imageBase, ModelFormat.BasicDX, new Dictionary <int, Attach>()); DllItemInfo info = new DllItemInfo() { Export = name, Label = mdl.Name }; output.Items.Add(info); if (!labels.Contains(mdl.Name)) { models.Add(new ModelAnimations(data.Filename, name, mdl, ModelFormat.BasicDX)); labels.AddRange(mdl.GetLabels()); } } break; case "basicdxmodelarray": for (int i = 0; i < data.Length; i++) { int ptr = BitConverter.ToInt32(datafile, address); if (ptr != 0) { ptr = (int)(ptr - imageBase); NJS_OBJECT mdl = new NJS_OBJECT(datafile, ptr, imageBase, ModelFormat.BasicDX, new Dictionary <int, Attach>()); string idx = name + "[" + i.ToString(NumberFormatInfo.InvariantInfo) + "]"; DllItemInfo info = new DllItemInfo() { Export = name, Index = i, Label = mdl.Name }; output.Items.Add(info); if (!labels.Contains(mdl.Name)) { string fn = Path.Combine(data.Filename, i.ToString(NumberFormatInfo.InvariantInfo) + ".sa1mdl"); models.Add(new ModelAnimations(fn, idx, mdl, ModelFormat.BasicDX)); labels.AddRange(mdl.GetLabels()); } } address += 4; } break; case "chunkmodel": { NJS_OBJECT mdl = new NJS_OBJECT(datafile, address, imageBase, ModelFormat.Chunk, new Dictionary <int, Attach>()); DllItemInfo info = new DllItemInfo() { Export = name, Label = mdl.Name }; output.Items.Add(info); if (!labels.Contains(mdl.Name)) { models.Add(new ModelAnimations(data.Filename, name, mdl, ModelFormat.Chunk)); labels.AddRange(mdl.GetLabels()); } } break; case "chunkmodelarray": for (int i = 0; i < data.Length; i++) { int ptr = BitConverter.ToInt32(datafile, address); if (ptr != 0) { ptr = (int)(ptr - imageBase); NJS_OBJECT mdl = new NJS_OBJECT(datafile, ptr, imageBase, ModelFormat.Chunk, new Dictionary <int, Attach>()); string idx = name + "[" + i.ToString(NumberFormatInfo.InvariantInfo) + "]"; DllItemInfo info = new DllItemInfo() { Export = name, Index = i, Label = mdl.Name }; output.Items.Add(info); if (!labels.Contains(mdl.Name)) { string fn = Path.Combine(data.Filename, i.ToString(NumberFormatInfo.InvariantInfo) + ".sa2mdl"); models.Add(new ModelAnimations(fn, idx, mdl, ModelFormat.Chunk)); labels.AddRange(mdl.GetLabels()); } } address += 4; } break; case "actionarray": for (int i = 0; i < data.Length; i++) { int ptr = BitConverter.ToInt32(datafile, address); if (ptr != 0) { ptr = (int)(ptr - imageBase); NJS_ACTION ani = new NJS_ACTION(datafile, ptr, imageBase, modelfmt, new Dictionary <int, Attach>()); string idx = name + "[" + i.ToString(NumberFormatInfo.InvariantInfo) + "]"; ani.Animation.Name = item.Key + "_" + i; DllItemInfo info = new DllItemInfo() { Export = name, Index = i, Label = ani.Animation.Name, Field = "motion" }; output.Items.Add(info); info = new DllItemInfo() { Export = name, Index = i, Label = ani.Model.Name, Field = "object" }; output.Items.Add(info); string outputFN = Path.Combine(fileOutputPath, i.ToString(NumberFormatInfo.InvariantInfo) + ".saanim"); string fn = Path.Combine(data.Filename, i.ToString(NumberFormatInfo.InvariantInfo) + ".saanim"); ani.Animation.Save(outputFN); output.Files[fn] = new FileTypeHash("animation", HelperFunctions.FileHash(outputFN)); if (models.Contains(ani.Model.Name)) { ModelAnimations mdl = models[ani.Model.Name]; System.Text.StringBuilder sb = new System.Text.StringBuilder(260); PathRelativePathTo(sb, Path.GetFullPath(Path.Combine(projectFolderName, mdl.Filename)), 0, Path.GetFullPath(outputFN), 0); mdl.Animations.Add(sb.ToString()); // this is where the problem is } else { string mfn = Path.ChangeExtension(fn, modelext); string outputmfn = Path.Combine(projectFolderName, mfn); string animationName = Path.GetFileName(outputFN); ModelFile.CreateFile(outputmfn, ani.Model, new[] { animationName }, null, idx + "->object", null, modelfmt); output.Files[mfn] = new FileTypeHash("model", HelperFunctions.FileHash(outputmfn)); } } address += 4; } break; case "texlist": if (output.TexLists == null) { output.TexLists = new TexListContainer(); } output.TexLists.Add((uint)(address + imageBase), new DllTexListInfo(name, null)); break; case "texlistarray": if (output.TexLists == null) { output.TexLists = new TexListContainer(); } for (int i = 0; i < data.Length; i++) { uint ptr = BitConverter.ToUInt32(datafile, address); if (ptr != 0 && !output.TexLists.ContainsKey(ptr)) { output.TexLists.Add(ptr, new DllTexListInfo(name, i)); } address += 4; } break; case "animindexlist": { Directory.CreateDirectory(fileOutputPath); List <string> hashes = new List <string>(); int i = ByteConverter.ToInt16(datafile, address); while (i != -1) { new NJS_MOTION(datafile, datafile.GetPointer(address + 4, imageBase), imageBase, ByteConverter.ToInt16(datafile, address + 2)) .Save(fileOutputPath + "/" + i.ToString(NumberFormatInfo.InvariantInfo) + ".saanim"); hashes.Add(i.ToString(NumberFormatInfo.InvariantInfo) + ":" + HelperFunctions.FileHash(fileOutputPath + "/" + i.ToString(NumberFormatInfo.InvariantInfo) + ".saanim")); address += 8; i = ByteConverter.ToInt16(datafile, address); } output.DataItems.Add(new DllDataItemInfo() { Type = type, Export = name, Filename = data.Filename, MD5Hash = string.Join("|", hashes.ToArray()) }); } break; case "charaobjectdatalist": { Directory.CreateDirectory(fileOutputPath); List <CharaObjectData> result = new List <CharaObjectData>(); List <string> hashes = new List <string>(); for (int i = 0; i < data.Length; i++) { string chnm = charaobjectnames[i]; CharaObjectData chara = new CharaObjectData(); NJS_OBJECT model = new NJS_OBJECT(datafile, (int)(BitConverter.ToInt32(datafile, address) - imageBase), imageBase, ModelFormat.Chunk, new Dictionary <int, Attach>()); chara.MainModel = model.Name; NJS_MOTION anim = new NJS_MOTION(datafile, (int)(BitConverter.ToInt32(datafile, address + 4) - imageBase), imageBase, model.CountAnimated()); chara.Animation1 = anim.Name; anim.Save(Path.Combine(fileOutputPath, $"{chnm} Anim 1.saanim")); hashes.Add($"{chnm} Anim 1.saanim:" + HelperFunctions.FileHash(Path.Combine(fileOutputPath, $"{chnm} Anim 1.saanim"))); anim = new NJS_MOTION(datafile, (int)(BitConverter.ToInt32(datafile, address + 8) - imageBase), imageBase, model.CountAnimated()); chara.Animation2 = anim.Name; anim.Save(Path.Combine(fileOutputPath, $"{chnm} Anim 2.saanim")); hashes.Add($"{chnm} Anim 2.saanim:" + HelperFunctions.FileHash(Path.Combine(fileOutputPath, $"{chnm} Anim 2.saanim"))); anim = new NJS_MOTION(datafile, (int)(BitConverter.ToInt32(datafile, address + 12) - imageBase), imageBase, model.CountAnimated()); chara.Animation3 = anim.Name; anim.Save(Path.Combine(fileOutputPath, $"{chnm} Anim 3.saanim")); hashes.Add($"{chnm} Anim 3.saanim:" + HelperFunctions.FileHash(Path.Combine(fileOutputPath, $"{chnm} Anim 3.saanim"))); ModelFile.CreateFile(Path.Combine(fileOutputPath, $"{chnm}.sa2mdl"), model, new[] { $"{chnm} Anim 1.saanim", $"{chnm} Anim 2.saanim", $"{chnm} Anim 3.saanim" }, null, null, null, ModelFormat.Chunk); hashes.Add($"{chnm}.sa2mdl:" + HelperFunctions.FileHash(Path.Combine(fileOutputPath, $"{chnm}.sa2mdl"))); int ptr = BitConverter.ToInt32(datafile, address + 16); if (ptr != 0) { model = new NJS_OBJECT(datafile, (int)(ptr - imageBase), imageBase, ModelFormat.Chunk, new Dictionary <int, Attach>()); chara.AccessoryModel = model.Name; chara.AccessoryAttachNode = "object_" + (BitConverter.ToInt32(datafile, address + 20) - imageBase).ToString("X8"); ModelFile.CreateFile(Path.Combine(fileOutputPath, $"{chnm} Accessory.sa2mdl"), model, null, null, null, null, ModelFormat.Chunk); hashes.Add($"{chnm} Accessory.sa2mdl:" + HelperFunctions.FileHash(Path.Combine(fileOutputPath, $"{chnm} Accessory.sa2mdl"))); } ptr = BitConverter.ToInt32(datafile, address + 24); if (ptr != 0) { model = new NJS_OBJECT(datafile, (int)(ptr - imageBase), imageBase, ModelFormat.Chunk, new Dictionary <int, Attach>()); chara.SuperModel = model.Name; anim = new NJS_MOTION(datafile, (int)(BitConverter.ToInt32(datafile, address + 28) - imageBase), imageBase, model.CountAnimated()); chara.SuperAnimation1 = anim.Name; anim.Save(Path.Combine(fileOutputPath, $"Super {chnm} Anim 1.saanim")); hashes.Add($"Super {chnm} Anim 1.saanim:" + HelperFunctions.FileHash(Path.Combine(fileOutputPath, $"Super {chnm} Anim 1.saanim"))); anim = new NJS_MOTION(datafile, (int)(BitConverter.ToInt32(datafile, address + 32) - imageBase), imageBase, model.CountAnimated()); chara.SuperAnimation2 = anim.Name; anim.Save(Path.Combine(fileOutputPath, $"Super {chnm} Anim 2.saanim")); hashes.Add($"Super {chnm} Anim 2.saanim:" + HelperFunctions.FileHash(Path.Combine(fileOutputPath, $"Super {chnm} Anim 2.saanim"))); anim = new NJS_MOTION(datafile, (int)(BitConverter.ToInt32(datafile, address + 36) - imageBase), imageBase, model.CountAnimated()); chara.SuperAnimation3 = anim.Name; anim.Save(Path.Combine(fileOutputPath, $"Super {chnm} Anim 3.saanim")); hashes.Add($"Super {chnm} Anim 3.saanim:" + HelperFunctions.FileHash(Path.Combine(fileOutputPath, $"Super {chnm} Anim 3.saanim"))); ModelFile.CreateFile(Path.Combine(fileOutputPath, $"Super {chnm}.sa2mdl"), model, new[] { $"Super {chnm} Anim 1.saanim", $"Super {chnm} Anim 2.saanim", $"Super {chnm} Anim 3.saanim" }, null, null, null, ModelFormat.Chunk); hashes.Add($"Super {chnm}.sa2mdl:" + HelperFunctions.FileHash(Path.Combine(fileOutputPath, $"Super {chnm}.sa2mdl"))); } chara.Unknown1 = BitConverter.ToInt32(datafile, address + 40); chara.Rating = BitConverter.ToInt32(datafile, address + 44); chara.DescriptionID = BitConverter.ToInt32(datafile, address + 48); chara.TextBackTexture = BitConverter.ToInt32(datafile, address + 52); chara.Unknown5 = BitConverter.ToSingle(datafile, address + 56); result.Add(chara); address += 60; } IniSerializer.Serialize(result, Path.Combine(fileOutputPath, "info.ini")); hashes.Add("info.ini:" + HelperFunctions.FileHash(Path.Combine(fileOutputPath, "info.ini"))); output.DataItems.Add(new DllDataItemInfo() { Type = type, Export = name, Filename = data.Filename, MD5Hash = string.Join("|", hashes.ToArray()) }); } break; case "kartspecialinfolist": { Directory.CreateDirectory(fileOutputPath); List <KartSpecialInfo> result = new List <KartSpecialInfo>(); List <string> hashes = new List <string>(); for (int i = 0; i < data.Length; i++) { KartSpecialInfo kart = new KartSpecialInfo { ID = ByteConverter.ToInt32(datafile, address) }; NJS_OBJECT model = new NJS_OBJECT(datafile, (int)(BitConverter.ToInt32(datafile, address + 4) - imageBase), imageBase, ModelFormat.Chunk, new Dictionary <int, Attach>()); kart.Model = model.Name; ModelFile.CreateFile(Path.Combine(fileOutputPath, $"{i}.sa2mdl"), model, null, null, null, null, ModelFormat.Chunk); hashes.Add($"{i}.sa2mdl:" + HelperFunctions.FileHash(Path.Combine(fileOutputPath, $"{i}.sa2mdl"))); int ptr = BitConverter.ToInt32(datafile, address + 8); if (ptr != 0) { model = new NJS_OBJECT(datafile, (int)(ptr - imageBase), imageBase, ModelFormat.Chunk, new Dictionary <int, Attach>()); kart.LowModel = model.Name; ModelFile.CreateFile(Path.Combine(fileOutputPath, $"{i} Low.sa2mdl"), model, null, null, null, null, ModelFormat.Chunk); hashes.Add($"{i} Low.sa2mdl:" + HelperFunctions.FileHash(Path.Combine(fileOutputPath, $"{i} Low.sa2mdl"))); } kart.TexList = ByteConverter.ToUInt32(datafile, address + 12); kart.Unknown1 = ByteConverter.ToInt32(datafile, address + 16); kart.Unknown2 = ByteConverter.ToInt32(datafile, address + 20); kart.Unknown3 = ByteConverter.ToInt32(datafile, address + 24); result.Add(kart); address += 0x1C; } IniSerializer.Serialize(result, Path.Combine(fileOutputPath, "info.ini")); hashes.Add("info.ini:" + HelperFunctions.FileHash(Path.Combine(fileOutputPath, "info.ini"))); output.DataItems.Add(new DllDataItemInfo() { Type = type, Export = name, Filename = data.Filename, MD5Hash = string.Join("|", hashes.ToArray()) }); } break; } itemcount++; } foreach (ModelAnimations item in models) { string modelOutputPath = string.Concat(projectFolderName, item.Filename); //string modelOutputPath = item.Filename; ModelFile.CreateFile(modelOutputPath, item.Model, item.Animations.ToArray(), null, item.Name, null, item.Format); string type = "model"; switch (item.Format) { case ModelFormat.Basic: type = "basicmodel"; break; case ModelFormat.BasicDX: type = "basicdxmodel"; break; case ModelFormat.Chunk: type = "chunkmodel"; break; } output.Files[item.Filename] = new FileTypeHash(type, HelperFunctions.FileHash(modelOutputPath)); } IniSerializer.Serialize(output, Path.Combine(projectFolderName, Path.GetFileNameWithoutExtension(datafilename)) + "_data.ini"); timer.Stop(); Console.WriteLine("Split " + itemcount + " items in " + timer.Elapsed.TotalSeconds + " seconds."); Console.WriteLine(); #if !DEBUG } catch (Exception e) { Console.WriteLine(e.Message); Console.WriteLine(e.StackTrace); Console.WriteLine("Press any key to exit."); Console.ReadLine(); return((int)SA_Tools.Split.SplitERRORVALUE.UnhandledException); } #endif return((int)SA_Tools.Split.SplitERRORVALUE.Success); }
public static void ExportCPP(DllIniData IniData, Dictionary <string, bool> itemsToExport, string fileName) { using (TextWriter writer = File.CreateText(fileName)) { bool SA2 = IniData.Game == Game.SA2B; ModelFormat modelfmt = SA2 ? ModelFormat.Chunk : ModelFormat.BasicDX; LandTableFormat landfmt = SA2 ? LandTableFormat.SA2 : LandTableFormat.SADX; writer.WriteLine("// Generated by SA Tools DLL Mod Generator"); writer.WriteLine(); if (SA2) { writer.WriteLine("#include \"SA2ModLoader.h\""); } else { writer.WriteLine("#include \"SADXModLoader.h\""); } writer.WriteLine(); List <string> labels = new List <string>(); Dictionary <string, uint> texlists = new Dictionary <string, uint>(); foreach (KeyValuePair <string, FileTypeHash> item in IniData.Files.Where(i => itemsToExport[i.Key])) { switch (item.Value.Type) { case "landtable": LandTable tbl = LandTable.LoadFromFile(item.Key); texlists.Add(tbl.Name, tbl.TextureList); tbl.ToStructVariables(writer, landfmt, new List <string>()); labels.AddRange(tbl.GetLabels()); break; case "model": NJS_OBJECT mdl = new ModelFile(item.Key).Model; mdl.ToStructVariables(writer, modelfmt == ModelFormat.BasicDX, new List <string>()); labels.AddRange(mdl.GetLabels()); break; case "basicmodel": case "chunkmodel": mdl = new ModelFile(item.Key).Model; mdl.ToStructVariables(writer, false, new List <string>()); labels.AddRange(mdl.GetLabels()); break; case "basicdxmodel": mdl = new ModelFile(item.Key).Model; mdl.ToStructVariables(writer, true, new List <string>()); labels.AddRange(mdl.GetLabels()); break; case "animation": case "animindex": NJS_MOTION ani = NJS_MOTION.Load(item.Key); ani.ToStructVariables(writer); labels.Add(ani.Name); break; } writer.WriteLine(); } writer.WriteLine("extern \"C\" __declspec(dllexport) void __cdecl Init(const char *path, const HelperFunctions &helperFunctions)"); writer.WriteLine("{"); writer.WriteLine("\tHMODULE handle = GetModuleHandle(L\"{0}\");", IniData.Name); List <string> exports = new List <string>(IniData.Items.Where(item => labels.Contains(item.Label)).Select(item => item.Export).Distinct()); foreach (KeyValuePair <string, string> item in IniData.Exports.Where(item => exports.Contains(item.Key))) { writer.WriteLine("\t{0}{1} = ({0})GetProcAddress(handle, \"{1}\");", typemap[item.Value], item.Key); } foreach (DllItemInfo item in IniData.Items.Where(item => labels.Contains(item.Label))) { writer.WriteLine("\t{0} = &{1};", item.ToString(), item.Label); } if (texlists.Count > 0 && IniData.TexLists != null && IniData.TexLists.Items != null) { exports = new List <string>(IniData.TexLists.Where(item => texlists.Values.Contains(item.Key)).Select(item => item.Value.Export).Distinct()); foreach (KeyValuePair <string, string> item in IniData.Exports.Where(item => exports.Contains(item.Key))) { writer.WriteLine("\t{0}{1} = ({0})GetProcAddress(handle, \"{1}\");", typemap[item.Value], item.Key); } foreach (KeyValuePair <string, uint> item in texlists.Where(item => IniData.TexLists.ContainsKey(item.Value))) { DllTexListInfo tex = IniData.TexLists[item.Value]; string str; if (tex.Index.HasValue) { str = $"{tex.Export}[{tex.Index.Value}]"; } else { str = tex.Export; } writer.WriteLine("\t{0}.TexList = {1};", item.Key, str); } } writer.WriteLine("}"); writer.WriteLine(); writer.WriteLine("extern \"C\" __declspec(dllexport) const ModInfo {0}ModInfo = {{ ModLoaderVer }};", SA2 ? "SA2" : "SADX"); } }
static void Main(string[] args) { string datafilename, inifilename; if (args.Length > 0) { datafilename = args[0]; Console.WriteLine("File: {0}", datafilename); } else { Console.Write("File: "); datafilename = Console.ReadLine(); } if (args.Length > 1) { inifilename = args[1]; Console.WriteLine("INI File: {0}", inifilename); } else { Console.Write("INI File: "); inifilename = Console.ReadLine(); } byte[] datafile = File.ReadAllBytes(datafilename); IniData inifile = IniSerializer.Deserialize <IniData>(inifilename); uint imageBase = HelperFunctions.SetupEXE(ref datafile).Value; Dictionary <string, int> exports; { int ptr = BitConverter.ToInt32(datafile, BitConverter.ToInt32(datafile, 0x3c) + 4 + 20 + 96); GCHandle handle = GCHandle.Alloc(datafile, GCHandleType.Pinned); IMAGE_EXPORT_DIRECTORY dir = (IMAGE_EXPORT_DIRECTORY)Marshal.PtrToStructure( Marshal.UnsafeAddrOfPinnedArrayElement(datafile, ptr), typeof(IMAGE_EXPORT_DIRECTORY)); handle.Free(); exports = new Dictionary <string, int>(dir.NumberOfFunctions); int nameaddr = dir.AddressOfNames; int ordaddr = dir.AddressOfNameOrdinals; for (int i = 0; i < dir.NumberOfNames; i++) { string name = HelperFunctions.GetCString(datafile, BitConverter.ToInt32(datafile, nameaddr), System.Text.Encoding.ASCII); int addr = BitConverter.ToInt32(datafile, dir.AddressOfFunctions + (BitConverter.ToInt16(datafile, ordaddr) * 4)); exports.Add(name, addr); nameaddr += 4; ordaddr += 2; } } ModelFormat modelfmt = 0; LandTableFormat landfmt = 0; string modelext = null; string landext = null; switch (inifile.Game) { case Game.SADX: modelfmt = ModelFormat.BasicDX; landfmt = LandTableFormat.SADX; modelext = ".sa1mdl"; landext = ".sa1lvl"; break; case Game.SA2B: modelfmt = ModelFormat.Chunk; landfmt = LandTableFormat.SA2; modelext = ".sa2mdl"; landext = ".sa2lvl"; break; } int itemcount = 0; List <string> labels = new List <string>(); ModelAnimationsDictionary models = new ModelAnimationsDictionary(); DllIniData output = new DllIniData() { Name = inifile.ModuleName, Game = inifile.Game }; Stopwatch timer = new Stopwatch(); timer.Start(); foreach (KeyValuePair <string, FileInfo> item in inifile.Files) { if (string.IsNullOrEmpty(item.Key)) { continue; } FileInfo data = item.Value; string type = data.Type; string name = item.Key; output.Exports[name] = type; int address = exports[name]; if (data.Filename != null) { Console.WriteLine(name + " -> " + data.Filename); Directory.CreateDirectory(Path.GetDirectoryName(data.Filename)); } else { Console.WriteLine(name); } switch (type) { case "landtable": { LandTable land = new LandTable(datafile, address, imageBase, landfmt) { Description = name, Tool = "splitDLL" }; DllItemInfo info = new DllItemInfo() { Export = name, Label = land.Name }; output.Items.Add(info); if (!labels.Contains(land.Name)) { land.SaveToFile(data.Filename, landfmt); output.Files[data.Filename] = new FileTypeHash("landtable", HelperFunctions.FileHash(data.Filename)); labels.AddRange(land.GetLabels()); } } break; case "landtablearray": for (int i = 0; i < data.Length; i++) { int ptr = BitConverter.ToInt32(datafile, address); if (ptr != 0) { ptr = (int)(ptr - imageBase); string idx = name + "[" + i.ToString(NumberFormatInfo.InvariantInfo) + "]"; LandTable land = new LandTable(datafile, ptr, imageBase, landfmt) { Description = idx, Tool = "splitDLL" }; DllItemInfo info = new DllItemInfo() { Export = name, Index = i, Label = land.Name }; output.Items.Add(info); if (!labels.Contains(land.Name)) { string fn = Path.Combine(data.Filename, i.ToString(NumberFormatInfo.InvariantInfo) + landext); land.SaveToFile(fn, landfmt); output.Files[fn] = new FileTypeHash("landtable", HelperFunctions.FileHash(fn)); labels.AddRange(land.GetLabels()); } } address += 4; } break; case "model": { NJS_OBJECT mdl = new NJS_OBJECT(datafile, address, imageBase, modelfmt); DllItemInfo info = new DllItemInfo() { Export = name, Label = mdl.Name }; output.Items.Add(info); if (!labels.Contains(mdl.Name)) { models.Add(new ModelAnimations(data.Filename, name, mdl, modelfmt)); labels.AddRange(mdl.GetLabels()); } } break; case "morph": { BasicAttach dummy = new BasicAttach(datafile, address, imageBase, modelfmt == ModelFormat.BasicDX); NJS_OBJECT mdl = new NJS_OBJECT() { Attach = dummy }; DllItemInfo info = new DllItemInfo() { Export = name, Label = dummy.Name }; output.Items.Add(info); if (!labels.Contains(dummy.Name)) { models.Add(new ModelAnimations(data.Filename, name, mdl, modelfmt)); labels.AddRange(mdl.GetLabels()); } } break; case "modelarray": for (int i = 0; i < data.Length; i++) { int ptr = BitConverter.ToInt32(datafile, address); if (ptr != 0) { ptr = (int)(ptr - imageBase); NJS_OBJECT mdl = new NJS_OBJECT(datafile, ptr, imageBase, modelfmt); string idx = name + "[" + i.ToString(NumberFormatInfo.InvariantInfo) + "]"; DllItemInfo info = new DllItemInfo() { Export = name, Index = i, Label = mdl.Name }; output.Items.Add(info); if (!labels.Contains(mdl.Name)) { string fn = Path.Combine(data.Filename, i.ToString(NumberFormatInfo.InvariantInfo) + modelext); models.Add(new ModelAnimations(fn, idx, mdl, modelfmt)); labels.AddRange(mdl.GetLabels()); } } address += 4; } break; case "modelsarray": for (int i = 0; i < data.Length; i++) { int ptr = BitConverter.ToInt32(datafile, address); if (ptr != 0) { ptr = (int)(ptr - imageBase); BasicAttach dummy = new BasicAttach(datafile, ptr, imageBase, modelfmt == ModelFormat.BasicDX); NJS_OBJECT mdl = new NJS_OBJECT() { Attach = dummy }; string idx = name + "[" + i.ToString(NumberFormatInfo.InvariantInfo) + "]"; DllItemInfo info = new DllItemInfo() { Export = name, Index = i, Label = dummy.Name }; output.Items.Add(info); if (!labels.Contains(dummy.Name)) { string fn = Path.Combine(data.Filename, i.ToString(NumberFormatInfo.InvariantInfo) + modelext); models.Add(new ModelAnimations(fn, idx, mdl, ModelFormat.BasicDX)); labels.AddRange(mdl.GetLabels()); } } address += 4; } break; case "basicmodel": { NJS_OBJECT mdl = new NJS_OBJECT(datafile, address, imageBase, ModelFormat.Basic); DllItemInfo info = new DllItemInfo() { Export = name, Label = mdl.Name }; output.Items.Add(info); if (!labels.Contains(mdl.Name)) { models.Add(new ModelAnimations(data.Filename, name, mdl, ModelFormat.Basic)); labels.AddRange(mdl.GetLabels()); } } break; case "basicmodelarray": for (int i = 0; i < data.Length; i++) { int ptr = BitConverter.ToInt32(datafile, address); if (ptr != 0) { ptr = (int)(ptr - imageBase); NJS_OBJECT mdl = new NJS_OBJECT(datafile, ptr, imageBase, ModelFormat.Basic); string idx = name + "[" + i.ToString(NumberFormatInfo.InvariantInfo) + "]"; DllItemInfo info = new DllItemInfo() { Export = name, Index = i, Label = mdl.Name }; output.Items.Add(info); if (!labels.Contains(mdl.Name)) { string fn = Path.Combine(data.Filename, i.ToString(NumberFormatInfo.InvariantInfo) + ".sa1mdl"); models.Add(new ModelAnimations(fn, idx, mdl, ModelFormat.Basic)); labels.AddRange(mdl.GetLabels()); } } address += 4; } break; case "basicdxmodel": { NJS_OBJECT mdl = new NJS_OBJECT(datafile, address, imageBase, ModelFormat.BasicDX); DllItemInfo info = new DllItemInfo() { Export = name, Label = mdl.Name }; output.Items.Add(info); if (!labels.Contains(mdl.Name)) { models.Add(new ModelAnimations(data.Filename, name, mdl, ModelFormat.BasicDX)); labels.AddRange(mdl.GetLabels()); } } break; case "basicdxmodelarray": for (int i = 0; i < data.Length; i++) { int ptr = BitConverter.ToInt32(datafile, address); if (ptr != 0) { ptr = (int)(ptr - imageBase); NJS_OBJECT mdl = new NJS_OBJECT(datafile, ptr, imageBase, ModelFormat.BasicDX); string idx = name + "[" + i.ToString(NumberFormatInfo.InvariantInfo) + "]"; DllItemInfo info = new DllItemInfo() { Export = name, Index = i, Label = mdl.Name }; output.Items.Add(info); if (!labels.Contains(mdl.Name)) { string fn = Path.Combine(data.Filename, i.ToString(NumberFormatInfo.InvariantInfo) + ".sa1mdl"); models.Add(new ModelAnimations(fn, idx, mdl, ModelFormat.BasicDX)); labels.AddRange(mdl.GetLabels()); } } address += 4; } break; case "chunkmodel": { NJS_OBJECT mdl = new NJS_OBJECT(datafile, address, imageBase, ModelFormat.Chunk); DllItemInfo info = new DllItemInfo() { Export = name, Label = mdl.Name }; output.Items.Add(info); if (!labels.Contains(mdl.Name)) { models.Add(new ModelAnimations(data.Filename, name, mdl, ModelFormat.Chunk)); labels.AddRange(mdl.GetLabels()); } } break; case "chunkmodelarray": for (int i = 0; i < data.Length; i++) { int ptr = BitConverter.ToInt32(datafile, address); if (ptr != 0) { ptr = (int)(ptr - imageBase); NJS_OBJECT mdl = new NJS_OBJECT(datafile, ptr, imageBase, ModelFormat.Chunk); string idx = name + "[" + i.ToString(NumberFormatInfo.InvariantInfo) + "]"; DllItemInfo info = new DllItemInfo() { Export = name, Index = i, Label = mdl.Name }; output.Items.Add(info); if (!labels.Contains(mdl.Name)) { string fn = Path.Combine(data.Filename, i.ToString(NumberFormatInfo.InvariantInfo) + ".sa2mdl"); models.Add(new ModelAnimations(fn, idx, mdl, ModelFormat.Chunk)); labels.AddRange(mdl.GetLabels()); } } address += 4; } break; case "actionarray": for (int i = 0; i < data.Length; i++) { int ptr = BitConverter.ToInt32(datafile, address); if (ptr != 0) { ptr = (int)(ptr - imageBase); AnimationHeader ani = new AnimationHeader(datafile, ptr, imageBase, modelfmt); string idx = name + "[" + i.ToString(NumberFormatInfo.InvariantInfo) + "]"; ani.Animation.Name = item.Key + "_" + i; DllItemInfo info = new DllItemInfo() { Export = name, Index = i, Label = ani.Animation.Name, Field = "motion" }; output.Items.Add(info); info = new DllItemInfo() { Export = name, Index = i, Label = ani.Model.Name, Field = "object" }; output.Items.Add(info); string fn = Path.Combine(data.Filename, i.ToString(NumberFormatInfo.InvariantInfo) + ".saanim"); ani.Animation.Save(fn); output.Files[fn] = new FileTypeHash("animation", HelperFunctions.FileHash(fn)); if (models.Contains(ani.Model.Name)) { ModelAnimations mdl = models[ani.Model.Name]; System.Text.StringBuilder sb = new System.Text.StringBuilder(260); PathRelativePathTo(sb, Path.GetFullPath(mdl.Filename), 0, Path.GetFullPath(fn), 0); mdl.Animations.Add(sb.ToString()); } else { string mfn = Path.ChangeExtension(fn, modelext); ModelFile.CreateFile(mfn, ani.Model, new[] { Path.GetFileName(fn) }, null, null, idx + "->object", "splitDLL", null, modelfmt); output.Files[mfn] = new FileTypeHash("model", HelperFunctions.FileHash(mfn)); } } address += 4; } break; case "texlist": if (output.TexLists == null) { output.TexLists = new TexListContainer(); } output.TexLists.Add((uint)(address + imageBase), new DllTexListInfo(name, null)); break; case "texlistarray": if (output.TexLists == null) { output.TexLists = new TexListContainer(); } for (int i = 0; i < data.Length; i++) { uint ptr = BitConverter.ToUInt32(datafile, address); if (ptr != 0 && !output.TexLists.ContainsKey(ptr)) { output.TexLists.Add(ptr, new DllTexListInfo(name, i)); } address += 4; } break; } itemcount++; } foreach (ModelAnimations item in models) { ModelFile.CreateFile(item.Filename, item.Model, item.Animations.ToArray(), null, null, item.Name, "splitDLL", null, item.Format); string type = "model"; switch (item.Format) { case ModelFormat.Basic: type = "basicmodel"; break; case ModelFormat.BasicDX: type = "basicdxmodel"; break; case ModelFormat.Chunk: type = "chunkmodel"; break; } output.Files[item.Filename] = new FileTypeHash(type, HelperFunctions.FileHash(item.Filename)); } IniSerializer.Serialize(output, Path.Combine(Environment.CurrentDirectory, Path.GetFileNameWithoutExtension(datafilename)) + "_data.ini"); timer.Stop(); Console.WriteLine("Split " + itemcount + " items in " + timer.Elapsed.TotalSeconds + " seconds."); Console.WriteLine(); }
private void button5_Click(object sender, EventArgs e) { using (SaveFileDialog fd = new SaveFileDialog() { DefaultExt = "cpp", Filter = "C++ source files|*.cpp", InitialDirectory = Environment.CurrentDirectory, RestoreDirectory = true }) if (fd.ShowDialog(this) == DialogResult.OK) { using (TextWriter writer = File.CreateText(fd.FileName)) { bool SA2 = IniData.Game == Game.SA2B; ModelFormat modelfmt = SA2 ? ModelFormat.Chunk : ModelFormat.BasicDX; LandTableFormat landfmt = SA2 ? LandTableFormat.SA2 : LandTableFormat.SADX; writer.WriteLine("// Generated by SA Tools DLL Mod Generator"); writer.WriteLine(); if (SA2) { writer.WriteLine("#include \"SA2ModLoader.h\""); } else { writer.WriteLine("#include \"SADXModLoader.h\""); } writer.WriteLine(); List <string> labels = new List <string>(); Dictionary <string, uint> texlists = new Dictionary <string, uint>(); foreach (KeyValuePair <string, FileTypeHash> item in IniData.Files.Where((a, i) => listView1.CheckedIndices.Contains(i))) { switch (item.Value.Type) { case "landtable": LandTable tbl = LandTable.LoadFromFile(item.Key); texlists.Add(tbl.Name, tbl.TextureList); tbl.ToStructVariables(writer, landfmt, new List <string>()); labels.AddRange(tbl.GetLabels()); break; case "model": NJS_OBJECT mdl = new ModelFile(item.Key).Model; mdl.ToStructVariables(writer, modelfmt == ModelFormat.BasicDX, new List <string>()); labels.AddRange(mdl.GetLabels()); break; case "basicmodel": case "chunkmodel": mdl = new ModelFile(item.Key).Model; mdl.ToStructVariables(writer, false, new List <string>()); labels.AddRange(mdl.GetLabels()); break; case "basicdxmodel": mdl = new ModelFile(item.Key).Model; mdl.ToStructVariables(writer, true, new List <string>()); labels.AddRange(mdl.GetLabels()); break; case "animation": Animation ani = Animation.Load(item.Key); ani.ToStructVariables(writer); labels.Add(ani.Name); break; } writer.WriteLine(); } writer.WriteLine("extern \"C\" __declspec(dllexport) void __cdecl Init(const char *path, const HelperFunctions &helperFunctions)"); writer.WriteLine("{"); writer.WriteLine("\tHMODULE handle = GetModuleHandle(L\"{0}\");", IniData.Name); List <string> exports = new List <string>(IniData.Items.Where(item => labels.Contains(item.Label)).Select(item => item.Export).Distinct()); foreach (KeyValuePair <string, string> item in IniData.Exports.Where(item => exports.Contains(item.Key))) { writer.WriteLine("\t{0}{1} = ({0})GetProcAddress(handle, \"{1}\");", typemap[item.Value], item.Key); } foreach (DllItemInfo item in IniData.Items.Where(item => labels.Contains(item.Label))) { writer.WriteLine("\t{0} = &{1};", item.ToString(), item.Label); } if (texlists.Count > 0 && IniData.TexLists != null && IniData.TexLists.Items != null) { exports = new List <string>(IniData.TexLists.Where(item => texlists.Values.Contains(item.Key)).Select(item => item.Value.Export).Distinct()); foreach (KeyValuePair <string, string> item in IniData.Exports.Where(item => exports.Contains(item.Key))) { writer.WriteLine("\t{0}{1} = ({0})GetProcAddress(handle, \"{1}\");", typemap[item.Value], item.Key); } foreach (KeyValuePair <string, uint> item in texlists.Where(item => IniData.TexLists.ContainsKey(item.Value))) { DllTexListInfo tex = IniData.TexLists[item.Value]; string str; if (tex.Index.HasValue) { str = $"{tex.Export}[{tex.Index.Value}]"; } else { str = tex.Export; } writer.WriteLine("\t{0}.TexList = {1};", item.Key, str); } } writer.WriteLine("}"); writer.WriteLine(); writer.WriteLine("extern \"C\" __declspec(dllexport) const ModInfo {0}ModInfo = {{ ModLoaderVer }};", SA2 ? "SA2" : "SADX"); } } }