From 33eccab27babcc4ffb09753c5bb72557a14d39c3 Mon Sep 17 00:00:00 2001 From: Shadow Date: Tue, 31 Dec 2024 22:30:00 -0500 Subject: [PATCH] Add support for POE filenames when extracting --- AquaModelTool/AquaModelToolUI.Designer.cs | 71 +++++--- AquaModelTool/AquaModelToolUI.cs | 200 +++++++++++++++++++++- PSO2-Aqua-Library | 2 +- 3 files changed, 242 insertions(+), 31 deletions(-) diff --git a/AquaModelTool/AquaModelToolUI.Designer.cs b/AquaModelTool/AquaModelToolUI.Designer.cs index 84198fb..694ffc3 100644 --- a/AquaModelTool/AquaModelToolUI.Designer.cs +++ b/AquaModelTool/AquaModelToolUI.Designer.cs @@ -118,6 +118,8 @@ private void InitializeComponent() billyHatcherCyrillicbinTextTotxtToolStripMenuItem = new ToolStripMenuItem(); billyHatcherCyrillictxtTobinToolStripMenuItem = new ToolStripMenuItem(); toolStripSeparator17 = new ToolStripSeparator(); + stageGeobjExtractToolStripMenuItem = new ToolStripMenuItem(); + toolStripSeparator21 = new ToolStripSeparator(); otherGamesToolStripMenuItem3 = new ToolStripMenuItem(); blueDragonipkExtractToolStripMenuItem = new ToolStripMenuItem(); ikarugaarcExtractToolStripMenuItem = new ToolStripMenuItem(); @@ -234,10 +236,11 @@ private void InitializeComponent() objCollisionReadToolStripMenuItem = new ToolStripMenuItem(); arEnemyReadToolStripMenuItem = new ToolStripMenuItem(); pOE2IndexReadToolStripMenuItem = new ToolStripMenuItem(); - filePanel = new Panel(); - splitter1 = new Splitter(); setEnemyReadToolStripMenuItem = new ToolStripMenuItem(); setCameraReadToolStripMenuItem = new ToolStripMenuItem(); + filePanel = new Panel(); + splitter1 = new Splitter(); + pathOfExile1ModelSupportIsIncompleteAndMayFailOnSomeFilesToolStripMenuItem = new ToolStripMenuItem(); menuStrip1.SuspendLayout(); SuspendLayout(); // @@ -751,7 +754,7 @@ private void InitializeComponent() // // otherGamesToolStripMenuItem2 // - otherGamesToolStripMenuItem2.DropDownItems.AddRange(new ToolStripItem[] { extractBorderBreakPS4FARCToolStripMenuItem, setMOTBONEbinPathToolStripMenuItem, toolStripSeparator7, billyHatcherGinjaTofbxToolStripMenuItem, readBillyHatchermc2TofbxToolStripMenuItem, fbxSetToBillyHatcherlndToolStripMenuItem, fbxToBillyHatchermc2ToolStripMenuItem, billyHatcherprdArchiveExtractToolStripMenuItem, packBillyHatcherprdToolStripMenuItem, packBillyHatchernrcToolStripMenuItem, packBillyHatchergplToolStripMenuItem, billyHatcherbinTextTotxtToolStripMenuItem, billyHatcherbintxtBackTobinToolStripMenuItem, billyHatcherCyrillicbinTextTotxtToolStripMenuItem, billyHatcherCyrillictxtTobinToolStripMenuItem, toolStripSeparator17 }); + otherGamesToolStripMenuItem2.DropDownItems.AddRange(new ToolStripItem[] { extractBorderBreakPS4FARCToolStripMenuItem, setMOTBONEbinPathToolStripMenuItem, toolStripSeparator7, billyHatcherGinjaTofbxToolStripMenuItem, readBillyHatchermc2TofbxToolStripMenuItem, fbxSetToBillyHatcherlndToolStripMenuItem, fbxToBillyHatchermc2ToolStripMenuItem, billyHatcherprdArchiveExtractToolStripMenuItem, packBillyHatcherprdToolStripMenuItem, packBillyHatchernrcToolStripMenuItem, packBillyHatchergplToolStripMenuItem, billyHatcherbinTextTotxtToolStripMenuItem, billyHatcherbintxtBackTobinToolStripMenuItem, billyHatcherCyrillicbinTextTotxtToolStripMenuItem, billyHatcherCyrillictxtTobinToolStripMenuItem, toolStripSeparator17, stageGeobjExtractToolStripMenuItem, toolStripSeparator21 }); otherGamesToolStripMenuItem2.Name = "otherGamesToolStripMenuItem2"; otherGamesToolStripMenuItem2.Size = new Size(344, 22); otherGamesToolStripMenuItem2.Text = "Other Sega Games"; @@ -864,9 +867,21 @@ private void InitializeComponent() toolStripSeparator17.Name = "toolStripSeparator17"; toolStripSeparator17.Size = new Size(424, 6); // + // stageGeobjExtractToolStripMenuItem + // + stageGeobjExtractToolStripMenuItem.Name = "stageGeobjExtractToolStripMenuItem"; + stageGeobjExtractToolStripMenuItem.Size = new Size(427, 22); + stageGeobjExtractToolStripMenuItem.Text = "Billy Hatcher Stage geobj arc extract"; + stageGeobjExtractToolStripMenuItem.Click += stageGeobjExtractToolStripMenuItem_Click; + // + // toolStripSeparator21 + // + toolStripSeparator21.Name = "toolStripSeparator21"; + toolStripSeparator21.Size = new Size(424, 6); + // // otherGamesToolStripMenuItem3 // - otherGamesToolStripMenuItem3.DropDownItems.AddRange(new ToolStripItem[] { blueDragonipkExtractToolStripMenuItem, ikarugaarcExtractToolStripMenuItem, toolStripSeparator20, pathOfExile2ToolStripMenuItem, pathOfExile2BatchModelConvertToolStripMenuItem, pathOfExile2MToolStripMenuItem, pathOfExile2RiggedModelAnimationConvertToolStripMenuItem }); + otherGamesToolStripMenuItem3.DropDownItems.AddRange(new ToolStripItem[] { blueDragonipkExtractToolStripMenuItem, ikarugaarcExtractToolStripMenuItem, toolStripSeparator20, pathOfExile2ToolStripMenuItem, pathOfExile2BatchModelConvertToolStripMenuItem, pathOfExile2MToolStripMenuItem, pathOfExile2RiggedModelAnimationConvertToolStripMenuItem, pathOfExile1ModelSupportIsIncompleteAndMayFailOnSomeFilesToolStripMenuItem }); otherGamesToolStripMenuItem3.Name = "otherGamesToolStripMenuItem3"; otherGamesToolStripMenuItem3.Size = new Size(344, 22); otherGamesToolStripMenuItem3.Text = "Other Games"; @@ -894,28 +909,28 @@ private void InitializeComponent() // pathOfExile2ToolStripMenuItem.Name = "pathOfExile2ToolStripMenuItem"; pathOfExile2ToolStripMenuItem.Size = new Size(376, 22); - pathOfExile2ToolStripMenuItem.Text = "Path of Exile 2 Archive Extract"; + pathOfExile2ToolStripMenuItem.Text = "Path of Exile 1 and 2 Archive Extract"; pathOfExile2ToolStripMenuItem.Click += pathOfExile2ArchiveExtractToolStripMenuItem_Click; // // pathOfExile2BatchModelConvertToolStripMenuItem // pathOfExile2BatchModelConvertToolStripMenuItem.Name = "pathOfExile2BatchModelConvertToolStripMenuItem"; - pathOfExile2BatchModelConvertToolStripMenuItem.Size = new Size(376, 22); - pathOfExile2BatchModelConvertToolStripMenuItem.Text = "Path of Exile 2 Batch Model Convert (No model rigging)"; + pathOfExile2BatchModelConvertToolStripMenuItem.Size = new Size(444, 22); + pathOfExile2BatchModelConvertToolStripMenuItem.Text = "Path of Exile 1 and 2 Batch Model Convert (No model rigging)"; pathOfExile2BatchModelConvertToolStripMenuItem.Click += pathOfExile2BatchModelConvertToolStripMenuItem_Click; // // pathOfExile2MToolStripMenuItem // pathOfExile2MToolStripMenuItem.Name = "pathOfExile2MToolStripMenuItem"; - pathOfExile2MToolStripMenuItem.Size = new Size(376, 22); - pathOfExile2MToolStripMenuItem.Text = "Path of Exile 2 Rigged Model Convert"; + pathOfExile2MToolStripMenuItem.Size = new Size(444, 22); + pathOfExile2MToolStripMenuItem.Text = "Path of Exile 1 and 2 Rigged Model Convert"; pathOfExile2MToolStripMenuItem.Click += pathOfExile2RiggedModelConvertToolStripMenuItem_Click; // // pathOfExile2RiggedModelAnimationConvertToolStripMenuItem // pathOfExile2RiggedModelAnimationConvertToolStripMenuItem.Name = "pathOfExile2RiggedModelAnimationConvertToolStripMenuItem"; - pathOfExile2RiggedModelAnimationConvertToolStripMenuItem.Size = new Size(376, 22); - pathOfExile2RiggedModelAnimationConvertToolStripMenuItem.Text = "Path of Exile 2 Rigged Model + Animation Convert (Slow)"; + pathOfExile2RiggedModelAnimationConvertToolStripMenuItem.Size = new Size(444, 22); + pathOfExile2RiggedModelAnimationConvertToolStripMenuItem.Text = "Path of Exile 1 and 2 Rigged Model + Animation Convert (Slow)"; pathOfExile2RiggedModelAnimationConvertToolStripMenuItem.Click += pathOfExile2RiggedModelAnimationConvertToolStripMenuItem_Click; // // toolStripSeparator5 @@ -1669,6 +1684,20 @@ private void InitializeComponent() pOE2IndexReadToolStripMenuItem.Text = "POE2IndexRead"; pOE2IndexReadToolStripMenuItem.Click += pOE2IndexReadToolStripMenuItem_Click; // + // setEnemyReadToolStripMenuItem + // + setEnemyReadToolStripMenuItem.Name = "setEnemyReadToolStripMenuItem"; + setEnemyReadToolStripMenuItem.Size = new Size(213, 22); + setEnemyReadToolStripMenuItem.Text = "SetEnemyRead"; + setEnemyReadToolStripMenuItem.Click += setEnemyReadToolStripMenuItem_Click; + // + // setCameraReadToolStripMenuItem + // + setCameraReadToolStripMenuItem.Name = "setCameraReadToolStripMenuItem"; + setCameraReadToolStripMenuItem.Size = new Size(213, 22); + setCameraReadToolStripMenuItem.Text = "SetCameraRead"; + setCameraReadToolStripMenuItem.Click += setCameraReadToolStripMenuItem_Click; + // // filePanel // filePanel.AutoSize = true; @@ -1689,19 +1718,12 @@ private void InitializeComponent() splitter1.TabIndex = 2; splitter1.TabStop = false; // - // setEnemyReadToolStripMenuItem + // pathOfExile1ModelSupportIsIncompleteAndMayFailOnSomeFilesToolStripMenuItem // - setEnemyReadToolStripMenuItem.Name = "setEnemyReadToolStripMenuItem"; - setEnemyReadToolStripMenuItem.Size = new Size(213, 22); - setEnemyReadToolStripMenuItem.Text = "SetEnemyRead"; - setEnemyReadToolStripMenuItem.Click += setEnemyReadToolStripMenuItem_Click; - // - // setCameraReadToolStripMenuItem - // - setCameraReadToolStripMenuItem.Name = "setCameraReadToolStripMenuItem"; - setCameraReadToolStripMenuItem.Size = new Size(213, 22); - setCameraReadToolStripMenuItem.Text = "SetCameraRead"; - setCameraReadToolStripMenuItem.Click += setCameraReadToolStripMenuItem_Click; + pathOfExile1ModelSupportIsIncompleteAndMayFailOnSomeFilesToolStripMenuItem.Enabled = false; + pathOfExile1ModelSupportIsIncompleteAndMayFailOnSomeFilesToolStripMenuItem.Name = "pathOfExile1ModelSupportIsIncompleteAndMayFailOnSomeFilesToolStripMenuItem"; + pathOfExile1ModelSupportIsIncompleteAndMayFailOnSomeFilesToolStripMenuItem.Size = new Size(444, 22); + pathOfExile1ModelSupportIsIncompleteAndMayFailOnSomeFilesToolStripMenuItem.Text = "Path of Exile 1 model support is incomplete and may fail on some files"; // // AquaModelTool // @@ -1934,6 +1956,9 @@ private void InitializeComponent() private ToolStripMenuItem pathOfExile2RiggedModelAnimationConvertToolStripMenuItem; private ToolStripMenuItem setEnemyReadToolStripMenuItem; private ToolStripMenuItem setCameraReadToolStripMenuItem; + private ToolStripMenuItem stageGeobjExtractToolStripMenuItem; + private ToolStripSeparator toolStripSeparator21; + private ToolStripMenuItem pathOfExile1ModelSupportIsIncompleteAndMayFailOnSomeFilesToolStripMenuItem; } } diff --git a/AquaModelTool/AquaModelToolUI.cs b/AquaModelTool/AquaModelToolUI.cs index 2e56906..da996b6 100644 --- a/AquaModelTool/AquaModelToolUI.cs +++ b/AquaModelTool/AquaModelToolUI.cs @@ -13,6 +13,7 @@ using AquaModelLibrary.Data.BillyHatcher.SetData; using AquaModelLibrary.Data.BlueDragon; using AquaModelLibrary.Data.BluePoint.CAWS; +using AquaModelLibrary.Data.BluePoint.CGPR; using AquaModelLibrary.Data.BluePoint.CMDL; using AquaModelLibrary.Data.BluePoint.CTXR; using AquaModelLibrary.Data.CustomRoboBattleRevolution; @@ -7106,8 +7107,7 @@ private void pOE2IndexReadToolStripMenuItem_Click(object sender, EventArgs e) { foreach (var file in openFileDialog.FileNames) { - byte[] bytes = File.ReadAllBytes(file); - var index = new POE2Index(bytes); + var index = new POE2Index(POE2ArchiveUtility.DecompressArchive(File.ReadAllBytes(file))[0].file); } } } @@ -7124,9 +7124,9 @@ private static void ConvertModelAndActions(bool exportMotions) POE2Action armature = null; var openFileDialog1 = new OpenFileDialog() { - Title = "Select Action file", + Title = "Select Rig file", FileName = "", - Filter = "POE2 Action files (*.action)|*.action", + Filter = "POE2 Rig files (*.ast, *.action)|*.ast;*.action", }; if (openFileDialog1.ShowDialog() == DialogResult.OK) { @@ -7215,20 +7215,29 @@ private void pathOfExile2ArchiveExtractToolStripMenuItem_Click(object sender, Ev if (openFileDialog.ShowDialog() == DialogResult.OK) { bool errorDisplayed = false; + string currentIndexDirectory = ""; + POE2Index index = null; foreach (var file in openFileDialog.FileNames) { byte[] bytes = File.ReadAllBytes(file); - POE2Index index = null; string filePath = file; if (file.Contains("Bundles2")) { var bundlesPathStart = file.IndexOf("Bundles2") + 9; + var newIndexDirectory = file.Substring(0, bundlesPathStart); + filePath = Path.ChangeExtension(file.Substring(bundlesPathStart).Replace("\\", "/"), ""); filePath = filePath.Substring(0, filePath.Length - 1); filePath = Path.ChangeExtension(filePath, ""); filePath = filePath.Substring(0, filePath.Length - 1); - var indexPath = Path.Combine(file.Substring(0, bundlesPathStart), "_.index.bin"); - index = new POE2Index(POE2ArchiveUtility.DecompressArchive(File.ReadAllBytes(indexPath))[0].file); + //Try to recycle the index so we're not making this longer than it has to be. This should allow the user to potentially do silly crap + //like extract poe1 and 2 stuff at the same time if they somehow got both sets of files in a search + if (currentIndexDirectory != newIndexDirectory) + { + currentIndexDirectory = newIndexDirectory; + var indexPath = Path.Combine(newIndexDirectory, "_.index.bin"); + index = new POE2Index(POE2ArchiveUtility.DecompressArchive(File.ReadAllBytes(indexPath))[0].file); + } } else { @@ -7325,6 +7334,31 @@ private void setEnemyReadToolStripMenuItem_Click(object sender, EventArgs e) { byte[] bytes = File.ReadAllBytes(file); var ene = new SetEnemyList(bytes); + for (int i = 0; i < ene.setEnemies.Count; i++) + { + var obj = ene.setEnemies[i]; + int a = 0; + if (obj.int_20 != 0) + { + a = 1; + } + if (obj.int_24 != 0) + { + a = 1; + } + if (obj.int_28 != 0) + { + a = 1; + } + if (obj.int_2C != 0) + { + a = 1; + } + if (obj.flt_4C != 0) + { + a = 1; + } + } } } } @@ -7347,6 +7381,158 @@ private void setCameraReadToolStripMenuItem_Click(object sender, EventArgs e) } } } + + private void stageGeobjExtractToolStripMenuItem_Click(object sender, EventArgs e) + { + var openFileDialog = new OpenFileDialog() + { + Title = "Select Billy Hatcher geobj_*.arc File", + Filter = "Billy Hatcher geobj_*.arc files|geobj_*.arc", + FileName = "", + Multiselect = true + }; + if (openFileDialog.ShowDialog() == DialogResult.OK) + { + foreach (var file in openFileDialog.FileNames) + { + var filename = Path.GetFileName(file); + if (GEObj_Stage.archiveFilenames.Contains(filename)) + { + var arc = new GEObj_Stage(File.ReadAllBytes(file)); + + var outDir = file + "_out"; + Directory.CreateDirectory(outDir); + foreach (var pair in arc.models) + { + var model = pair.Value; + if (model != null) + { + var outPath = Path.Combine(outDir, $"{pair.Key}.fbx"); + var aqp = NinjaModelConvert.NinjaToAqua(model, out var aqn); + if (aqp != null && aqp.vtxlList.Count > 0 || aqp.tempTris[0].faceVerts.Count > 0) + { + aqp.ConvertToPSO2Model(true, false, false, true, false, false, false, true); + aqp.ConvertToLegacyTypes(); + aqp.CreateTrueVertWeights(); + + FbxExporterNative.ExportToFile(aqp, aqn, new List(), outPath, new List(), new List(), false); + } + } + } + foreach (var pair in arc.colModels) + { + var model = pair.Value; + if (model != null) + { + var aqpList = model.ConvertToAquaObject(); + var aqn = AquaNode.GenerateBasicAQN(); + for (int i = 0; i < aqpList.Count; i++) + { + var aqp = aqpList[i]; + string outPath; + if (i == 0 && aqpList.Count == 1) + { + outPath = Path.Combine(outDir, $"{pair.Key}.fbx"); + } + else + { + outPath = Path.Combine(outDir, $"{pair.Key}_{i}.fbx"); + } + + if (aqp != null && aqp.vtxlList.Count > 0 || aqp.tempTris[0].faceVerts.Count > 0) + { + aqp.ConvertToLegacyTypes(); + aqp.CreateTrueVertWeights(); + + FbxExporterNative.ExportToFile(aqp, aqn, new List(), outPath, new List(), new List(), false); + } + } + } + } + foreach (var pair in arc.model2s) + { + var model = pair.Value; + if (model != null) + { + var outPath = Path.Combine(outDir, $"{pair.Key}.fbx"); + var aqp = NinjaModelConvert.NinjaToAqua(model, out var aqn); + if (aqp != null && aqp.vtxlList.Count > 0 || aqp.tempTris[0].faceVerts.Count > 0) + { + aqp.ConvertToPSO2Model(true, false, false, true, false, false, false, true); + aqp.ConvertToLegacyTypes(); + aqp.CreateTrueVertWeights(); + + FbxExporterNative.ExportToFile(aqp, aqn, new List(), outPath, new List(), new List(), false); + } + } + } + foreach (var pair in arc.colModel2s) + { + var model = pair.Value; + if (model != null) + { + var aqpList = model.ConvertToAquaObject(); + var aqn = AquaNode.GenerateBasicAQN(); + for (int i = 0; i < aqpList.Count; i++) + { + var aqp = aqpList[i]; + string outPath; + if (i == 0 && aqpList.Count == 1) + { + outPath = Path.Combine(outDir, $"{pair.Key}.fbx"); + } + else + { + outPath = Path.Combine(outDir, $"{pair.Key}_{i}.fbx"); + } + + if (aqp != null && aqp.vtxlList.Count > 0 || aqp.tempTris[0].faceVerts.Count > 0) + { + aqp.ConvertToLegacyTypes(); + aqp.CreateTrueVertWeights(); + + FbxExporterNative.ExportToFile(aqp, aqn, new List(), outPath, new List(), new List(), false); + } + } + } + } + if (arc.gvm != null) + { + arc.gvm.Save(Path.Combine(outDir, "textures.gvm")); + } + } + else + { + var arc = new GEObj_Object(File.ReadAllBytes(file)); + + var outDir = file + "_out"; + Directory.CreateDirectory(outDir); + foreach (var pair in arc.models) + { + var model = pair.Value; + if (model != null) + { + var outPath = Path.Combine(outDir, $"{pair.Key}.fbx"); + var aqp = NinjaModelConvert.NinjaToAqua(model, out var aqn); + if (aqp != null && aqp.vtxlList.Count > 0 || aqp.tempTris[0].faceVerts.Count > 0) + { + aqp.ConvertToPSO2Model(true, false, false, true, false, false, false, true); + aqp.ConvertToLegacyTypes(); + aqp.CreateTrueVertWeights(); + + FbxExporterNative.ExportToFile(aqp, aqn, new List(), outPath, new List(), new List(), false); + } + } + } + if (arc.gvm != null) + { + arc.gvm.Save(Path.Combine(outDir, "textures.gvm")); + } + } + + } + } + } } } diff --git a/PSO2-Aqua-Library b/PSO2-Aqua-Library index b1384e3..8a5c3f3 160000 --- a/PSO2-Aqua-Library +++ b/PSO2-Aqua-Library @@ -1 +1 @@ -Subproject commit b1384e3b2764a0d7f2c94c5aec9e84d9e0b44940 +Subproject commit 8a5c3f3f5174e5afb9b7f29f366e6f7edc4e10bb