From 9a172610df1a5658d9de920a8c02ad97cfa467da Mon Sep 17 00:00:00 2001 From: VaDiM Date: Wed, 29 Apr 2026 01:22:54 +0300 Subject: [PATCH] [GUI] Add option to specify parsing mode of Tuanjie meshes --- AssetStudio/Classes/Mesh.cs | 12 +- .../CustomOptions/CustomBundleOptions.cs | 12 -- .../CustomOptions/CustomMeshOptions.cs | 25 ++++ AssetStudio/CustomOptions/ImportOptions.cs | 14 +++ AssetStudioGUI/ImportOptionsForm.Designer.cs | 108 +++++++++++++++++- AssetStudioGUI/ImportOptionsForm.cs | 9 +- 6 files changed, 160 insertions(+), 20 deletions(-) create mode 100644 AssetStudio/CustomOptions/CustomMeshOptions.cs diff --git a/AssetStudio/Classes/Mesh.cs b/AssetStudio/Classes/Mesh.cs index 16ff8a7..11e98d6 100644 --- a/AssetStudio/Classes/Mesh.cs +++ b/AssetStudio/Classes/Mesh.cs @@ -1,4 +1,5 @@ -using System; +using AssetStudio.CustomOptions; +using System; using System.Collections; using System.Collections.Generic; using System.IO; @@ -744,13 +745,16 @@ namespace AssetStudio var m_KeepIndices = reader.ReadBoolean(); } - if (version.IsTuanjie) + var tuanjieParsingMode = reader.assetsFile.assetsManager.Options.MeshOptions.TuanjieMeshParsingMode; + var useSharedClusterData = tuanjieParsingMode == ImportOptions.CustomMeshOptions.MeshParsingMode.Tuanjie + || (tuanjieParsingMode == ImportOptions.CustomMeshOptions.MeshParsingMode.Auto && reader.version < (2022, 3, 61, 2)); + if (version.IsTuanjie && useSharedClusterData) { - if (version < (2022, 3, 48) || (version == (2022, 3, 48) && version.Build < 3)) //2022.3.48t3(1.4.0) down + if (version < (2022, 3, 48, 3)) //2022.3.48t3(1.4.0) down { _ = new SharedClusterData(reader, rev: 1); } - else if (version < (2022, 3, 61) || (version == (2022, 3, 61) && version.Build < 2)) //2022.3.48t3(1.4.0) - 2022.3.61t1(1.6.0) + else if (version < (2022, 3, 61, 2)) //2022.3.48t3(1.4.0) - 2022.3.61t1(1.6.0) { _ = new SharedClusterData(reader, rev: 2); } diff --git a/AssetStudio/CustomOptions/CustomBundleOptions.cs b/AssetStudio/CustomOptions/CustomBundleOptions.cs index 5e0329e..5ac2da1 100644 --- a/AssetStudio/CustomOptions/CustomBundleOptions.cs +++ b/AssetStudio/CustomOptions/CustomBundleOptions.cs @@ -34,18 +34,6 @@ } public CustomBundleOptions() { } - - private static T SetOption(string option, T value, T curValue) - { - if (value.Equals(curValue)) - return curValue; - - var val = string.IsNullOrEmpty(value.ToString()) - ? "None" - : value.ToString(); - Logger.Info($"- {option}: {val}"); - return value; - } } } } diff --git a/AssetStudio/CustomOptions/CustomMeshOptions.cs b/AssetStudio/CustomOptions/CustomMeshOptions.cs new file mode 100644 index 0000000..cd201ce --- /dev/null +++ b/AssetStudio/CustomOptions/CustomMeshOptions.cs @@ -0,0 +1,25 @@ +namespace AssetStudio.CustomOptions +{ + public partial class ImportOptions + { + public sealed class CustomMeshOptions + { + public enum MeshParsingMode + { + Auto, + Tuanjie, + Unity, + } + + private MeshParsingMode _tuanjieMeshParsingMode; + + public MeshParsingMode TuanjieMeshParsingMode + { + get => _tuanjieMeshParsingMode; + set => _tuanjieMeshParsingMode = SetOption(nameof(TuanjieMeshParsingMode), value, _tuanjieMeshParsingMode); + } + + public CustomMeshOptions() { } + } + } +} diff --git a/AssetStudio/CustomOptions/ImportOptions.cs b/AssetStudio/CustomOptions/ImportOptions.cs index 3b35175..5a158b0 100644 --- a/AssetStudio/CustomOptions/ImportOptions.cs +++ b/AssetStudio/CustomOptions/ImportOptions.cs @@ -17,6 +17,7 @@ namespace AssetStudio.CustomOptions public event EventHandler UnityVersionChanged; public CustomBundleOptions BundleOptions { get; set; } + public CustomMeshOptions MeshOptions { get; set; } public UnityVersion CustomUnityVersion { get => _customUnityVer; set => SetUnityVersion(value); } static ImportOptions() @@ -31,6 +32,7 @@ namespace AssetStudio.CustomOptions public ImportOptions() { BundleOptions = new CustomBundleOptions(); + MeshOptions = new CustomMeshOptions(); CustomUnityVersion = null; } @@ -94,5 +96,17 @@ namespace AssetStudio.CustomOptions Logger.Info($"- Specified Unity version: {_customUnityVer}"); } + + private static T SetOption(string option, T value, T curValue) + { + if (value.Equals(curValue)) + return curValue; + + var val = string.IsNullOrEmpty(value.ToString()) + ? "None" + : value.ToString(); + Logger.Info($"- {option}: {val}"); + return value; + } } } diff --git a/AssetStudioGUI/ImportOptionsForm.Designer.cs b/AssetStudioGUI/ImportOptionsForm.Designer.cs index 95a38d0..7ec60cf 100644 --- a/AssetStudioGUI/ImportOptionsForm.Designer.cs +++ b/AssetStudioGUI/ImportOptionsForm.Designer.cs @@ -52,12 +52,22 @@ this.tabPage1 = new System.Windows.Forms.TabPage(); this.tabPage2 = new System.Windows.Forms.TabPage(); this.cacheGroupBox = new System.Windows.Forms.GroupBox(); + this.tabPage3 = new System.Windows.Forms.TabPage(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.panel1 = new System.Windows.Forms.Panel(); + this.tMeshModeUnityRadioButton = new System.Windows.Forms.RadioButton(); + this.tMeshModeTuanjieRadioButton = new System.Windows.Forms.RadioButton(); + this.tMeshModeAutoRadioButton = new System.Windows.Forms.RadioButton(); + this.label1 = new System.Windows.Forms.Label(); this.unityVersionGroupBox.SuspendLayout(); this.decompressionGroupBox.SuspendLayout(); this.tabControl1.SuspendLayout(); this.tabPage1.SuspendLayout(); this.tabPage2.SuspendLayout(); this.cacheGroupBox.SuspendLayout(); + this.tabPage3.SuspendLayout(); + this.groupBox1.SuspendLayout(); + this.panel1.SuspendLayout(); this.SuspendLayout(); // // cachePathLabel @@ -106,7 +116,6 @@ // legacyUnityVersionComboBox // this.legacyUnityVersionComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; - this.legacyUnityVersionComboBox.FormattingEnabled = true; this.legacyUnityVersionComboBox.Items.AddRange(new object[] { "None", "1.2 mac", @@ -167,7 +176,6 @@ // customBlockCompressionComboBox // this.customBlockCompressionComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; - this.customBlockCompressionComboBox.FormattingEnabled = true; this.customBlockCompressionComboBox.Items.AddRange(new object[] { "Auto", "Zstd", @@ -192,7 +200,6 @@ // customBlockInfoCompressionComboBox // this.customBlockInfoCompressionComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; - this.customBlockInfoCompressionComboBox.FormattingEnabled = true; this.customBlockInfoCompressionComboBox.Items.AddRange(new object[] { "Auto", "Zstd", @@ -280,6 +287,7 @@ // this.tabControl1.Controls.Add(this.tabPage1); this.tabControl1.Controls.Add(this.tabPage2); + this.tabControl1.Controls.Add(this.tabPage3); this.tabControl1.Location = new System.Drawing.Point(12, 12); this.tabControl1.Margin = new System.Windows.Forms.Padding(12); this.tabControl1.Name = "tabControl1"; @@ -326,6 +334,87 @@ this.cacheGroupBox.TabStop = false; this.cacheGroupBox.Text = "Disk cache"; // + // tabPage3 + // + this.tabPage3.AutoScroll = true; + this.tabPage3.BackColor = System.Drawing.SystemColors.Menu; + this.tabPage3.Controls.Add(this.groupBox1); + this.tabPage3.Location = new System.Drawing.Point(4, 24); + this.tabPage3.Name = "tabPage3"; + this.tabPage3.Size = new System.Drawing.Size(363, 291); + this.tabPage3.TabIndex = 2; + this.tabPage3.Text = "Meshes"; + // + // groupBox1 + // + this.groupBox1.AutoSize = true; + this.groupBox1.Controls.Add(this.panel1); + this.groupBox1.Controls.Add(this.label1); + this.groupBox1.Location = new System.Drawing.Point(3, 3); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(357, 82); + this.groupBox1.TabIndex = 0; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "Tuanjie"; + // + // panel1 + // + this.panel1.AutoSize = true; + this.panel1.Controls.Add(this.tMeshModeUnityRadioButton); + this.panel1.Controls.Add(this.tMeshModeTuanjieRadioButton); + this.panel1.Controls.Add(this.tMeshModeAutoRadioButton); + this.panel1.Location = new System.Drawing.Point(32, 37); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(288, 23); + this.panel1.TabIndex = 1; + // + // tMeshModeUnityRadioButton + // + this.tMeshModeUnityRadioButton.AutoSize = true; + this.tMeshModeUnityRadioButton.Dock = System.Windows.Forms.DockStyle.Left; + this.tMeshModeUnityRadioButton.Location = new System.Drawing.Point(156, 0); + this.tMeshModeUnityRadioButton.Name = "tMeshModeUnityRadioButton"; + this.tMeshModeUnityRadioButton.Padding = new System.Windows.Forms.Padding(0, 0, 5, 0); + this.tMeshModeUnityRadioButton.Size = new System.Drawing.Size(90, 23); + this.tMeshModeUnityRadioButton.TabIndex = 2; + this.tMeshModeUnityRadioButton.Text = "Unity mesh"; + this.tMeshModeUnityRadioButton.UseVisualStyleBackColor = true; + // + // tMeshModeTuanjieRadioButton + // + this.tMeshModeTuanjieRadioButton.AutoSize = true; + this.tMeshModeTuanjieRadioButton.Dock = System.Windows.Forms.DockStyle.Left; + this.tMeshModeTuanjieRadioButton.Location = new System.Drawing.Point(56, 0); + this.tMeshModeTuanjieRadioButton.Name = "tMeshModeTuanjieRadioButton"; + this.tMeshModeTuanjieRadioButton.Padding = new System.Windows.Forms.Padding(0, 0, 5, 0); + this.tMeshModeTuanjieRadioButton.Size = new System.Drawing.Size(100, 23); + this.tMeshModeTuanjieRadioButton.TabIndex = 1; + this.tMeshModeTuanjieRadioButton.Text = "Tuanjie mesh"; + this.tMeshModeTuanjieRadioButton.UseVisualStyleBackColor = true; + // + // tMeshModeAutoRadioButton + // + this.tMeshModeAutoRadioButton.AutoSize = true; + this.tMeshModeAutoRadioButton.Checked = true; + this.tMeshModeAutoRadioButton.Dock = System.Windows.Forms.DockStyle.Left; + this.tMeshModeAutoRadioButton.Location = new System.Drawing.Point(0, 0); + this.tMeshModeAutoRadioButton.Name = "tMeshModeAutoRadioButton"; + this.tMeshModeAutoRadioButton.Padding = new System.Windows.Forms.Padding(0, 0, 5, 0); + this.tMeshModeAutoRadioButton.Size = new System.Drawing.Size(56, 23); + this.tMeshModeAutoRadioButton.TabIndex = 0; + this.tMeshModeAutoRadioButton.TabStop = true; + this.tMeshModeAutoRadioButton.Text = "Auto"; + this.tMeshModeAutoRadioButton.UseVisualStyleBackColor = true; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(6, 19); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(80, 15); + this.label1.TabIndex = 0; + this.label1.Text = "Parsing mode"; + // // ImportOptionsForm // this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); @@ -357,6 +446,12 @@ this.tabPage2.PerformLayout(); this.cacheGroupBox.ResumeLayout(false); this.cacheGroupBox.PerformLayout(); + this.tabPage3.ResumeLayout(false); + this.tabPage3.PerformLayout(); + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); + this.panel1.ResumeLayout(false); + this.panel1.PerformLayout(); this.ResumeLayout(false); this.PerformLayout(); @@ -387,5 +482,12 @@ private System.Windows.Forms.TabPage tabPage2; private System.Windows.Forms.GroupBox cacheGroupBox; private System.Windows.Forms.ComboBox legacyUnityVersionComboBox; + private System.Windows.Forms.TabPage tabPage3; + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Panel panel1; + private System.Windows.Forms.RadioButton tMeshModeUnityRadioButton; + private System.Windows.Forms.RadioButton tMeshModeTuanjieRadioButton; + private System.Windows.Forms.RadioButton tMeshModeAutoRadioButton; } } \ No newline at end of file diff --git a/AssetStudioGUI/ImportOptionsForm.cs b/AssetStudioGUI/ImportOptionsForm.cs index b9cf893..c4fa474 100644 --- a/AssetStudioGUI/ImportOptionsForm.cs +++ b/AssetStudioGUI/ImportOptionsForm.cs @@ -1,7 +1,9 @@ using AssetStudio; +using AssetStudio.CustomOptions; using System; using System.Diagnostics; using System.IO; +using System.Linq; using System.Windows.Forms; namespace AssetStudioGUI @@ -31,6 +33,8 @@ namespace AssetStudioGUI alwaysDecompressToDiskCheckBox.Checked = assetsManager.Options.BundleOptions.DecompressToDisk; customBlockInfoCompressionComboBox.SelectedIndex = SetCompressionComboBoxIndex(assetsManager.Options.BundleOptions.CustomBlockInfoCompression); customBlockCompressionComboBox.SelectedIndex = SetCompressionComboBoxIndex(assetsManager.Options.BundleOptions.CustomBlockCompression); + var tMeshMode = assetsManager.Options.MeshOptions.TuanjieMeshParsingMode; + ((RadioButton)panel1.Controls.Cast().First(x => x.TabIndex == (int)tMeshMode)).Checked = true; } private void ApplyOptions() @@ -64,6 +68,9 @@ namespace AssetStudioGUI _assetsManager.Options.BundleOptions.DecompressToDisk = decompressToDisk; Properties.Settings.Default.decompressToDisk = decompressToDisk; + var tMeshModeIndex = ((RadioButton)panel1.Controls.Cast().First(x => ((RadioButton)x).Checked)).TabIndex; + _assetsManager.Options.MeshOptions.TuanjieMeshParsingMode = (ImportOptions.CustomMeshOptions.MeshParsingMode)tMeshModeIndex; + Properties.Settings.Default.Save(); } @@ -193,6 +200,7 @@ namespace AssetStudioGUI Directory.CreateDirectory(_cachePath); DisplayCachePath(); } + #endregion private void saveToDiskButton_Click(object sender, EventArgs e) { @@ -205,7 +213,6 @@ namespace AssetStudioGUI _assetsManager.Options.SaveToFile(savePath); } } - #endregion private void closeButton_Click(object sender, EventArgs e) {