├── .gitignore ├── MultiConverter.GUI ├── About.Designer.cs ├── About.cs ├── About.resx ├── MainForm.Designer.cs ├── MainForm.cs ├── MainForm.resx ├── MultiConverter.GUI.csproj └── Program.cs ├── MultiConverter.Lib ├── Common │ ├── C3Vector.cs │ ├── C4Plane.cs │ ├── CAaBox.cs │ └── CArgb.cs ├── Converters │ ├── ADT │ │ └── ADTFile.cs │ ├── AdtConverter.cs │ ├── AnimConverter.cs │ ├── Base │ │ ├── ChunkedWowFile.cs │ │ ├── IChunk.cs │ │ ├── IConverter.cs │ │ └── WowFile.cs │ ├── Chunks.cs │ ├── ModelConverter.cs │ ├── SkinConverter.cs │ ├── WDTConverter.cs │ ├── WMO │ │ ├── Chunks │ │ │ ├── MFOG.cs │ │ │ ├── MODD.cs │ │ │ ├── MODI.cs │ │ │ ├── MODN.cs │ │ │ ├── MODS.cs │ │ │ ├── MOGI.cs │ │ │ ├── MOGN.cs │ │ │ ├── MOHD.cs │ │ │ ├── MOLT.cs │ │ │ ├── MOMT.cs │ │ │ ├── MOPR.cs │ │ │ ├── MOPT.cs │ │ │ ├── MOPV.cs │ │ │ ├── MOSB.cs │ │ │ ├── MOTX.cs │ │ │ ├── MOVB.cs │ │ │ ├── MOVV.cs │ │ │ └── MVER.cs │ │ ├── Entries │ │ │ ├── MFOGEntry.cs │ │ │ ├── MODDEntry.cs │ │ │ ├── MODSEntry.cs │ │ │ ├── MOGIEntry.cs │ │ │ ├── MOHDEntry.cs │ │ │ ├── MOLTEntry.cs │ │ │ ├── MOMTEntry.cs │ │ │ ├── MOPREntry.cs │ │ │ ├── MOPTEntry.cs │ │ │ └── MOPVEntry.cs │ │ └── WMOFile.cs │ └── WMOGroupConverter.cs ├── MultiConverter.Lib.csproj ├── Updater │ ├── Update.cs │ └── UpdateManager.cs └── Util │ ├── Extensions.cs │ ├── Listfile.cs │ └── Utils.cs ├── MultiConverter.Updater ├── MainForm.Designer.cs ├── MainForm.cs ├── MainForm.resx ├── MultiConverter.Updater.csproj ├── Program.cs └── Updater │ ├── Update.cs │ └── UpdateManager.cs ├── MultiConverter.sln ├── README.MD ├── update.json └── update_beta.json /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | Changes.txt 10 | 11 | # User-specific files (MonoDevelop/Xamarin Studio) 12 | *.userprefs 13 | 14 | # Build results 15 | [Dd]ebug/ 16 | [Dd]ebugPublic/ 17 | [Rr]elease/ 18 | [Rr]eleases/ 19 | bld/ 20 | [Bb]in/ 21 | [Oo]bj/ 22 | [Ll]og/ 23 | 24 | # Visual Studio 2015 cache/options directory 25 | .vs/ 26 | # Uncomment if you have tasks that create the project's static files in wwwroot 27 | #wwwroot/ 28 | 29 | # MSTest test Results 30 | [Tt]est[Rr]esult*/ 31 | [Bb]uild[Ll]og.* 32 | 33 | # NUNIT 34 | *.VisualState.xml 35 | TestResult.xml 36 | 37 | # Build Results of an ATL Project 38 | [Dd]ebugPS/ 39 | [Rr]eleasePS/ 40 | dlldata.c 41 | 42 | # DNX 43 | project.lock.json 44 | artifacts/ 45 | 46 | *_i.c 47 | *_p.c 48 | *_i.h 49 | *.ilk 50 | *.meta 51 | *.obj 52 | *.pch 53 | *.pdb 54 | *.pgc 55 | *.pgd 56 | *.rsp 57 | *.sbr 58 | *.tlb 59 | *.tli 60 | *.tlh 61 | *.tmp 62 | *.tmp_proj 63 | *.log 64 | *.vspscc 65 | *.vssscc 66 | .builds 67 | *.pidb 68 | *.svclog 69 | *.scc 70 | 71 | # Chutzpah Test files 72 | _Chutzpah* 73 | 74 | # Visual C++ cache files 75 | ipch/ 76 | *.aps 77 | *.ncb 78 | *.opendb 79 | *.opensdf 80 | *.sdf 81 | *.cachefile 82 | *.VC.db 83 | *.VC.VC.opendb 84 | 85 | # Visual Studio profiler 86 | *.psess 87 | *.vsp 88 | *.vspx 89 | *.sap 90 | 91 | # TFS 2012 Local Workspace 92 | $tf/ 93 | 94 | # Guidance Automation Toolkit 95 | *.gpState 96 | 97 | # ReSharper is a .NET coding add-in 98 | _ReSharper*/ 99 | *.[Rr]e[Ss]harper 100 | *.DotSettings.user 101 | 102 | # JustCode is a .NET coding add-in 103 | .JustCode 104 | 105 | # TeamCity is a build add-in 106 | _TeamCity* 107 | 108 | # DotCover is a Code Coverage Tool 109 | *.dotCover 110 | 111 | # NCrunch 112 | _NCrunch_* 113 | .*crunch*.local.xml 114 | nCrunchTemp_* 115 | 116 | # MightyMoose 117 | *.mm.* 118 | AutoTest.Net/ 119 | 120 | # Web workbench (sass) 121 | .sass-cache/ 122 | 123 | # Installshield output folder 124 | [Ee]xpress/ 125 | 126 | # DocProject is a documentation generator add-in 127 | DocProject/buildhelp/ 128 | DocProject/Help/*.HxT 129 | DocProject/Help/*.HxC 130 | DocProject/Help/*.hhc 131 | DocProject/Help/*.hhk 132 | DocProject/Help/*.hhp 133 | DocProject/Help/Html2 134 | DocProject/Help/html 135 | 136 | # Click-Once directory 137 | publish/ 138 | 139 | # Publish Web Output 140 | *.[Pp]ublish.xml 141 | *.azurePubxml 142 | # TODO: Comment the next line if you want to checkin your web deploy settings 143 | # but database connection strings (with potential passwords) will be unencrypted 144 | *.pubxml 145 | *.publishproj 146 | 147 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 148 | # checkin your Azure Web App publish settings, but sensitive information contained 149 | # in these scripts will be unencrypted 150 | PublishScripts/ 151 | 152 | # NuGet Packages 153 | *.nupkg 154 | # The packages folder can be ignored because of Package Restore 155 | **/packages/* 156 | # except build/, which is used as an MSBuild target. 157 | !**/packages/build/ 158 | # Uncomment if necessary however generally it will be regenerated when needed 159 | #!**/packages/repositories.config 160 | # NuGet v3's project.json files produces more ignoreable files 161 | *.nuget.props 162 | *.nuget.targets 163 | 164 | # Microsoft Azure Build Output 165 | csx/ 166 | *.build.csdef 167 | 168 | # Microsoft Azure Emulator 169 | ecf/ 170 | rcf/ 171 | 172 | # Windows Store app package directories and files 173 | AppPackages/ 174 | BundleArtifacts/ 175 | Package.StoreAssociation.xml 176 | _pkginfo.txt 177 | 178 | # Visual Studio cache files 179 | # files ending in .cache can be ignored 180 | *.[Cc]ache 181 | # but keep track of directories ending in .cache 182 | !*.[Cc]ache/ 183 | 184 | # Others 185 | ClientBin/ 186 | ~$* 187 | *~ 188 | *.dbmdl 189 | *.dbproj.schemaview 190 | *.publishsettings 191 | node_modules/ 192 | orleans.codegen.cs 193 | 194 | # Since there are multiple workflows, uncomment next line to ignore bower_components 195 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 196 | #bower_components/ 197 | 198 | # RIA/Silverlight projects 199 | Generated_Code/ 200 | 201 | # Backup & report files from converting an old project file 202 | # to a newer Visual Studio version. Backup files are not needed, 203 | # because we have git ;-) 204 | _UpgradeReport_Files/ 205 | UpgradeLog*.XML 206 | UpgradeLog*.htm 207 | 208 | # SQL Server files 209 | *.mdf 210 | *.ldf 211 | 212 | # Business Intelligence projects 213 | *.rdl.data 214 | *.bim.layout 215 | *.bim_*.settings 216 | 217 | # Microsoft Fakes 218 | FakesAssemblies/ 219 | 220 | # GhostDoc plugin setting file 221 | *.GhostDoc.xml 222 | 223 | # Node.js Tools for Visual Studio 224 | .ntvs_analysis.dat 225 | 226 | # Visual Studio 6 build log 227 | *.plg 228 | 229 | # Visual Studio 6 workspace options file 230 | *.opt 231 | 232 | # Visual Studio LightSwitch build output 233 | **/*.HTMLClient/GeneratedArtifacts 234 | **/*.DesktopClient/GeneratedArtifacts 235 | **/*.DesktopClient/ModelManifest.xml 236 | **/*.Server/GeneratedArtifacts 237 | **/*.Server/ModelManifest.xml 238 | _Pvt_Extensions 239 | 240 | # Paket dependency manager 241 | .paket/paket.exe 242 | paket-files/ 243 | 244 | # FAKE - F# Make 245 | .fake/ 246 | 247 | # JetBrains Rider 248 | .idea/ 249 | *.sln.iml 250 | -------------------------------------------------------------------------------- /MultiConverter.GUI/About.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace MultiConverter.GUI 2 | { 3 | partial class About 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | protected override void Dispose(bool disposing) 14 | { 15 | if (disposing && (components != null)) 16 | { 17 | components.Dispose(); 18 | } 19 | base.Dispose(disposing); 20 | } 21 | 22 | #region Windows Form Designer generated code 23 | 24 | /// 25 | /// Required method for Designer support - do not modify 26 | /// the contents of this method with the code editor. 27 | /// 28 | private void InitializeComponent() 29 | { 30 | this.tableLayoutPanel = new System.Windows.Forms.TableLayoutPanel(); 31 | this.labelProductName = new System.Windows.Forms.Label(); 32 | this.labelVersion = new System.Windows.Forms.Label(); 33 | this.labelCopyright = new System.Windows.Forms.Label(); 34 | this.labelCompanyName = new System.Windows.Forms.Label(); 35 | this.textBoxDescription = new System.Windows.Forms.TextBox(); 36 | this.okButton = new System.Windows.Forms.Button(); 37 | this.tableLayoutPanel.SuspendLayout(); 38 | this.SuspendLayout(); 39 | // 40 | // tableLayoutPanel 41 | // 42 | this.tableLayoutPanel.ColumnCount = 1; 43 | this.tableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); 44 | this.tableLayoutPanel.Controls.Add(this.labelProductName, 0, 0); 45 | this.tableLayoutPanel.Controls.Add(this.labelVersion, 0, 1); 46 | this.tableLayoutPanel.Controls.Add(this.labelCopyright, 0, 2); 47 | this.tableLayoutPanel.Controls.Add(this.labelCompanyName, 0, 3); 48 | this.tableLayoutPanel.Controls.Add(this.textBoxDescription, 0, 4); 49 | this.tableLayoutPanel.Controls.Add(this.okButton, 0, 5); 50 | this.tableLayoutPanel.Dock = System.Windows.Forms.DockStyle.Fill; 51 | this.tableLayoutPanel.Location = new System.Drawing.Point(10, 10); 52 | this.tableLayoutPanel.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); 53 | this.tableLayoutPanel.Name = "tableLayoutPanel"; 54 | this.tableLayoutPanel.RowCount = 6; 55 | this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 10.03788F)); 56 | this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 10.03788F)); 57 | this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 10.22727F)); 58 | this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 9.469697F)); 59 | this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50.18939F)); 60 | this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 10.03788F)); 61 | this.tableLayoutPanel.Size = new System.Drawing.Size(487, 307); 62 | this.tableLayoutPanel.TabIndex = 0; 63 | // 64 | // labelProductName 65 | // 66 | this.labelProductName.Dock = System.Windows.Forms.DockStyle.Fill; 67 | this.labelProductName.Location = new System.Drawing.Point(7, 0); 68 | this.labelProductName.Margin = new System.Windows.Forms.Padding(7, 0, 4, 0); 69 | this.labelProductName.MaximumSize = new System.Drawing.Size(0, 20); 70 | this.labelProductName.Name = "labelProductName"; 71 | this.labelProductName.Size = new System.Drawing.Size(476, 20); 72 | this.labelProductName.TabIndex = 19; 73 | this.labelProductName.Text = "Product Name"; 74 | this.labelProductName.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; 75 | // 76 | // labelVersion 77 | // 78 | this.labelVersion.Dock = System.Windows.Forms.DockStyle.Fill; 79 | this.labelVersion.Location = new System.Drawing.Point(7, 30); 80 | this.labelVersion.Margin = new System.Windows.Forms.Padding(7, 0, 4, 0); 81 | this.labelVersion.MaximumSize = new System.Drawing.Size(0, 20); 82 | this.labelVersion.Name = "labelVersion"; 83 | this.labelVersion.Size = new System.Drawing.Size(476, 20); 84 | this.labelVersion.TabIndex = 0; 85 | this.labelVersion.Text = "Version"; 86 | this.labelVersion.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; 87 | // 88 | // labelCopyright 89 | // 90 | this.labelCopyright.Dock = System.Windows.Forms.DockStyle.Fill; 91 | this.labelCopyright.Location = new System.Drawing.Point(7, 60); 92 | this.labelCopyright.Margin = new System.Windows.Forms.Padding(7, 0, 4, 0); 93 | this.labelCopyright.MaximumSize = new System.Drawing.Size(0, 20); 94 | this.labelCopyright.Name = "labelCopyright"; 95 | this.labelCopyright.Size = new System.Drawing.Size(476, 20); 96 | this.labelCopyright.TabIndex = 21; 97 | this.labelCopyright.Text = "Copyright"; 98 | this.labelCopyright.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; 99 | // 100 | // labelCompanyName 101 | // 102 | this.labelCompanyName.Dock = System.Windows.Forms.DockStyle.Fill; 103 | this.labelCompanyName.Location = new System.Drawing.Point(7, 91); 104 | this.labelCompanyName.Margin = new System.Windows.Forms.Padding(7, 0, 4, 0); 105 | this.labelCompanyName.MaximumSize = new System.Drawing.Size(0, 20); 106 | this.labelCompanyName.Name = "labelCompanyName"; 107 | this.labelCompanyName.Size = new System.Drawing.Size(476, 20); 108 | this.labelCompanyName.TabIndex = 22; 109 | this.labelCompanyName.Text = "Company Name"; 110 | this.labelCompanyName.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; 111 | // 112 | // textBoxDescription 113 | // 114 | this.textBoxDescription.Dock = System.Windows.Forms.DockStyle.Fill; 115 | this.textBoxDescription.Location = new System.Drawing.Point(7, 123); 116 | this.textBoxDescription.Margin = new System.Windows.Forms.Padding(7, 3, 4, 3); 117 | this.textBoxDescription.Multiline = true; 118 | this.textBoxDescription.Name = "textBoxDescription"; 119 | this.textBoxDescription.ReadOnly = true; 120 | this.textBoxDescription.ScrollBars = System.Windows.Forms.ScrollBars.Both; 121 | this.textBoxDescription.Size = new System.Drawing.Size(476, 148); 122 | this.textBoxDescription.TabIndex = 23; 123 | this.textBoxDescription.TabStop = false; 124 | this.textBoxDescription.Text = "Description"; 125 | // 126 | // okButton 127 | // 128 | this.okButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); 129 | this.okButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; 130 | this.okButton.Location = new System.Drawing.Point(395, 279); 131 | this.okButton.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); 132 | this.okButton.Name = "okButton"; 133 | this.okButton.Size = new System.Drawing.Size(88, 25); 134 | this.okButton.TabIndex = 24; 135 | this.okButton.Text = "&OK"; 136 | this.okButton.Click += new System.EventHandler(this.okButton_Click); 137 | // 138 | // About 139 | // 140 | this.AcceptButton = this.okButton; 141 | this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); 142 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 143 | this.ClientSize = new System.Drawing.Size(507, 327); 144 | this.Controls.Add(this.tableLayoutPanel); 145 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; 146 | this.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); 147 | this.MaximizeBox = false; 148 | this.MinimizeBox = false; 149 | this.Name = "About"; 150 | this.Padding = new System.Windows.Forms.Padding(10, 10, 10, 10); 151 | this.ShowIcon = false; 152 | this.ShowInTaskbar = false; 153 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; 154 | this.Text = "About"; 155 | this.tableLayoutPanel.ResumeLayout(false); 156 | this.tableLayoutPanel.PerformLayout(); 157 | this.ResumeLayout(false); 158 | 159 | } 160 | 161 | #endregion 162 | 163 | private System.Windows.Forms.TableLayoutPanel tableLayoutPanel; 164 | private System.Windows.Forms.Label labelProductName; 165 | private System.Windows.Forms.Label labelVersion; 166 | private System.Windows.Forms.Label labelCopyright; 167 | private System.Windows.Forms.Label labelCompanyName; 168 | private System.Windows.Forms.TextBox textBoxDescription; 169 | private System.Windows.Forms.Button okButton; 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /MultiConverter.GUI/About.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using System.Windows.Forms; 4 | 5 | namespace MultiConverter.GUI 6 | { 7 | partial class About : Form 8 | { 9 | public About() 10 | { 11 | InitializeComponent(); 12 | this.Text = String.Format("About {0}", AssemblyTitle); 13 | this.labelProductName.Text = AssemblyProduct; 14 | this.labelVersion.Text = String.Format("Version {0}", AssemblyVersion); 15 | this.labelCopyright.Text = AssemblyCopyright; 16 | this.labelCompanyName.Text = AssemblyCompany; 17 | this.textBoxDescription.Text = AssemblyDescription; 18 | } 19 | 20 | #region Assembly Attribute Accessors 21 | 22 | public string AssemblyTitle 23 | { 24 | get 25 | { 26 | object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyTitleAttribute), false); 27 | if (attributes.Length > 0) 28 | { 29 | AssemblyTitleAttribute titleAttribute = (AssemblyTitleAttribute)attributes[0]; 30 | if (titleAttribute.Title != "") 31 | { 32 | return titleAttribute.Title; 33 | } 34 | } 35 | return System.IO.Path.GetFileNameWithoutExtension(Assembly.GetExecutingAssembly().CodeBase); 36 | } 37 | } 38 | 39 | public string AssemblyVersion 40 | { 41 | get 42 | { 43 | return Assembly.GetExecutingAssembly().GetName().Version.ToString(); 44 | } 45 | } 46 | 47 | public string AssemblyDescription 48 | { 49 | get 50 | { 51 | object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyDescriptionAttribute), false); 52 | if (attributes.Length == 0) 53 | { 54 | return ""; 55 | } 56 | return ((AssemblyDescriptionAttribute)attributes[0]).Description; 57 | } 58 | } 59 | 60 | public string AssemblyProduct 61 | { 62 | get 63 | { 64 | object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyProductAttribute), false); 65 | if (attributes.Length == 0) 66 | { 67 | return ""; 68 | } 69 | return ((AssemblyProductAttribute)attributes[0]).Product; 70 | } 71 | } 72 | 73 | public string AssemblyCopyright 74 | { 75 | get 76 | { 77 | object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyCopyrightAttribute), false); 78 | if (attributes.Length == 0) 79 | { 80 | return ""; 81 | } 82 | return ((AssemblyCopyrightAttribute)attributes[0]).Copyright; 83 | } 84 | } 85 | 86 | public string AssemblyCompany 87 | { 88 | get 89 | { 90 | object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyCompanyAttribute), false); 91 | if (attributes.Length == 0) 92 | { 93 | return ""; 94 | } 95 | return ((AssemblyCompanyAttribute)attributes[0]).Company; 96 | } 97 | } 98 | #endregion 99 | 100 | private void okButton_Click(object sender, EventArgs e) 101 | { 102 | Close(); 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /MultiConverter.GUI/About.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /MultiConverter.GUI/MainForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace MultiConverter.GUI 2 | { 3 | partial class ConverterForm 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.fix_btn = new System.Windows.Forms.Button(); 32 | this.lb = new System.Windows.Forms.ListBox(); 33 | this.button1 = new System.Windows.Forms.Button(); 34 | this.progress = new System.Windows.Forms.ProgressBar(); 35 | this.cb_wod = new System.Windows.Forms.CheckBox(); 36 | this.adt_water = new System.Windows.Forms.CheckBox(); 37 | this.adt_models = new System.Windows.Forms.CheckBox(); 38 | this.adt_group = new System.Windows.Forms.GroupBox(); 39 | this.wmo_group = new System.Windows.Forms.GroupBox(); 40 | this.m2_group = new System.Windows.Forms.GroupBox(); 41 | this.helmFix = new System.Windows.Forms.CheckBox(); 42 | this.menuStrip1 = new System.Windows.Forms.MenuStrip(); 43 | this.helpToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 44 | this.aboutToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 45 | this.adt_group.SuspendLayout(); 46 | this.wmo_group.SuspendLayout(); 47 | this.m2_group.SuspendLayout(); 48 | this.menuStrip1.SuspendLayout(); 49 | this.SuspendLayout(); 50 | // 51 | // fix_btn 52 | // 53 | this.fix_btn.Location = new System.Drawing.Point(371, 39); 54 | this.fix_btn.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); 55 | this.fix_btn.Name = "fix_btn"; 56 | this.fix_btn.Size = new System.Drawing.Size(180, 45); 57 | this.fix_btn.TabIndex = 0; 58 | this.fix_btn.Text = "Fix"; 59 | this.fix_btn.UseVisualStyleBackColor = true; 60 | this.fix_btn.Click += new System.EventHandler(this.fix_btn_Click); 61 | // 62 | // lb 63 | // 64 | this.lb.AllowDrop = true; 65 | this.lb.FormattingEnabled = true; 66 | this.lb.ItemHeight = 15; 67 | this.lb.Location = new System.Drawing.Point(15, 40); 68 | this.lb.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); 69 | this.lb.Name = "lb"; 70 | this.lb.Size = new System.Drawing.Size(348, 244); 71 | this.lb.TabIndex = 2; 72 | this.lb.DragDrop += new System.Windows.Forms.DragEventHandler(this.filepath_OnDrop); 73 | this.lb.DragEnter += new System.Windows.Forms.DragEventHandler(this.filepath_DragEnter); 74 | // 75 | // button1 76 | // 77 | this.button1.Location = new System.Drawing.Point(371, 91); 78 | this.button1.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); 79 | this.button1.Name = "button1"; 80 | this.button1.Size = new System.Drawing.Size(180, 45); 81 | this.button1.TabIndex = 3; 82 | this.button1.Text = "Clear"; 83 | this.button1.UseVisualStyleBackColor = true; 84 | this.button1.Click += new System.EventHandler(this.button1_Click); 85 | // 86 | // progress 87 | // 88 | this.progress.Location = new System.Drawing.Point(15, 288); 89 | this.progress.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); 90 | this.progress.Name = "progress"; 91 | this.progress.Size = new System.Drawing.Size(349, 27); 92 | this.progress.TabIndex = 4; 93 | // 94 | // cb_wod 95 | // 96 | this.cb_wod.AutoSize = true; 97 | this.cb_wod.Location = new System.Drawing.Point(6, 16); 98 | this.cb_wod.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); 99 | this.cb_wod.Name = "cb_wod"; 100 | this.cb_wod.Size = new System.Drawing.Size(102, 19); 101 | this.cb_wod.TabIndex = 5; 102 | this.cb_wod.Text = "Legion > WoD"; 103 | this.cb_wod.UseVisualStyleBackColor = true; 104 | // 105 | // adt_water 106 | // 107 | this.adt_water.AutoSize = true; 108 | this.adt_water.Checked = true; 109 | this.adt_water.CheckState = System.Windows.Forms.CheckState.Checked; 110 | this.adt_water.Location = new System.Drawing.Point(7, 22); 111 | this.adt_water.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); 112 | this.adt_water.Name = "adt_water"; 113 | this.adt_water.Size = new System.Drawing.Size(136, 19); 114 | this.adt_water.TabIndex = 6; 115 | this.adt_water.Text = "Liquids (Water, Lava)"; 116 | this.adt_water.UseVisualStyleBackColor = true; 117 | // 118 | // adt_models 119 | // 120 | this.adt_models.AutoSize = true; 121 | this.adt_models.Checked = true; 122 | this.adt_models.CheckState = System.Windows.Forms.CheckState.Checked; 123 | this.adt_models.Location = new System.Drawing.Point(7, 46); 124 | this.adt_models.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); 125 | this.adt_models.Name = "adt_models"; 126 | this.adt_models.Size = new System.Drawing.Size(130, 19); 127 | this.adt_models.TabIndex = 7; 128 | this.adt_models.Text = "Models (WMO, M2)"; 129 | this.adt_models.UseVisualStyleBackColor = true; 130 | // 131 | // adt_group 132 | // 133 | this.adt_group.Controls.Add(this.adt_models); 134 | this.adt_group.Controls.Add(this.adt_water); 135 | this.adt_group.Location = new System.Drawing.Point(371, 241); 136 | this.adt_group.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); 137 | this.adt_group.Name = "adt_group"; 138 | this.adt_group.Padding = new System.Windows.Forms.Padding(4, 3, 4, 3); 139 | this.adt_group.Size = new System.Drawing.Size(180, 74); 140 | this.adt_group.TabIndex = 8; 141 | this.adt_group.TabStop = false; 142 | this.adt_group.Text = "ADT"; 143 | // 144 | // wmo_group 145 | // 146 | this.wmo_group.Controls.Add(this.cb_wod); 147 | this.wmo_group.Location = new System.Drawing.Point(371, 143); 148 | this.wmo_group.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); 149 | this.wmo_group.Name = "wmo_group"; 150 | this.wmo_group.Padding = new System.Windows.Forms.Padding(4, 3, 4, 3); 151 | this.wmo_group.Size = new System.Drawing.Size(180, 43); 152 | this.wmo_group.TabIndex = 9; 153 | this.wmo_group.TabStop = false; 154 | this.wmo_group.Text = "WMO"; 155 | // 156 | // m2_group 157 | // 158 | this.m2_group.Controls.Add(this.helmFix); 159 | this.m2_group.Location = new System.Drawing.Point(371, 193); 160 | this.m2_group.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); 161 | this.m2_group.Name = "m2_group"; 162 | this.m2_group.Padding = new System.Windows.Forms.Padding(4, 3, 4, 3); 163 | this.m2_group.Size = new System.Drawing.Size(180, 42); 164 | this.m2_group.TabIndex = 10; 165 | this.m2_group.TabStop = false; 166 | this.m2_group.Text = "M2"; 167 | // 168 | // helmFix 169 | // 170 | this.helmFix.AutoSize = true; 171 | this.helmFix.Checked = true; 172 | this.helmFix.CheckState = System.Windows.Forms.CheckState.Checked; 173 | this.helmFix.Location = new System.Drawing.Point(9, 16); 174 | this.helmFix.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); 175 | this.helmFix.Name = "helmFix"; 176 | this.helmFix.Size = new System.Drawing.Size(108, 19); 177 | this.helmFix.TabIndex = 0; 178 | this.helmFix.Text = "Helm Offset Fix"; 179 | this.helmFix.UseVisualStyleBackColor = true; 180 | // 181 | // menuStrip1 182 | // 183 | this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { 184 | this.helpToolStripMenuItem}); 185 | this.menuStrip1.Location = new System.Drawing.Point(0, 0); 186 | this.menuStrip1.Name = "menuStrip1"; 187 | this.menuStrip1.Padding = new System.Windows.Forms.Padding(7, 2, 0, 2); 188 | this.menuStrip1.Size = new System.Drawing.Size(565, 24); 189 | this.menuStrip1.TabIndex = 11; 190 | this.menuStrip1.Text = "menuStrip1"; 191 | // 192 | // helpToolStripMenuItem 193 | // 194 | this.helpToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { 195 | this.aboutToolStripMenuItem}); 196 | this.helpToolStripMenuItem.Name = "helpToolStripMenuItem"; 197 | this.helpToolStripMenuItem.Size = new System.Drawing.Size(44, 20); 198 | this.helpToolStripMenuItem.Text = "Help"; 199 | // 200 | // aboutToolStripMenuItem 201 | // 202 | this.aboutToolStripMenuItem.Name = "aboutToolStripMenuItem"; 203 | this.aboutToolStripMenuItem.Size = new System.Drawing.Size(107, 22); 204 | this.aboutToolStripMenuItem.Text = "About"; 205 | this.aboutToolStripMenuItem.Click += new System.EventHandler(this.aboutToolStripMenuItem_Click); 206 | // 207 | // ConverterForm 208 | // 209 | this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); 210 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 211 | this.ClientSize = new System.Drawing.Size(565, 330); 212 | this.Controls.Add(this.m2_group); 213 | this.Controls.Add(this.wmo_group); 214 | this.Controls.Add(this.adt_group); 215 | this.Controls.Add(this.progress); 216 | this.Controls.Add(this.button1); 217 | this.Controls.Add(this.lb); 218 | this.Controls.Add(this.fix_btn); 219 | this.Controls.Add(this.menuStrip1); 220 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow; 221 | this.MainMenuStrip = this.menuStrip1; 222 | this.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); 223 | this.MaximumSize = new System.Drawing.Size(581, 369); 224 | this.MinimumSize = new System.Drawing.Size(581, 369); 225 | this.Name = "ConverterForm"; 226 | this.Text = "Multi-Converter"; 227 | this.adt_group.ResumeLayout(false); 228 | this.adt_group.PerformLayout(); 229 | this.wmo_group.ResumeLayout(false); 230 | this.wmo_group.PerformLayout(); 231 | this.m2_group.ResumeLayout(false); 232 | this.m2_group.PerformLayout(); 233 | this.menuStrip1.ResumeLayout(false); 234 | this.menuStrip1.PerformLayout(); 235 | this.ResumeLayout(false); 236 | this.PerformLayout(); 237 | 238 | } 239 | 240 | #endregion 241 | 242 | private System.Windows.Forms.Button fix_btn; 243 | private System.Windows.Forms.ListBox lb; 244 | private System.Windows.Forms.Button button1; 245 | private System.Windows.Forms.ProgressBar progress; 246 | private System.Windows.Forms.CheckBox cb_wod; 247 | private System.Windows.Forms.CheckBox adt_water; 248 | private System.Windows.Forms.CheckBox adt_models; 249 | private System.Windows.Forms.GroupBox adt_group; 250 | private System.Windows.Forms.GroupBox wmo_group; 251 | private System.Windows.Forms.GroupBox m2_group; 252 | private System.Windows.Forms.CheckBox helmFix; 253 | private System.Windows.Forms.MenuStrip menuStrip1; 254 | private System.Windows.Forms.ToolStripMenuItem helpToolStripMenuItem; 255 | private System.Windows.Forms.ToolStripMenuItem aboutToolStripMenuItem; 256 | } 257 | } 258 | 259 | -------------------------------------------------------------------------------- /MultiConverter.GUI/MainForm.cs: -------------------------------------------------------------------------------- 1 | using MultiConverter.Lib; 2 | using MultiConverter.Lib.Updater; 3 | using MultiConverter.Lib.Converters; 4 | using MultiConverter.Lib.Converters.ADT; 5 | using MultiConverter.Lib.Converters.Base; 6 | using MultiConverter.Lib.Converters.WMO; 7 | using System; 8 | using System.Collections.Generic; 9 | using System.ComponentModel; 10 | using System.Diagnostics; 11 | using System.IO; 12 | using System.Text.RegularExpressions; 13 | using System.Threading; 14 | using System.Windows.Forms; 15 | using System.Reflection; 16 | 17 | namespace MultiConverter.GUI 18 | { 19 | public partial class ConverterForm : Form 20 | { 21 | public static int PROGRESS = 5; 22 | 23 | public ConverterForm() 24 | { 25 | new Thread(() => 26 | { 27 | if (!Listfile.IsInitialized) 28 | Listfile.Initialize(); 29 | }).Start(); 30 | 31 | InitializeComponent(); 32 | lb.HorizontalScrollbar = true; 33 | 34 | new Thread(() => 35 | { 36 | Thread.Sleep(3000); 37 | 38 | var hasUpdate = UpdateManager.HasUpdates(AssemblyVersion); 39 | if (hasUpdate.Item1) 40 | { 41 | var messageBox = MessageBox.Show($"An update is available! From: {AssemblyVersion} To: {hasUpdate.Item2}.\nPress OK to update.", "Update!", MessageBoxButtons.OK); 42 | if (messageBox == DialogResult.OK) 43 | { 44 | // Start the updater.. 45 | UpdateManager.StartUpdater(); 46 | 47 | // Close the current window. 48 | Invoke((MethodInvoker)delegate 49 | { 50 | Close(); 51 | }); 52 | } 53 | } 54 | }).Start(); 55 | } 56 | 57 | private void Clear() => lb.Items.Clear(); 58 | 59 | private void fix_btn_Click(object sender, EventArgs e) 60 | { 61 | if (lb.Items.Count == 0) 62 | return; 63 | 64 | if (lb.Items.Count > 0) 65 | { 66 | progress.Value = 0; 67 | progress.Maximum = lb.Items.Count; 68 | progress.Step = PROGRESS; 69 | Fix(); 70 | } 71 | } 72 | 73 | private void Fix() 74 | { 75 | Enabled = false; 76 | 77 | var filenameList = new List(); 78 | foreach (var item in lb.Items) 79 | filenameList.Add(item.ToString()); 80 | 81 | FixList(filenameList); 82 | } 83 | 84 | private void FixList(List list) 85 | { 86 | var bw = new BackgroundWorker(); 87 | bw.WorkerReportsProgress = true; 88 | 89 | bw.DoWork += new DoWorkEventHandler((sender, e) => 90 | { 91 | var filenames = e.Argument as List; 92 | var progress = 0; 93 | 94 | var worker = sender as BackgroundWorker; 95 | 96 | foreach (string filename in filenames) 97 | { 98 | IConverter converter = null; 99 | 100 | if (filename.EndsWith("m2")) 101 | { 102 | var m2converter = new M2Converter(filename, helmFix.Checked); 103 | if (m2converter.Fix()) 104 | m2converter.Save(); 105 | 106 | continue; 107 | } 108 | else if (filename.EndsWith("adt")) 109 | converter = new ADTFile(filename.Replace(".adt", "_obj0.adt"), filename.Replace(".adt", "_tex0.adt")); 110 | // else if (filename.EndsWith("wdt")) 111 | // converter = new WDTConverter(filename); 112 | else if (Regex.IsMatch(filename, @".*_[0-9]{3}(_(lod[0-9]))?\.(wmo)")) 113 | { 114 | var wmoconverter = new WMOGroupConverter(filename, false); 115 | if (wmoconverter.Fix()) 116 | wmoconverter.Save(); 117 | 118 | continue; 119 | } 120 | else if (filename.EndsWith(".skin")) 121 | continue; 122 | if (filename.EndsWith("wmo")) 123 | converter = new WMOFile(); 124 | // else if (filename.EndsWith("anim")) 125 | // converter = new AnimConverter(filename); 126 | 127 | converter.Read(File.ReadAllBytes(filename)); 128 | converter.Write(filename); 129 | 130 | if (++progress == PROGRESS) 131 | { 132 | worker.ReportProgress(1); 133 | progress = 0; 134 | } 135 | } 136 | }); 137 | 138 | bw.ProgressChanged += new ProgressChangedEventHandler((sender, e) => 139 | { 140 | progress.PerformStep(); 141 | }); 142 | 143 | bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler((sender, e) => 144 | { 145 | if (e.Error != null) 146 | MessageBox.Show(e.Error.ToString()); 147 | 148 | progress.Value = progress.Maximum; 149 | Enabled = true; 150 | Clear(); 151 | }); 152 | 153 | bw.RunWorkerAsync(list); 154 | } 155 | 156 | private void filepath_DragEnter(object sender, DragEventArgs e) 157 | { 158 | if (e.Data.GetDataPresent(DataFormats.FileDrop)) 159 | e.Effect = DragDropEffects.Copy; 160 | else 161 | e.Effect = DragDropEffects.None; 162 | } 163 | 164 | private void filepath_OnDrop(object sender, DragEventArgs e) 165 | { 166 | if (e.Data.GetDataPresent(DataFormats.FileDrop)) 167 | { 168 | progress.Value = 0; 169 | var list = (string[])e.Data.GetData(DataFormats.FileDrop, false); 170 | LoadFiles(list); 171 | } 172 | } 173 | 174 | private void LoadFiles(string[] list) 175 | { 176 | this.Enabled = false; 177 | 178 | BackgroundWorker bw = new BackgroundWorker(); 179 | bw.WorkerReportsProgress = true; 180 | bw.WorkerSupportsCancellation = false; 181 | 182 | bw.DoWork += new DoWorkEventHandler((sender, e) => 183 | { 184 | Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High; 185 | var files = e.Argument as string[]; 186 | var lf = new HashSet(); 187 | 188 | foreach (var s in files) 189 | { 190 | if (Directory.Exists(s)) 191 | { 192 | foreach (string file in Directory.EnumerateFiles(s, "*.*", SearchOption.AllDirectories)) 193 | if (Utils.IsCorrectFile(file) && !lf.Contains(file)) 194 | lf.Add(file.ToLower()); 195 | } 196 | else if (Utils.IsCorrectFile(s) && !lf.Contains(s)) 197 | lf.Add(s.ToLower()); 198 | } 199 | 200 | e.Result = lf; 201 | }); 202 | 203 | bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler((sender, e) => 204 | { 205 | var files = (HashSet)e.Result; 206 | foreach (string file in files) 207 | lb.Items.Add(file); 208 | Enabled = true; 209 | }); 210 | 211 | bw.RunWorkerAsync(list); 212 | } 213 | 214 | private void button1_Click(object sender, EventArgs e) 215 | { 216 | progress.Value = 0; 217 | Clear(); 218 | } 219 | 220 | private void aboutToolStripMenuItem_Click(object sender, EventArgs e) 221 | { 222 | var aboutBox = new About(); 223 | aboutBox.Show(); 224 | } 225 | 226 | public string AssemblyVersion 227 | { 228 | get 229 | { 230 | return Assembly.GetExecutingAssembly().GetName().Version.ToString(); 231 | } 232 | } 233 | } 234 | } 235 | -------------------------------------------------------------------------------- /MultiConverter.GUI/MainForm.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /MultiConverter.GUI/MultiConverter.GUI.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | netcoreapp3.1 6 | true 7 | 3.6.1.0 8 | WoW - MultiConverter 9 | MaxtorCoder & Adspartan 10 | The Fuckporting Company 11 | WoW - MultiConverter 12 | Copyright © 2018 - 2020 13 | WoW Multi-Converter made by Adspartan and maintained by MaxtorCoder. 14 | 15 | Code is on https://github.com/MaxtorCoder/MultiConverter 16 | https://github.com/MaxtorCoder/MultiConverter 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | false 25 | false 26 | 3.6.2.0 27 | 3.6.2.0 28 | 29 | 30 | 31 | ..\bin\Debug\ 32 | 33 | 34 | ..\bin\Release\ 35 | 36 | 37 | -------------------------------------------------------------------------------- /MultiConverter.GUI/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Forms; 3 | 4 | namespace MultiConverter.GUI 5 | { 6 | static class Program 7 | { 8 | /// 9 | /// The main entry point for the application. 10 | /// 11 | [STAThread] 12 | static void Main() 13 | { 14 | Application.SetHighDpiMode(HighDpiMode.SystemAware); 15 | Application.EnableVisualStyles(); 16 | Application.SetCompatibleTextRenderingDefault(false); 17 | Application.Run(new ConverterForm()); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /MultiConverter.Lib/Common/C3Vector.cs: -------------------------------------------------------------------------------- 1 | namespace MultiConverter.Lib.Common 2 | { 3 | public struct C3Vector 4 | { 5 | public float X; 6 | public float Y; 7 | public float Z; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /MultiConverter.Lib/Common/C4Plane.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace MultiConverter.Lib.Common 6 | { 7 | public struct C4Plane 8 | { 9 | public C3Vector Normal; 10 | public float Distance; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /MultiConverter.Lib/Common/CAaBox.cs: -------------------------------------------------------------------------------- 1 | namespace MultiConverter.Lib.Common 2 | { 3 | public struct CAaBox 4 | { 5 | public C3Vector Min; 6 | public C3Vector Max; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /MultiConverter.Lib/Common/CArgb.cs: -------------------------------------------------------------------------------- 1 | namespace MultiConverter.Lib.Common 2 | { 3 | public struct CArgb 4 | { 5 | public byte R; 6 | public byte G; 7 | public byte B; 8 | public byte A; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /MultiConverter.Lib/Converters/ADT/ADTFile.cs: -------------------------------------------------------------------------------- 1 | using MultiConverter.Lib.Converters.Base; 2 | // using MultiConverter.Lib.Converters.ADT.Chunks; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Linq; 7 | 8 | 9 | namespace MultiConverter.Lib.Converters.ADT 10 | { 11 | public class ADTFile : IConverter 12 | { 13 | public static List Chunks = new List(); 14 | public static Dictionary ChunkData = new Dictionary(); 15 | public static Dictionary ChunkExtraData = new Dictionary(); 16 | 17 | public static bool DisableDoodads = false; 18 | public static bool DisableWMOs = false; 19 | 20 | public ADTFile(string objFilename, string texFilename) 21 | { 22 | 23 | } 24 | 25 | public void Read(byte[] inData) 26 | { 27 | // Clear chunks to prevent double data. 28 | Chunks.Clear(); 29 | 30 | using (var stream = new MemoryStream(inData)) 31 | using (var reader = new BinaryReader(stream)) 32 | { 33 | var chunkOrder = 0u; 34 | while (reader.BaseStream.Position < reader.BaseStream.Length) 35 | { 36 | var chunkId = new string(reader.ReadChars(4).Reverse().ToArray()); 37 | var chunkSize = reader.ReadUInt32(); 38 | 39 | var chunkData = new byte[chunkSize]; 40 | Buffer.BlockCopy(stream.ToArray(), (int)reader.BaseStream.Position, chunkData, 0, (int)chunkSize); 41 | 42 | IChunk chunk = null; 43 | switch (chunkId) 44 | { 45 | default: 46 | Console.WriteLine($"Skipping {chunkId}"); 47 | break; 48 | } 49 | 50 | if (chunk != null) 51 | chunk.Read(chunkData); 52 | 53 | ChunkExtraData.Add(chunkId, (chunkOrder, false)); 54 | ChunkData.Add(chunkId, chunk != null ? chunk.Write() : chunkData); 55 | 56 | ++chunkOrder; 57 | reader.BaseStream.Position += chunkSize; 58 | } 59 | 60 | // Close the streams so they can be written. 61 | reader.Close(); 62 | stream.Close(); 63 | } 64 | } 65 | 66 | public void Write(string filename) 67 | { 68 | using (var stream = new MemoryStream()) 69 | using (var writer = new BinaryWriter(stream)) 70 | { 71 | foreach (var chunk in ChunkData) 72 | { 73 | var reversedSignature = chunk.Key.Reverse().ToArray(); 74 | 75 | foreach (var signatureChar in reversedSignature) 76 | writer.Write(signatureChar); 77 | 78 | writer.Write(chunk.Value.Length); 79 | writer.Write(chunk.Value); 80 | } 81 | 82 | File.WriteAllBytes(filename, stream.ToArray()); 83 | } 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /MultiConverter.Lib/Converters/AdtConverter.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using System.IO; 4 | using MultiConverter.Lib.Converters.Base; 5 | using MultiConverter.Lib.Common; 6 | using MultiConverter.Lib.Util; 7 | 8 | namespace MultiConverter.Lib.Converters 9 | { 10 | public class AdtConverter 11 | { 12 | private string modelname; 13 | private string file; 14 | private ChunkedWowFile adt; 15 | private ChunkedWowFile obj; 16 | private ChunkedWowFile tex; 17 | private bool water; 18 | private bool models; 19 | private int textureCount = 0; 20 | 21 | private int adtPos = 0; 22 | private int texPos = 0; 23 | private int objPos = 0; 24 | 25 | private Dictionary MDXFilenames = new Dictionary(); 26 | private Dictionary WMOFilenames = new Dictionary(); 27 | private Dictionary MapTextures = new Dictionary(); 28 | private List MDDFs = new List(); 29 | private List MODFs = new List(); 30 | 31 | public AdtConverter(string path, bool h2o, bool model) 32 | { 33 | file = path; 34 | water = h2o; 35 | models = model; 36 | modelname = Path.GetFileNameWithoutExtension(path); 37 | 38 | adt = new ChunkedWowFile(path); 39 | obj = new ChunkedWowFile(path.Replace(".adt", "_obj0.adt")); 40 | tex = new ChunkedWowFile(path.Replace(".adt", "_tex0.adt")); 41 | 42 | // clean the folder 43 | Utils.DeleteFile(path.Replace(".adt", "_obj1.adt")); 44 | Utils.DeleteFile(path.Replace(".adt", "_lod.adt")); 45 | } 46 | 47 | public bool Fix() 48 | { 49 | // already converted 50 | if (!adt.Valid || !obj.Valid || !tex.Valid || adt.ReadUInt(0x18) > 0) 51 | return false; 52 | 53 | // Update the version 54 | adt.WriteInt(8, 12); 55 | 56 | CreateMCIN(); 57 | 58 | if (adt.HasChunk("MTEX")) 59 | RetrieveMTEX(); 60 | if (adt.HasChunk("MMDX")) 61 | RetrieveMMDX(); 62 | if (tex.HasChunk("MDID") && tex.HasChunk("MHID")) //< Textures. 63 | { 64 | RetrieveTextures(); 65 | WriteMTEX(); 66 | } 67 | 68 | if (obj.HasChunk("MMID") && obj.HasChunk("MWMO") && obj.HasChunk("MWID")) 69 | { 70 | RetrieveMMID(); 71 | RetrieveMWMO(); 72 | RetrieveMWID(); 73 | } 74 | 75 | if (obj.HasChunk("MDDF") && obj.HasChunk("MODF")) 76 | { 77 | 78 | } 79 | 80 | CheckMH2O(); 81 | 82 | for (int i = 0; i < 256; ++i) 83 | RetrieveMCNK(i); 84 | 85 | CheckMFBO(); 86 | 87 | RetrieveMTXF(); 88 | 89 | return true; 90 | } 91 | 92 | private void CreateMDXChunks() 93 | { 94 | var calculatedSize = CalculateChunkSize(MDXFilenames); 95 | adt.AddEmptyBytes(adtPos, (int)calculatedSize + 8); 96 | adt.WriteHeaderMagic("MMDX", ref adtPos); 97 | adt.WriteUInt(calculatedSize, ref adtPos); 98 | 99 | foreach (var filename in MDXFilenames.Values) 100 | adt.WriteString(filename, ref adtPos); 101 | 102 | adt.AddEmptyBytes(adtPos, (MDXFilenames.Count * 4) + 8); 103 | adt.WriteHeaderMagic("MMID", ref adtPos); 104 | adt.WriteInt(MDXFilenames.Count * 4, ref adtPos); 105 | 106 | var mdxFilenames = MDXFilenames.Values.ToList(); 107 | var lastMDX = string.Empty; 108 | foreach (var filename in mdxFilenames) 109 | { 110 | if (lastMDX == string.Empty) 111 | adt.WriteInt(0, ref adtPos); 112 | else 113 | adt.WriteInt(lastMDX.Length, ref adtPos); 114 | 115 | lastMDX = filename; 116 | } 117 | } 118 | 119 | private void CreateWMOChunks() 120 | { 121 | var calculatedSize = CalculateChunkSize(WMOFilenames); 122 | adt.AddEmptyBytes(adtPos, (int)calculatedSize + 8); 123 | adt.WriteHeaderMagic("MWMO", ref adtPos); 124 | adt.WriteUInt(calculatedSize, ref adtPos); 125 | 126 | foreach (var filename in WMOFilenames.Values) 127 | adt.WriteString(filename, ref adtPos); 128 | 129 | adt.AddEmptyBytes(adtPos, (WMOFilenames.Count * 4) + 8); 130 | adt.WriteHeaderMagic("MWID", ref adtPos); 131 | adt.WriteInt(WMOFilenames.Count * 4, ref adtPos); 132 | 133 | var wmoFilenames = WMOFilenames.Values.ToList(); 134 | var lastWMO = string.Empty; 135 | foreach (var filename in wmoFilenames) 136 | { 137 | if (lastWMO == string.Empty) 138 | adt.WriteInt(0, ref adtPos); 139 | else 140 | adt.WriteInt(lastWMO.Length, ref adtPos); 141 | 142 | lastWMO = filename; 143 | } 144 | } 145 | 146 | private void CreateMCIN() 147 | { 148 | adt.AddEmptyBytes(0x54, 0x1008); 149 | adt.WriteInt(0x54, ChunkedWowFile.MagicToInt("MCIN")); 150 | adt.WriteInt(0x58, 0x1000); // chunk size 151 | adt.WriteInt(0x18, 0x40); 152 | 153 | // after mcin chunk 154 | adtPos = 0x1008 + 0x54; 155 | } 156 | 157 | private void RetrieveMTEX() 158 | { 159 | // skip MAMP chunk 160 | int start_mtex = tex.IsChunk(0xC, ChunkedWowFile.MagicToInt("MAMP")) ? tex.ReadInt(0x10) + 0x14 : 0xC; 161 | 162 | // real size = size + 0x8 (header size) 163 | int size = tex.ReadInt(start_mtex + 4) + 0x8; 164 | 165 | // start MTEX 166 | adt.AddEmptyBytes(adtPos, size); 167 | 168 | tex.BlockCopy(start_mtex, adt, adtPos, size); 169 | // remove unecessary data 170 | tex.RemoveBytes(0x0, start_mtex + size); 171 | 172 | adt.WriteInt(0x1C, adtPos - 0x14); 173 | 174 | for (int i = adtPos + 0x8; i < adtPos + size; ++i) 175 | { 176 | if (adt.Data[i] == 0) 177 | { 178 | textureCount++; 179 | } 180 | } 181 | 182 | adtPos += size; 183 | } 184 | 185 | private void RetrieveMMDX() 186 | { 187 | int size = 0x8; 188 | 189 | if (models) 190 | { 191 | size += obj.ReadInt(0x10); 192 | 193 | adt.AddEmptyBytes(adtPos, size); 194 | obj.BlockCopy(0xC, adt, adtPos, size); 195 | obj.RemoveBytes(0, size + 0xC); 196 | 197 | } 198 | else 199 | { 200 | adt.AddEmptyBytes(adtPos, size); 201 | adt.WriteHeaderMagic(adtPos, "MMDX"); 202 | obj.RemoveBytes(0, obj.ReadInt(0x10) + 0xC + 0x8); 203 | } 204 | 205 | adt.WriteInt(0x20, adtPos - 0x14); 206 | adtPos += size; 207 | } 208 | 209 | private void RetrieveMMID() 210 | { 211 | int size = 0x8; 212 | 213 | if (models) 214 | { 215 | size += obj.ReadInt(0x4); 216 | adt.AddEmptyBytes(adtPos, size); 217 | obj.BlockCopy(0, adt, adtPos, size); 218 | obj.RemoveBytes(0, size); 219 | } 220 | else 221 | { 222 | adt.AddEmptyBytes(adtPos, size); 223 | adt.WriteHeaderMagic(adtPos, "MMID"); 224 | obj.RemoveBytes(0, obj.ReadInt(0x4) + 0x8); 225 | } 226 | 227 | adt.WriteInt(0x24, adtPos - 0x14); 228 | adtPos += size; 229 | } 230 | 231 | private void RetrieveMWMO() 232 | { 233 | int size = 0x8; 234 | 235 | if (models) 236 | { 237 | size += obj.ReadInt(0x4); 238 | adt.AddEmptyBytes(adtPos, size); 239 | obj.BlockCopy(0, adt, adtPos, size); 240 | obj.RemoveBytes(0, size); 241 | } 242 | else 243 | { 244 | adt.AddEmptyBytes(adtPos, size); 245 | adt.WriteHeaderMagic(adtPos, "MWMO"); 246 | obj.RemoveBytes(0, obj.ReadInt(0x4) + 0x8); 247 | } 248 | 249 | 250 | adt.WriteInt(0x28, adtPos - 0x14); 251 | adtPos += size; 252 | } 253 | 254 | private void RetrieveMWID() 255 | { 256 | int size = 0x8; 257 | 258 | if (models) 259 | { 260 | size += obj.ReadInt(0x4); 261 | adt.AddEmptyBytes(adtPos, size); 262 | obj.BlockCopy(0, adt, adtPos, size); 263 | obj.RemoveBytes(0, size); 264 | } 265 | else 266 | { 267 | adt.AddEmptyBytes(adtPos, size); 268 | adt.WriteHeaderMagic(adtPos, "MWID"); 269 | obj.RemoveBytes(0, obj.ReadInt(0x4) + 0x8); 270 | } 271 | 272 | adt.WriteInt(0x2C, adtPos - 0x14); 273 | adtPos += size; 274 | } 275 | 276 | private void RetrieveTextures() 277 | { 278 | using (var stream = new MemoryStream(tex.Data)) 279 | using (var reader = new BinaryReader(stream)) 280 | { 281 | while (reader.BaseStream.Position < reader.BaseStream.Length) 282 | { 283 | var chunk = new string(reader.ReadChars(4)); 284 | var size = reader.ReadUInt32(); 285 | 286 | switch (chunk) 287 | { 288 | case "PMAM": 289 | texPos += (int)size + 8; 290 | reader.BaseStream.Position += size; 291 | break; 292 | case "DIDM": //< Texures 293 | for (var i = 0; i < size / 4; ++i) 294 | { 295 | var filedataid = reader.ReadUInt32(); 296 | if (filedataid != 0) 297 | { 298 | var filename = Listfile.LookupFilename(filedataid, ".adt", modelname) + "\0"; 299 | MapTextures.Add(filedataid, filename); 300 | } 301 | } 302 | 303 | texPos += (int)size + 8; 304 | break; 305 | case "DIHM": //< Textures as well 306 | for (var i = 0; i < size / 4; ++i) 307 | { 308 | var filedataid = reader.ReadUInt32(); 309 | if (filedataid != 0) 310 | { 311 | var filename = Listfile.LookupFilename(filedataid, ".adt", modelname) + "\0"; 312 | MapTextures.Add(filedataid, filename); 313 | } 314 | } 315 | 316 | texPos += (int)size + 8; 317 | break; 318 | default: 319 | reader.BaseStream.Position += size; 320 | break; 321 | } 322 | } 323 | } 324 | } 325 | 326 | private void WriteMTEX() 327 | { 328 | var calculatedSize = CalculateChunkSize(MapTextures); 329 | adt.AddEmptyBytes(adtPos, (int)calculatedSize + 8); 330 | adt.WriteHeaderMagic("MTEX", ref adtPos); 331 | adt.WriteUInt(calculatedSize, ref adtPos); 332 | 333 | foreach (var texture in MapTextures.Values) 334 | adt.WriteString(texture, ref adtPos); 335 | } 336 | 337 | private void Fix_MH2O_Info(int pos) 338 | { 339 | ushort id = adt.ReadUShort(pos); 340 | ushort type = adt.ReadUShort(pos + 0x2); 341 | 342 | if (id > 100) 343 | { 344 | switch (id) 345 | { 346 | case 181: 347 | case 221: 348 | case 301: 349 | case 406: 350 | case 407: 351 | case 411: 352 | case 689: 353 | case 733: 354 | case 750: 355 | case 751: 356 | case 752: 357 | case 760: 358 | case 761: 359 | case 763: 360 | case 764: 361 | case 765: 362 | case 787: 363 | case 805: 364 | case 806: 365 | case 807: 366 | case 808: 367 | case 809: 368 | case 812: 369 | case 814: 370 | case 834: 371 | case 837: 372 | case 839: 373 | case 844: 374 | case 848: 375 | case 849: 376 | case 850: 377 | case 851: 378 | case 852: 379 | case 853: 380 | case 855: 381 | case 864: 382 | case 865: 383 | case 866: 384 | case 872: 385 | case 880: 386 | case 881: 387 | case 884: 388 | case 885: 389 | case 886: 390 | case 887: 391 | case 888: 392 | case 892: 393 | case 894: 394 | default: // water for default 395 | id = 5; 396 | break; 397 | case 101: 398 | case 321: 399 | case 324: 400 | case 350: 401 | case 412: 402 | case 868: 403 | case 890: 404 | case 891: 405 | case 896: 406 | id = 2; 407 | break; 408 | case 121: 409 | case 141: 410 | case 302: 411 | case 303: 412 | case 397: 413 | case 404: 414 | case 671: 415 | case 739: 416 | case 859: 417 | case 860: 418 | case 869: 419 | case 870: 420 | case 873: 421 | case 874: 422 | case 875: 423 | case 876: 424 | case 877: 425 | case 878: 426 | case 879: 427 | id = 7; 428 | break; 429 | case 586: 430 | id = 4; 431 | break; 432 | 433 | } 434 | } 435 | 436 | switch (id) 437 | { 438 | // ocean 439 | case 2: 440 | case 6: 441 | case 10: 442 | case 14: 443 | case 100: 444 | type = 2; 445 | break; 446 | // lava 447 | case 3: 448 | case 7: 449 | case 11: 450 | case 15: 451 | type = 1; 452 | break; 453 | // water and slime (no data found for this one that's why) 454 | default: 455 | type = 0; 456 | break; 457 | } 458 | adt.WriteUShort(pos, id); 459 | adt.WriteUShort(pos + 0x2, type); 460 | } 461 | 462 | private void FixMH2O(int start) 463 | { 464 | int pos = start; 465 | 466 | for (int i = 0; i < 256; ++i) 467 | { 468 | int ofs = adt.ReadInt(pos); 469 | if (ofs > 0) 470 | { 471 | Fix_MH2O_Info(start + ofs); 472 | } 473 | pos += 0xC; 474 | } 475 | } 476 | 477 | private void CheckMH2O() 478 | { 479 | if (adt.IsChunk(adtPos, "MH2O")) 480 | { 481 | if (water) 482 | { 483 | FixMH2O(adtPos + 0x8); 484 | int size = adt.ReadInt(adtPos + 4) + 0x8; 485 | adt.WriteInt(0x3C, adtPos - 0x14); 486 | adtPos += size; 487 | } 488 | else 489 | { 490 | adt.RemoveBytes(adtPos, adt.ReadInt(adtPos + 4) + 0x8); 491 | adt.WriteInt(0x3C, 0); 492 | } 493 | } 494 | else // no MH2O 495 | { 496 | adt.WriteInt(0x3C, 0); 497 | } 498 | } 499 | 500 | private ushort HighToLowResHole(ulong hole) 501 | { 502 | if (hole == 0) 503 | { 504 | return 0; 505 | } 506 | 507 | ushort low = 0x0000; 508 | 509 | for (int i = 0; i < 64; ++i) 510 | { 511 | if (((hole >> i) & 0x1) != 0) 512 | { 513 | int x = (i % 8) / 2, y = i / 16; 514 | low |= (ushort)(1 << (x + y * 4)); 515 | } 516 | } 517 | 518 | return low; 519 | } 520 | 521 | enum chunks : int 522 | { 523 | MCNK = 1296256587, 524 | MCCV = 1296253782, 525 | MCNR = 1296256594, 526 | MCLY = 1296256089, 527 | MCRF = 1296257606, 528 | MCSH = 1296257864, 529 | MCAL = 1296253260, 530 | MCSE = 1296257861, 531 | // cata+ 532 | MCRD = 1296257604, 533 | MCRW = 1296257623, 534 | MCLV = 1296256086, 535 | } 536 | 537 | private void RetrieveMCNK(int id = 0) 538 | { 539 | // adt.RemoveUnwantedChunksUntil(0, (int)chunks.MCNK); 540 | // tex.RemoveUnwantedChunksUntil(0, (int)chunks.MCNK); 541 | // obj.RemoveUnwantedChunksUntil(0, (int)chunks.MCNK); 542 | 543 | var root_mcnk_int = ChunkedWowFile.MagicToInt("MCNK"); 544 | var mcnk_ofs_root = adt.ChunksOfs(0, root_mcnk_int); 545 | var mcnk_ofs_tex = tex.ChunksOfs(0, root_mcnk_int); 546 | var mcnk_ofs_obj = obj.ChunksOfs(0, root_mcnk_int); 547 | 548 | int size_root_mcnk = adt.ReadInt(mcnk_ofs_root[root_mcnk_int] + 4); 549 | int size_tex_mcnk = tex.ReadInt(mcnk_ofs_tex[root_mcnk_int] + 4); 550 | int size_obj_mcnk = obj.ReadInt(mcnk_ofs_obj[root_mcnk_int] + 4); 551 | 552 | mcnk_ofs_root.Remove(root_mcnk_int); 553 | mcnk_ofs_tex.Remove(root_mcnk_int); 554 | mcnk_ofs_obj.Remove(root_mcnk_int); 555 | 556 | ChunkedWowFile root_mcnk = new ChunkedWowFile(adt.Data, mcnk_ofs_root[root_mcnk_int] + 8, size_root_mcnk); 557 | ChunkedWowFile tex_mcnk = new ChunkedWowFile(tex.Data, mcnk_ofs_tex[root_mcnk_int] + 8, size_tex_mcnk); 558 | ChunkedWowFile obj_mcnk = new ChunkedWowFile(obj.Data, mcnk_ofs_obj[root_mcnk_int] + 8, size_obj_mcnk); 559 | 560 | // remove MCNK in split files 561 | tex.RemoveBytes(0, size_tex_mcnk + 8); 562 | obj.RemoveBytes(0, size_obj_mcnk + 8); 563 | 564 | Dictionary adt_chunks = root_mcnk.ChunksOfs(0x88, (int)chunks.MCNK); 565 | Dictionary tex_chunks = tex_mcnk.ChunksOfs(0, (int)chunks.MCNK); 566 | Dictionary obj_chunks = obj_mcnk.ChunksOfs(0, (int)chunks.MCNK); 567 | 568 | int pos = 0; 569 | int ofsMCVT = 0x88; 570 | int sizeMCVT = (9 * 9 + 8 * 8) * 4; 571 | 572 | root_mcnk.WriteInt(pos + 0x3C, 0); 573 | 574 | uint flags = root_mcnk.ReadUInt(pos + 0x8); 575 | 576 | // fix high res hole 577 | if ((flags & 0x10000) != 0) 578 | { 579 | root_mcnk.WriteUShort(pos + 0x3C + 0x8, HighToLowResHole(root_mcnk.ReadULong(pos + 0x14 + 0x8))); 580 | } 581 | 582 | root_mcnk.WriteUInt(pos + 0x8, flags & 0xFFFF); 583 | 584 | pos += ofsMCVT + 0x8 + sizeMCVT; 585 | 586 | int ofsMCCV = 0; 587 | int sizeMCCV = 0; 588 | 589 | if (adt_chunks.ContainsKey((int)chunks.MCCV)) 590 | { 591 | ofsMCCV = pos; 592 | sizeMCCV = root_mcnk.ReadInt(ofsMCCV + 0x4) + 0x8; 593 | pos += sizeMCCV; 594 | } 595 | 596 | // remove MCLV 597 | if (adt_chunks.ContainsKey((int)chunks.MCLV)) 598 | { 599 | root_mcnk.RemoveUnwantedChunksUntil(pos, (int)chunks.MCNR); 600 | } 601 | 602 | int ofsMCNR = pos; 603 | pos += 448 + 0x8; 604 | root_mcnk.WriteInt(ofsMCNR + 0x4, 435); 605 | 606 | int ofsMCLY = 0; 607 | int sizeMCLY = 0; 608 | 609 | int nLayer = 0; 610 | 611 | List mcal_offsets = new List(); 612 | 613 | if (tex_chunks.ContainsKey((int)chunks.MCLY)) 614 | { 615 | tex_mcnk.RemoveUnwantedChunksUntil(0, (int)chunks.MCLY); 616 | ofsMCLY = pos; 617 | int size = tex_mcnk.ReadInt(0x4); 618 | sizeMCLY = size + 0x8; 619 | root_mcnk.AddEmptyBytes(pos, sizeMCLY); 620 | tex_mcnk.BlockCopy(0, root_mcnk, pos, sizeMCLY); 621 | tex_mcnk.RemoveBytes(0, sizeMCLY); 622 | 623 | nLayer = size / 0x10; 624 | 625 | int layer_pos = pos + 0x8; 626 | for (int i = 0; i < nLayer; ++i) 627 | { 628 | uint groundEffect = root_mcnk.ReadUInt(layer_pos + 0xC); 629 | if (groundEffect > 73186) // max wotlk id in GroundEffectTexture 630 | { 631 | root_mcnk.WriteInt(layer_pos + 0xC, 0); 632 | } 633 | root_mcnk.WriteUInt(layer_pos + 0x4, root_mcnk.ReadUInt(layer_pos + 0x4) & 0x7FF); 634 | mcal_offsets.Add(root_mcnk.ReadInt(layer_pos + 0x8)); 635 | 636 | layer_pos += 0x10; 637 | } 638 | 639 | if (nLayer > 4) 640 | { 641 | root_mcnk.RemoveBytes(pos + 0x8 + 64, 16 * (nLayer - 4)); 642 | sizeMCLY = 64 + 0x8; 643 | root_mcnk.WriteInt(pos + 0x4, 64); 644 | nLayer = 4; 645 | } 646 | pos += sizeMCLY; 647 | } 648 | 649 | int ofsMCRF = pos; 650 | int sizeMCRF = 0x8; 651 | 652 | int nDoodads = 0, nMapObjRefs = 0; 653 | 654 | root_mcnk.AddEmptyBytes(pos, 8); 655 | root_mcnk.WriteInt(pos, ChunkedWowFile.MagicToInt("MCRF")); 656 | pos += 0x8; 657 | 658 | if (models) 659 | { 660 | if (obj_chunks.ContainsKey((int)chunks.MCRD)) 661 | { 662 | obj_mcnk.RemoveUnwantedChunksUntil(0, (int)chunks.MCRD); 663 | int sizeMCRD = obj_mcnk.ReadInt(0x4); 664 | root_mcnk.AddEmptyBytes(pos, sizeMCRD); 665 | obj_mcnk.BlockCopy(0x8, root_mcnk, pos, sizeMCRD); 666 | pos += sizeMCRD; 667 | nDoodads = sizeMCRD / 4; 668 | sizeMCRF += sizeMCRD; 669 | obj_mcnk.RemoveBytes(0, 0x8 + sizeMCRD); 670 | } 671 | 672 | if (obj_chunks.ContainsKey((int)chunks.MCRW)) 673 | { 674 | obj_mcnk.RemoveUnwantedChunksUntil(0, (int)chunks.MCRW); 675 | int sizeMCRW = obj_mcnk.ReadInt(0x4); 676 | root_mcnk.AddEmptyBytes(pos, sizeMCRW); 677 | obj_mcnk.BlockCopy(0x8, root_mcnk, pos, sizeMCRW); 678 | pos += sizeMCRW; 679 | nMapObjRefs = sizeMCRW / 4; 680 | sizeMCRF += sizeMCRW; 681 | obj_mcnk.RemoveBytes(0, 0x8 + sizeMCRW); 682 | } 683 | } 684 | 685 | // update MCRF size 686 | root_mcnk.WriteInt(ofsMCRF + 0x4, sizeMCRF - 0x8); 687 | 688 | // MCSH 689 | int ofsMCSH = 0; 690 | int sizeMCSH = 0; 691 | 692 | if (tex_chunks.ContainsKey((int)chunks.MCSH)) 693 | { 694 | ofsMCSH = pos; 695 | tex_mcnk.RemoveUnwantedChunksUntil(0, (int)chunks.MCSH); 696 | sizeMCSH = tex_mcnk.ReadInt(0x4) + 0x8; 697 | root_mcnk.AddEmptyBytes(pos, sizeMCSH); 698 | tex_mcnk.BlockCopy(0, root_mcnk, pos, sizeMCSH); 699 | pos += sizeMCSH; 700 | tex_mcnk.RemoveBytes(0, sizeMCSH); 701 | } 702 | 703 | 704 | // MCAL 705 | int ofsMCAL = 0; 706 | int sizeMCAL = 0; 707 | ofsMCAL = pos; 708 | 709 | if (tex_chunks.ContainsKey((int)chunks.MCAL)) 710 | { 711 | tex_mcnk.RemoveUnwantedChunksUntil(0, (int)chunks.MCAL); 712 | sizeMCAL = tex_mcnk.ReadInt(0x4) + 0x8; 713 | root_mcnk.AddEmptyBytes(pos, sizeMCAL); 714 | tex_mcnk.BlockCopy(0, root_mcnk, pos, sizeMCAL); 715 | tex_mcnk.RemoveBytes(0, sizeMCAL); 716 | 717 | if (mcal_offsets.Count() > 4) 718 | { 719 | int size = sizeMCAL - 0x8; 720 | int target = mcal_offsets[4]; 721 | root_mcnk.RemoveBytes(pos + 0x8 + target, size - target); 722 | sizeMCAL = target + 0x8; 723 | root_mcnk.WriteInt(pos + 0x4, target); 724 | } 725 | 726 | pos += sizeMCAL; 727 | 728 | } 729 | if (sizeMCAL == 0) 730 | { 731 | root_mcnk.AddEmptyBytes(pos, 8); 732 | root_mcnk.WriteInt(pos, (int)chunks.MCAL); 733 | sizeMCAL = 0x8; 734 | pos += 8; 735 | } 736 | 737 | // MCSE 738 | int ofsMCSE = pos; 739 | int sizeMCSE = 0; 740 | int nSoundEmitter = 0; 741 | 742 | if (adt_chunks.ContainsKey((int)chunks.MCSE)) 743 | { 744 | root_mcnk.RemoveUnwantedChunksUntil(pos, (int)chunks.MCSE); 745 | sizeMCSE = root_mcnk.ReadInt(pos + 0x4) + 0x8; 746 | nSoundEmitter = (sizeMCSE - 8) / 0x1C; 747 | pos += sizeMCSE; 748 | } 749 | else 750 | { 751 | ofsMCSE = 0; 752 | } 753 | 754 | adt.AddEmptyBytes(adtPos, root_mcnk.Size() - size_root_mcnk - 8); 755 | root_mcnk.BlockCopy(0, adt.Data, adtPos, root_mcnk.Size()); 756 | 757 | FillMCIN(id, adtPos, root_mcnk.Size()); 758 | 759 | adt.WriteInt(adtPos, ChunkedWowFile.MagicToInt("MCNK")); // should not be necessary 760 | adt.WriteInt(adtPos + 0x4, root_mcnk.Size() - 0x8); 761 | 762 | int ofsPos = adtPos + 0x8; // MCNK header for offsets 763 | 764 | // Update headers 765 | adt.WriteInt(ofsPos + 0x4, (id % 16)); 766 | adt.WriteInt(ofsPos + 0x8, (id / 16)); 767 | // nLayer 768 | adt.WriteInt(ofsPos + 0xC, nLayer); 769 | // nDoodads 770 | adt.WriteInt(ofsPos + 0x10, nDoodads); 771 | adt.WriteInt(ofsPos + 0x14, ofsMCVT); 772 | adt.WriteInt(ofsPos + 0x18, ofsMCNR); 773 | adt.WriteInt(ofsPos + 0x1C, ofsMCLY); 774 | adt.WriteInt(ofsPos + 0x20, ofsMCRF); 775 | adt.WriteInt(ofsPos + 0x24, ofsMCAL); 776 | // sizeAlpha 777 | adt.WriteInt(ofsPos + 0x28, sizeMCAL); 778 | adt.WriteInt(ofsPos + 0x2C, ofsMCSH); 779 | // size shadow 780 | adt.WriteInt(ofsPos + 0x30, sizeMCSH); 781 | // area id 782 | adt.WriteInt(ofsPos + 0x34, 0); 783 | // nMapObjRefs 784 | adt.WriteInt(ofsPos + 0x38, nMapObjRefs); 785 | adt.WriteInt(ofsPos + 0x50, 0); 786 | adt.WriteInt(ofsPos + 0x58, ofsMCSE); 787 | // nSoundEmitter 788 | adt.WriteInt(ofsPos + 0x5C, nSoundEmitter); 789 | adt.WriteInt(ofsPos + 0x60, 0); // MCLQ 790 | adt.WriteInt(ofsPos + 0x64, 0); // size Liquid 791 | adt.WriteInt(ofsPos + 0x74, ofsMCCV); 792 | adt.WriteInt(ofsPos + 0x78, 0); 793 | adt.WriteInt(ofsPos + 0x7C, 0); 794 | 795 | adtPos += root_mcnk.Size(); 796 | } 797 | 798 | private void FillMCIN(int id, int ofs, int size) 799 | { 800 | int pos = 0x5C + 0x10 * id; 801 | adt.WriteInt(pos, ofs); 802 | adt.WriteInt(pos + 0x4, size); 803 | } 804 | 805 | private void CheckMFBO() 806 | { 807 | adt.RemoveUnwantedChunksUntil(adtPos, "MFBO"); 808 | 809 | if (adtPos < adt.Size() - 4 && adt.ReadInt(adtPos) == ChunkedWowFile.MagicToInt("MFBO")) 810 | { 811 | adt.WriteInt(0x38, adtPos - 0x14); 812 | adtPos += adt.ReadInt(adtPos + 0x4) + 0x8; 813 | } 814 | else 815 | { 816 | adt.WriteInt(0x38, 0x0); 817 | } 818 | } 819 | 820 | private void RetrieveMTXF() 821 | { 822 | adt.WriteInt(0x40, adtPos - 0x14); 823 | 824 | int posMTXF = 0, posMTXP = 0; 825 | int i = 0; 826 | for (i = 0; i < tex.Size() - 8; i += tex.ReadInt(i + 4)) 827 | { 828 | if (tex.IsChunk(i, "MTXF")) 829 | { 830 | posMTXF = i; 831 | break; 832 | } 833 | else if (tex.IsChunk(i, "MTXP")) 834 | { 835 | posMTXP = i; 836 | break; 837 | } 838 | } 839 | 840 | if (posMTXF > 0) 841 | { 842 | int size = tex.ReadInt(i + 0x4); 843 | adt.AddEmptyBytes(adtPos, 0x8 + size); 844 | adt.WriteInt(adtPos, ChunkedWowFile.MagicToInt("MTXF")); 845 | adt.WriteInt(adtPos + 0x4, size); 846 | adtPos += 0x8; 847 | 848 | for (int k = posMTXF + 0x8; k < posMTXF + 0x8 + size; k += 0x4) 849 | { 850 | // only flag used in wotlk 851 | adt.WriteInt(adtPos, tex.Data[k] & 0x1); 852 | adtPos += 0x4; 853 | } 854 | } 855 | else if (posMTXP > 0) 856 | { 857 | int size = tex.ReadInt(i + 0x4); 858 | int mtxf_size = size / 4; 859 | 860 | adt.AddEmptyBytes(adtPos, 0x8 + mtxf_size); 861 | adt.WriteInt(adtPos, ChunkedWowFile.MagicToInt("MTXF")); 862 | adt.WriteInt(adtPos + 0x4, mtxf_size); 863 | adtPos += 0x8; 864 | 865 | for (int k = posMTXP + 0x8; k < posMTXP + 0x8 + size; k += 0x10) 866 | { 867 | // only flag used in wotlk 868 | adt.WriteInt(adtPos, tex.Data[k] & 0x1); 869 | adtPos += 0x4; 870 | } 871 | } 872 | else 873 | { 874 | adt.AddEmptyBytes(adtPos, 0x8 + textureCount * 4); 875 | adt.WriteInt(adtPos, ChunkedWowFile.MagicToInt("MTXF")); 876 | adt.WriteInt(adtPos + 0x4, textureCount * 4); 877 | adtPos += 0x8 + textureCount * 4; 878 | } 879 | } 880 | 881 | private uint CalculateChunkSize(IDictionary filenames) 882 | { 883 | var finalSize = 0u; 884 | 885 | foreach (var filename in filenames) 886 | finalSize += (uint)filename.Value.Length; 887 | 888 | return finalSize; 889 | } 890 | 891 | public void Save() 892 | { 893 | adt.Save(); 894 | 895 | // Cleanup 896 | obj.RemoveOnDisk(); 897 | tex.RemoveOnDisk(); 898 | Utils.DeleteFile(file.Replace(".adt", ".tex")); 899 | Utils.DeleteFile(file.Replace(".adt", "_occ.wdt")); 900 | Utils.DeleteFile(file.Replace(".adt", "_lgt.wdt")); 901 | } 902 | } 903 | 904 | public struct MDDF 905 | { 906 | public uint NameId; 907 | public uint UniqueId; 908 | public C3Vector Position; 909 | public C3Vector Rotation; 910 | public ushort Scale; 911 | public ushort Flags; 912 | } 913 | 914 | public struct MODF 915 | { 916 | public uint NameId; 917 | public uint UniqueId; 918 | public C3Vector Position; 919 | public C3Vector Rotation; 920 | public CAaBox Extents; 921 | public ushort Flags; 922 | public ushort DoodadSet; 923 | public ushort NameSet; 924 | public ushort Scale; 925 | } 926 | } 927 | -------------------------------------------------------------------------------- /MultiConverter.Lib/Converters/AnimConverter.cs: -------------------------------------------------------------------------------- 1 | using MultiConverter.Lib.Converters.Base; 2 | 3 | namespace MultiConverter.Lib.Converters 4 | { 5 | public class AnimConverter : ChunkedWowFile 6 | { 7 | public AnimConverter(string file) : base(file) 8 | { 9 | 10 | } 11 | 12 | public bool Fix() 13 | { 14 | if (IsChunk(0, "2MFA")) 15 | { 16 | RemoveBytes(0, 0x8); 17 | return true; 18 | } 19 | 20 | return false; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /MultiConverter.Lib/Converters/Base/ChunkedWowFile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace MultiConverter.Lib.Converters.Base 5 | { 6 | public class ChunkedWowFile : WowFile 7 | { 8 | public ChunkedWowFile(string file) : base(file) 9 | { 10 | } 11 | 12 | public ChunkedWowFile(byte[] buff, int start, int count) : base("") 13 | { 14 | Data = new byte[count]; 15 | Buffer.BlockCopy(buff, start, Data, 0, count); 16 | } 17 | 18 | public bool IsChunk(int pos, string magic) 19 | { 20 | return IsChunk(pos, MagicToInt(magic)); 21 | } 22 | 23 | public bool IsChunk(int pos, int magic) 24 | { 25 | return BitConverter.ToInt32(Data, pos) == magic; 26 | } 27 | 28 | public void WriteHeaderMagic(int pos, string magic) 29 | { 30 | WriteInt(pos, MagicToInt(magic)); 31 | } 32 | 33 | public void WriteHeaderMagic(string magic, ref int pos) 34 | { 35 | WriteInt(MagicToInt(magic), ref pos); 36 | } 37 | 38 | /// 39 | /// Remove all chunks between the starting position and the desired chunk 40 | /// 41 | /// starting pos 42 | /// chunk 43 | public void RemoveUnwantedChunksUntil(int start, string magic) 44 | { 45 | int value = MagicToInt(magic.ToUpper()); 46 | // valid chunk 47 | if (value > 0) 48 | { 49 | RemoveUnwantedChunksUntil(start, value); 50 | } 51 | } 52 | 53 | /// 54 | /// Convert chunk magic to the value when stored in the file 55 | /// 56 | /// chunk magic (ex: MCNK) 57 | /// chunkk magic 58 | public static int MagicToInt(string chunk) 59 | { 60 | if (chunk.Length != 4) 61 | { 62 | return 0; 63 | } 64 | 65 | int magic = 0; 66 | 67 | for (int i = 0; i < 4; ++i) 68 | { 69 | // it's inverted in the file 70 | magic += chunk[3 - i] << (8 * i); 71 | } 72 | 73 | return magic; 74 | } 75 | 76 | public static int InvertedMagicToInt(string chunk) 77 | { 78 | if (chunk.Length != 4) 79 | { 80 | return 0; 81 | } 82 | 83 | int magic = 0; 84 | 85 | for (int i = 0; i < 4; ++i) 86 | { 87 | // it's inverted in the file 88 | magic += chunk[i] << (8 * i); 89 | } 90 | 91 | return magic; 92 | } 93 | 94 | /// 95 | /// Remove all chunks between the starting position and the desired chunk 96 | /// 97 | /// starting pos 98 | /// chunk magic 99 | public void RemoveUnwantedChunksUntil(int start, int magic) 100 | { 101 | if (Data.Length < start + 9) 102 | { 103 | return; 104 | } 105 | 106 | int header = ReadInt(start); 107 | int end = start; 108 | // check to prevent out of bound exception 109 | while (header != magic && Data.Length > end + 8) 110 | { 111 | end += ReadInt(end + 0x4) + 0x8; 112 | 113 | if (Data.Length < end + 4) 114 | { 115 | break; 116 | } 117 | header = ReadInt(end); 118 | } 119 | RemoveBytes(start, end - start); 120 | } 121 | 122 | public Dictionary ChunksOfs(int start, string end_magic) 123 | { 124 | return ChunksOfs(start, MagicToInt(end_magic)); 125 | } 126 | 127 | public Dictionary ChunksOfs(int start, int end_magic) 128 | { 129 | var chunk_pos = new Dictionary(); 130 | 131 | if (start < Data.Length) 132 | { 133 | int pos = start; 134 | int magic = ReadInt(pos); 135 | 136 | if (magic == end_magic) 137 | chunk_pos.Add(magic, pos); 138 | 139 | while (magic != end_magic && pos <= Data.Length - 8) 140 | { 141 | magic = ReadInt(pos); 142 | if (!chunk_pos.ContainsKey(magic)) 143 | chunk_pos.Add(magic, pos); 144 | 145 | int size = ReadInt(pos + 0x4) + 0x8; 146 | pos += size; 147 | } 148 | } 149 | 150 | return chunk_pos; 151 | } 152 | 153 | public bool HasChunk(string chunkMagic) 154 | { 155 | var magic = MagicToInt(chunkMagic); 156 | var chunks = ChunksOfs(0, magic); 157 | 158 | return chunks.ContainsKey(magic); 159 | } 160 | 161 | public int SkipChunk(int pos, string magic) 162 | { 163 | RemoveUnwantedChunksUntil(pos, magic); 164 | // Console.WriteLine($"Magic: {magic} Current Pos: {pos} New Pos: {pos + ReadInt(pos + 0x4) + 0x8}"); 165 | return pos + ReadInt(pos + 0x4) + 0x8; 166 | } 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /MultiConverter.Lib/Converters/Base/IChunk.cs: -------------------------------------------------------------------------------- 1 | namespace MultiConverter.Lib.Converters.Base 2 | { 3 | public interface IChunk 4 | { 5 | /// 6 | /// Chunk Magic 7 | /// 8 | string Signature { get; } 9 | 10 | /// 11 | /// Chunk Length 12 | /// 13 | uint Length { get; } 14 | 15 | /// 16 | /// Order 'id' of the chunk 17 | /// and where to place it. 18 | /// 19 | uint Order { get; } 20 | 21 | /// 22 | /// Read the chunk data. 23 | /// 24 | /// 25 | void Read(byte[] inData); 26 | 27 | /// 28 | /// Write the chunk data. 29 | /// 30 | /// 31 | byte[] Write(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /MultiConverter.Lib/Converters/Base/IConverter.cs: -------------------------------------------------------------------------------- 1 | namespace MultiConverter.Lib.Converters.Base 2 | { 3 | public interface IConverter 4 | { 5 | void Read(byte[] inData); 6 | void Write(string filename); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /MultiConverter.Lib/Converters/Base/WowFile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | 4 | namespace MultiConverter.Lib.Converters.Base 5 | { 6 | public class WowFile 7 | { 8 | public byte[] Data { get; protected set; } 9 | public string Path { get; } 10 | public bool Valid { get; } = false; 11 | 12 | public WowFile(string file) 13 | { 14 | Path = file; 15 | 16 | if (File.Exists(Path)) 17 | { 18 | Valid = true; 19 | Data = File.ReadAllBytes(Path); 20 | } 21 | } 22 | 23 | #region read 24 | public char ReadChar(int pos) 25 | { 26 | return BitConverter.ToChar(Data, pos); 27 | } 28 | public short ReadShort(int pos) 29 | { 30 | return BitConverter.ToInt16(Data, pos); 31 | } 32 | public ushort ReadUShort(int pos) 33 | { 34 | return BitConverter.ToUInt16(Data, pos); 35 | } 36 | public int ReadInt(int pos) 37 | { 38 | return BitConverter.ToInt32(Data, pos); 39 | } 40 | public uint ReadUInt(int pos) 41 | { 42 | return BitConverter.ToUInt32(Data, pos); 43 | } 44 | public ulong ReadULong(int pos) 45 | { 46 | return BitConverter.ToUInt64(Data, pos); 47 | } 48 | public float ReadFloat(int pos) 49 | { 50 | return BitConverter.ToSingle(Data, pos); 51 | } 52 | #endregion 53 | 54 | #region write 55 | public void WriteChar(int pos, char value) 56 | { 57 | Buffer.BlockCopy(BitConverter.GetBytes(value), 0, Data, pos, 1); 58 | } 59 | public void WriteChar(char value, ref int pos) 60 | { 61 | Buffer.BlockCopy(BitConverter.GetBytes(value), 0, Data, pos, 1); 62 | pos += 1; 63 | } 64 | public void WriteShort(int pos, short value) 65 | { 66 | Buffer.BlockCopy(BitConverter.GetBytes(value), 0, Data, pos, 2); 67 | } 68 | public void WriteShort(short value, ref int pos) 69 | { 70 | Buffer.BlockCopy(BitConverter.GetBytes(value), 0, Data, pos, 2); 71 | pos += 2; 72 | } 73 | public void WriteUShort(int pos, ushort value) 74 | { 75 | Buffer.BlockCopy(BitConverter.GetBytes(value), 0, Data, pos, 2); 76 | } 77 | public void WriteUShort(ushort value, ref int pos) 78 | { 79 | Buffer.BlockCopy(BitConverter.GetBytes(value), 0, Data, pos, 2); 80 | pos += 2; 81 | } 82 | public void WriteInt(int pos, int value) 83 | { 84 | Buffer.BlockCopy(BitConverter.GetBytes(value), 0, Data, pos, 4); 85 | } 86 | public void WriteInt(int value, ref int pos) 87 | { 88 | Buffer.BlockCopy(BitConverter.GetBytes(value), 0, Data, pos, 4); 89 | pos += 4; 90 | } 91 | public void WriteUInt(int pos, uint value) 92 | { 93 | Buffer.BlockCopy(BitConverter.GetBytes(value), 0, Data, pos, 4); 94 | } 95 | public void WriteUInt(uint value, ref int pos) 96 | { 97 | Buffer.BlockCopy(BitConverter.GetBytes(value), 0, Data, pos, 4); 98 | pos += 4; 99 | } 100 | public void WriteFloat(int pos, float value) 101 | { 102 | Buffer.BlockCopy(BitConverter.GetBytes(value), 0, Data, pos, 4); 103 | } 104 | public void WriteFloat(float value, ref int pos) 105 | { 106 | Buffer.BlockCopy(BitConverter.GetBytes(value), 0, Data, pos, 4); 107 | pos += 4; 108 | } 109 | public void WriteString(string value, ref int pos) 110 | { 111 | for (var i = 0; i < value.Length; ++i) 112 | WriteChar(pos + i, value[i]); 113 | 114 | pos += value.Length; 115 | } 116 | #endregion 117 | 118 | #region edit 119 | public void RemoveBytes(int start, int count) 120 | { 121 | int size = Data.Length; 122 | 123 | if (size < start + count || count <= 0) 124 | { 125 | // todo: exceptions 126 | return; 127 | } 128 | 129 | byte[] tmp = new byte[size - count]; 130 | if (start > 0) 131 | { 132 | Buffer.BlockCopy(Data, 0, tmp, 0, start); 133 | } 134 | Buffer.BlockCopy(Data, start + count, tmp, start, size - count - start); 135 | Data = tmp; 136 | } 137 | 138 | public void AddEmptyBytes(int start, int count) 139 | { 140 | int size = Data.Length; 141 | byte[] tmp = new byte[size + count]; 142 | Buffer.BlockCopy(Data, 0, tmp, 0, start); 143 | Buffer.BlockCopy(Data, start, tmp, start + count, size - start); 144 | Data = tmp; 145 | } 146 | 147 | public void InsertBytes(int start, byte[] bytes) 148 | { 149 | AddEmptyBytes(start, bytes.Length); 150 | Buffer.BlockCopy(bytes, 0, Data, start, bytes.Length); 151 | } 152 | 153 | public void BlockCopy(int source_ofs, WowFile dest, int dest_ofs, int count) 154 | { 155 | Buffer.BlockCopy(Data, source_ofs, dest.Data, dest_ofs, count); 156 | } 157 | 158 | public void BlockCopy(int source_ofs, Array dest, int dest_ofs, int count) 159 | { 160 | Buffer.BlockCopy(Data, source_ofs, dest, dest_ofs, count); 161 | } 162 | #endregion 163 | 164 | public int Size() => Data.Length; 165 | 166 | public void RemoveOnDisk() 167 | { 168 | if (Valid) 169 | File.Delete(Path); 170 | } 171 | 172 | public virtual void Save() 173 | { 174 | if (Valid) 175 | File.WriteAllBytes(Path, Data); 176 | } 177 | }; 178 | } 179 | -------------------------------------------------------------------------------- /MultiConverter.Lib/Converters/Chunks.cs: -------------------------------------------------------------------------------- 1 | namespace MultiConverter.Lib.Converters 2 | { 3 | public enum WMOChunkId 4 | { 5 | MVER = 0x4d564552, 6 | MOMO = 0x4d4f4d4f, 7 | MOHD = 0x4d4f4844, 8 | MOTX = 0x4d4f5458, 9 | MOMT = 0x4d4f4d54, 10 | MOUV = 0x4d4f5556, 11 | MOGN = 0x4d4f474e, 12 | MOGI = 0x4d4f4749, 13 | MOSB = 0x4d4f5342, 14 | MOPV = 0x4d4f5056, 15 | MOPT = 0x4d4f5054, 16 | MOPR = 0x4d4f5052, 17 | MOVV = 0x4d4f5656, 18 | MOVB = 0x4d4f5642, 19 | MOLT = 0x4d4f4c54, 20 | MODS = 0x4d4f4453, 21 | MODN = 0x4d4f444e, 22 | MODI = 0x4d4f4449, 23 | MODD = 0x4d4f4444, 24 | MFOG = 0x4d464f47, 25 | MCVP = 0x4d435650, 26 | GFID = 0x47464944, 27 | MOGP = 0x4d4f4750, 28 | MOPY = 0x4d4f5059, 29 | MOVI = 0x4d4f5649, 30 | MOVT = 0x4d4f5654, 31 | MONR = 0x4d4f4e52, 32 | MOTV = 0x4d4f5456, 33 | MOLV = 0x4d4f4c56, 34 | MOIN = 0x4d4f494e, 35 | MOBA = 0x4d4f4241, 36 | MOLR = 0x4d4f4c52, 37 | MODR = 0x4d4f4452, 38 | MOBN = 0x4d4f424e, 39 | MOBR = 0x4d4f4252, 40 | MOCV = 0x4d4f4356, 41 | MLIQ = 0x4d4c4951, 42 | MORI = 0x4d4f5249, 43 | MORB = 0x4d4f5242, 44 | MOTA = 0x4d4f5441, 45 | MOBS = 0x4d4f4253, 46 | MDAL = 0x4d44414c, 47 | MOPL = 0x4d4f504c, 48 | MOPB = 0x4d4f5042, 49 | MOLS = 0x4d4f4c53, 50 | MOLP = 0x4d4f4c50, 51 | MOLM = 0x4d4f4c4d, 52 | MOLD = 0x4d4f4c44, 53 | MPBV = 0x4d504256, 54 | MPBP = 0x4d504250, 55 | MPBI = 0x4d504249, 56 | MPBG = 0x4d504247, 57 | MGI2 = 0x4D474932, 58 | MDDI = 0x4D444449, 59 | MNLD = 0x4D4E4C44, 60 | MFED = 0x4D464544, 61 | MVAD = 0x4D415644, 62 | } 63 | 64 | public enum M2ChunkId 65 | { 66 | PFID = 0x44494650, 67 | SFID = 0x44494653, 68 | AFID = 0x44494641, 69 | BFID = 0x44494642, 70 | MD21 = 0x3132444D, 71 | TXAC = 0x43415854, 72 | EXPT = 0x54505845, 73 | EXP2 = 0x32505845, 74 | PABC = 0x43424150, 75 | PADC = 0x43444150, 76 | PSBC = 0x43425350, 77 | PEDC = 0x43444550, 78 | SKID = 0x44494B53, 79 | TXID = 0x44495854, 80 | LDV1 = 0x3156444C, 81 | MD20 = 0x3032444D 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /MultiConverter.Lib/Converters/SkinConverter.cs: -------------------------------------------------------------------------------- 1 | using MultiConverter.Lib.Converters.Base; 2 | using System; 3 | using System.Collections.Generic; 4 | 5 | namespace MultiConverter.Lib.Converters 6 | { 7 | public class SkinConverter : WowFile 8 | { 9 | private HashSet badsubmesh; 10 | 11 | public SkinConverter(string skin) : base(skin) 12 | { 13 | badsubmesh = new HashSet(); 14 | } 15 | 16 | public void Fix(ref List texture_unit_lookup, ref List blendmode_override, int n_transparency_lookup) 17 | { 18 | FixSubmesh(); 19 | FixTexUnit(ref texture_unit_lookup, ref blendmode_override, n_transparency_lookup); 20 | } 21 | 22 | private void FixSubmesh() 23 | { 24 | uint n = ReadUInt(0x1C); 25 | uint ofs = ReadUInt(0x20); 26 | 27 | for (uint i = 0; i < n; i++) 28 | { 29 | int pos = (int)(ofs + i * 0x30); 30 | 31 | if (ReadUShort(pos + 0x2) > 0) 32 | { 33 | for (int k = pos + 0x2; k < pos + 0x14; ++k) 34 | { 35 | Data[k] = 0; 36 | } 37 | badsubmesh.Add(i); 38 | } 39 | else if (Data[pos + 0x10] == 0) 40 | { 41 | Data[pos + 0x10] = 1; 42 | } 43 | Data[pos + 0x11] = 0; 44 | } 45 | } 46 | 47 | private void DuplicateTextureUnit(int start) 48 | { 49 | AddEmptyBytes(start + 0x18, 0x18); 50 | Buffer.BlockCopy(Data, start, Data, start + 0x18, 0x18); 51 | } 52 | 53 | private void FixTexUnit(ref List texture_unit_lookup, ref List blendmode_override, int n_transparency_lookup) 54 | { 55 | uint nTexUnit = ReadUInt(0x24); 56 | uint ofsTextUnit = ReadUInt(0x28); 57 | 58 | for (int i = (int)ofsTextUnit; i < ofsTextUnit + nTexUnit * 0x18; i += 0x18) 59 | { 60 | ushort shader_id = ReadUShort(i + 0x2), shader_to_save = 0; 61 | byte flags = Data[i]; 62 | 63 | ushort submesh = ReadUShort((int)i + 0x4); 64 | 65 | if (badsubmesh.Contains(submesh)) 66 | { 67 | WriteUInt((int)i + 0x2, 0x8000); 68 | continue; 69 | } 70 | 71 | ushort texture_count = ReadUShort(i + 0xE); 72 | Data[i] &= 0x10; 73 | 74 | bool skip_next_tu = false; 75 | 76 | if (shader_id >= 0x8000) 77 | { 78 | ushort low = (ushort)(shader_id & 0xFF); 79 | 80 | switch (low) 81 | { 82 | case 0: 83 | case 3: 84 | case 9: 85 | case 17: 86 | case 24: 87 | { 88 | skip_next_tu = true; 89 | texture_count = 2; 90 | DuplicateTextureUnit(i); 91 | nTexUnit++; 92 | 93 | Data[i + 0xE + 0x18] = 1; // next tu has 1 tex 94 | 95 | // use next renderflags 96 | WriteUShort(i + 0x18 + 0xA, (ushort)(ReadUShort(i + 0xA) + 1)); 97 | // material layer 98 | WriteShort(i + 0x18 + 0xC, 1); 99 | 100 | ushort blend_1 = 1; 101 | ushort blend_2 = 4; 102 | short[] tu_lookup = { 0, -1 }; 103 | 104 | bool added = false; 105 | 106 | for (ushort n = 0; n < blendmode_override.Count; n += 2) 107 | { 108 | if (blendmode_override[n] == blend_1 && blendmode_override[n + 1] == blend_2) 109 | { 110 | shader_to_save = n; 111 | added = true; 112 | break; 113 | } 114 | } 115 | 116 | if (!added) 117 | { 118 | shader_to_save = (ushort)blendmode_override.Count; 119 | blendmode_override.Add(blend_1); 120 | blendmode_override.Add(blend_2); 121 | } 122 | 123 | added = false; 124 | ushort tex_coord_to_save = 0; 125 | for (ushort n = 0; n < texture_unit_lookup.Count - 1; ++n) 126 | { 127 | if (texture_unit_lookup[n] == tu_lookup[0] && texture_unit_lookup[n + 1] == tu_lookup[1]) 128 | { 129 | tex_coord_to_save = n; 130 | added = true; 131 | break; 132 | } 133 | } 134 | 135 | if (!added) 136 | { 137 | int tul_size = texture_unit_lookup.Count; 138 | if (tul_size > 1 && texture_unit_lookup[tul_size - 1] == tu_lookup[0]) 139 | { 140 | tex_coord_to_save = (ushort)(tul_size - 1); 141 | texture_unit_lookup.Add(tu_lookup[1]); 142 | } 143 | else 144 | { 145 | tex_coord_to_save = (ushort)(tul_size); 146 | texture_unit_lookup.Add(tu_lookup[0]); 147 | texture_unit_lookup.Add(tu_lookup[1]); 148 | } 149 | } 150 | 151 | // texture coord combo 152 | WriteUShort(i + 0x12, tex_coord_to_save); 153 | WriteUShort(i + 0x18 + 0x12, tex_coord_to_save); 154 | 155 | WriteUShort(i + 0x2, shader_to_save); 156 | WriteUShort(i + 0x2 + 0x18, shader_to_save); 157 | } 158 | break; 159 | case 1: 160 | case 15: 161 | { 162 | skip_next_tu = true; 163 | texture_count = 1; 164 | DuplicateTextureUnit(i); 165 | nTexUnit++; 166 | 167 | Data[i + 0xE] = 1; // this tu has 1 tex 168 | Data[i + 0xE + 0x18] = 1; // next tu has 1 tex 169 | 170 | // use next renderflags 171 | WriteUShort(i + 0x18 + 0xA, (ushort)(ReadUShort(i + 0xA) + 1)); 172 | // material layer 173 | WriteShort(i + 0x18 + 0xC, 1); 174 | // texture combo 175 | WriteUShort(i + 0x18 + 0x10, (ushort)(ReadUShort(i + 0x10) + 1)); 176 | // transparency combo 177 | ushort transparency_combo = (ushort)(ReadUShort(i + 0x14)); 178 | if (transparency_combo + 1 < n_transparency_lookup) 179 | { 180 | transparency_combo++; 181 | } 182 | 183 | WriteUShort(i + 0x18 + 0x14, transparency_combo); 184 | 185 | short[] tu_lookup = { 0, (short)(shader_id == 0x8001 ? -1 : 1) }; 186 | 187 | // no blend override 188 | WriteUShort(i + 0x2, 0); 189 | WriteUShort(i + 0x2 + 0x18, 0); 190 | 191 | 192 | bool added = false; 193 | ushort tex_coord_to_save = 0; 194 | for (ushort n = 0; n < texture_unit_lookup.Count - 1; ++n) 195 | { 196 | if (texture_unit_lookup[n] == tu_lookup[0] && texture_unit_lookup[n + 1] == tu_lookup[1]) 197 | { 198 | tex_coord_to_save = n; 199 | added = true; 200 | break; 201 | } 202 | } 203 | 204 | if (!added) 205 | { 206 | int tul_size = texture_unit_lookup.Count; 207 | if (tul_size > 1 && texture_unit_lookup[tul_size - 1] == tu_lookup[0]) 208 | { 209 | tex_coord_to_save = (ushort)(tul_size - 1); 210 | texture_unit_lookup.Add(tu_lookup[1]); 211 | } 212 | else 213 | { 214 | tex_coord_to_save = (ushort)(tul_size); 215 | texture_unit_lookup.Add(tu_lookup[0]); 216 | texture_unit_lookup.Add(tu_lookup[1]); 217 | } 218 | } 219 | 220 | // texture coord combo 221 | WriteUShort(i + 0x12, tex_coord_to_save); 222 | tex_coord_to_save++; 223 | WriteUShort(i + 0x18 + 0x12, tex_coord_to_save); 224 | } 225 | break; 226 | case 2: 227 | { 228 | skip_next_tu = true; 229 | DuplicateTextureUnit(i); 230 | nTexUnit++; 231 | 232 | Data[i + 0xE + 0x18] = 1; // next tu has 1 tex 233 | 234 | // use next renderflags 235 | WriteUShort(i + 0x18 + 0xA, (ushort)(ReadUShort(i + 0xA) + 1)); 236 | // material layer 237 | WriteShort(i + 0x18 + 0xC, 1); 238 | 239 | ushort blend_1 = 1; 240 | ushort blend_2 = 3; 241 | short[] tu_lookup = { 0, -1 }; 242 | 243 | bool added = false; 244 | 245 | for (ushort n = 0; n < blendmode_override.Count; n += 2) 246 | { 247 | if (blendmode_override[n] == blend_1 && blendmode_override[n + 1] == blend_2) 248 | { 249 | shader_to_save = n; 250 | added = true; 251 | break; 252 | } 253 | } 254 | 255 | if (!added) 256 | { 257 | shader_to_save = (ushort)blendmode_override.Count; 258 | blendmode_override.Add(blend_1); 259 | blendmode_override.Add(blend_2); 260 | } 261 | 262 | WriteUShort(i + 0x2, shader_to_save); 263 | WriteUShort(i + 0x2 + 0x18, shader_to_save); 264 | 265 | added = false; 266 | ushort tex_coord_to_save = 0; 267 | for (ushort n = 0; n < texture_unit_lookup.Count - 1; ++n) 268 | { 269 | if (texture_unit_lookup[n] == tu_lookup[0] && texture_unit_lookup[n + 1] == tu_lookup[1]) 270 | { 271 | tex_coord_to_save = n; 272 | added = true; 273 | break; 274 | } 275 | } 276 | 277 | if (!added) 278 | { 279 | int tul_size = texture_unit_lookup.Count; 280 | if (tul_size > 1 && texture_unit_lookup[tul_size - 1] == tu_lookup[0]) 281 | { 282 | tex_coord_to_save = (ushort)(tul_size - 1); 283 | texture_unit_lookup.Add(tu_lookup[1]); 284 | } 285 | else 286 | { 287 | tex_coord_to_save = (ushort)(tul_size); 288 | texture_unit_lookup.Add(tu_lookup[0]); 289 | texture_unit_lookup.Add(tu_lookup[1]); 290 | } 291 | } 292 | 293 | // texture coord combo 294 | WriteUShort(i + 0x12, tex_coord_to_save); 295 | WriteUShort(i + 0x18 + 0x12, tex_coord_to_save); 296 | } 297 | break; 298 | case 5: 299 | case 8: 300 | case 10: 301 | case 12: 302 | case 16: 303 | case 23: 304 | shader_id = 0; 305 | texture_count = 1; 306 | break; 307 | // Combiners_Mod_Mod 308 | case 21: 309 | shader_id = 0x4011; 310 | texture_count = 2; 311 | break; 312 | // default: Combiners_Mod 313 | default: 314 | shader_id = 0x0010; 315 | texture_count = 1; 316 | break; 317 | } 318 | } 319 | 320 | if (shader_id < 0x8000) 321 | { 322 | ushort blend_1 = (ushort)((shader_id >> 4) & 0x7); 323 | ushort blend_2 = (ushort)(shader_id & 0x7); 324 | 325 | // T2 326 | if (texture_count > 1 && (shader_id & 0x4000) != 0 && blend_1 != 0 && blend_2 != 0) 327 | { 328 | bool added = false; 329 | 330 | for (ushort n = 0; n < blendmode_override.Count; n += 2) 331 | { 332 | if (blendmode_override[n] == blend_1 && blendmode_override[n + 1] == blend_2) 333 | { 334 | shader_to_save = n; 335 | added = true; 336 | break; 337 | } 338 | } 339 | 340 | if (!added) 341 | { 342 | shader_to_save = (ushort)blendmode_override.Count; 343 | blendmode_override.Add(blend_1); 344 | blendmode_override.Add(blend_2); 345 | } 346 | } 347 | else 348 | { 349 | texture_count = 1; 350 | } 351 | 352 | Data[i] &= 0x10; 353 | WriteUShort(i + 0x2, shader_to_save); 354 | 355 | // generate texture unit lookup 356 | short[] tu_lookup = new short[2]; 357 | 358 | if (texture_count == 1) 359 | { 360 | if ((shader_id & 0x80) != 0) 361 | { 362 | tu_lookup[0] = -1; 363 | } 364 | else 365 | { 366 | tu_lookup[0] = 0; 367 | } 368 | 369 | if (texture_unit_lookup.Contains(tu_lookup[0])) 370 | { 371 | WriteUShort(i + 0x12, (ushort)texture_unit_lookup.IndexOf(tu_lookup[0])); 372 | } 373 | else 374 | { 375 | WriteUShort(i + 0x12, (ushort)texture_unit_lookup.Count); 376 | texture_unit_lookup.Add(tu_lookup[0]); 377 | } 378 | } 379 | else 380 | { 381 | if ((shader_id & 0x80) != 0) 382 | { 383 | tu_lookup[0] = -1; 384 | // check if wotlk need to use Env_T2 rather than Env_T1 385 | tu_lookup[1] = (short)(((shader_id & 0x8) != 0) ? -1 : 0); 386 | } 387 | else 388 | { 389 | tu_lookup[0] = 0; 390 | tu_lookup[1] = (short)(((shader_id & 0x8) != 0) ? -1 : (((shader_id & 0x4000) != 0) ? 1 : 0)); 391 | } 392 | 393 | bool added = false; 394 | for (ushort n = 0; n < texture_unit_lookup.Count - 1; ++n) 395 | { 396 | if (texture_unit_lookup[n] == tu_lookup[0] && texture_unit_lookup[n + 1] == tu_lookup[1]) 397 | { 398 | WriteUShort(i + 0x12, n); 399 | added = true; 400 | break; 401 | } 402 | } 403 | 404 | if (!added) 405 | { 406 | int tul_size = texture_unit_lookup.Count; 407 | if (tul_size > 1 && texture_unit_lookup[tul_size - 1] == tu_lookup[0]) 408 | { 409 | WriteUShort(i + 0x12, (ushort)(tul_size - 1)); 410 | texture_unit_lookup.Add(tu_lookup[1]); 411 | } 412 | else 413 | { 414 | WriteUShort(i + 0x12, (ushort)tul_size); 415 | texture_unit_lookup.Add(tu_lookup[0]); 416 | texture_unit_lookup.Add(tu_lookup[1]); 417 | } 418 | } 419 | } 420 | } 421 | 422 | WriteUShort(i + 0xE, Math.Min(texture_count, (ushort)2)); 423 | 424 | if (skip_next_tu) 425 | { 426 | i += 0x18; 427 | } 428 | } 429 | 430 | WriteUInt(0x24, nTexUnit); 431 | } 432 | } 433 | } 434 | -------------------------------------------------------------------------------- /MultiConverter.Lib/Converters/WDTConverter.cs: -------------------------------------------------------------------------------- 1 | using MultiConverter.Lib.Converters.Base; 2 | 3 | namespace MultiConverter.Lib.Converters 4 | { 5 | public class WDTConverter : ChunkedWowFile 6 | { 7 | public WDTConverter(string file) : base(file) 8 | { 9 | } 10 | 11 | public bool Fix() 12 | { 13 | int flags = ReadInt(0x14); 14 | if ((flags & 0x80) != 0) 15 | { 16 | flags |= 0x4; 17 | } 18 | Data[0x14] = (byte)(flags & 0x1f); 19 | 20 | for (int i = 0x3C; i < 0x3C + 32768; i += 0x8) 21 | { 22 | Data[i] &= 0x1; 23 | } 24 | 25 | return true; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /MultiConverter.Lib/Converters/WMO/Chunks/MFOG.cs: -------------------------------------------------------------------------------- 1 | using MultiConverter.Lib.Converters.Base; 2 | using MultiConverter.Lib.Converters.WMO.Entries; 3 | using MultiConverter.Lib.Util; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.IO; 7 | using System.Text; 8 | 9 | namespace MultiConverter.Lib.Converters.WMO.Chunks 10 | { 11 | public class MFOG : IChunk 12 | { 13 | public string Signature => "MFOG"; 14 | public uint Length => (uint)Write().Length; 15 | public uint Order => 16; 16 | 17 | /// 18 | /// List of 19 | /// 20 | public List MFOGs = new List(); 21 | 22 | public void Read(byte[] inData) 23 | { 24 | using (var stream = new MemoryStream(inData)) 25 | using (var reader = new BinaryReader(stream)) 26 | { 27 | var mfogSize = inData.Length / 48; 28 | for (var i = 0; i < mfogSize; ++i) 29 | { 30 | MFOGs.Add(new MFOGEntry 31 | { 32 | Flags = reader.ReadUInt32(), 33 | Position = reader.ReadC3Vector(), 34 | SmallRadius = reader.ReadSingle(), 35 | LargeRadius = reader.ReadSingle(), 36 | FogEnd = reader.ReadSingle(), 37 | FogStartMultiplier = reader.ReadSingle(), 38 | FogColor = reader.ReadCArgb(), 39 | Unk1 = reader.ReadSingle(), 40 | Unk2 = reader.ReadSingle(), 41 | FogColor2 = reader.ReadCArgb() 42 | }); 43 | } 44 | } 45 | } 46 | 47 | public byte[] Write() 48 | { 49 | using (var stream = new MemoryStream()) 50 | using (var writer = new BinaryWriter(stream)) 51 | { 52 | foreach (var mfog in MFOGs) 53 | { 54 | writer.Write(mfog.Flags); 55 | writer.WriteC3Vector(mfog.Position); 56 | writer.Write(mfog.SmallRadius); 57 | writer.Write(mfog.LargeRadius); 58 | writer.Write(mfog.FogEnd); 59 | writer.Write(mfog.FogStartMultiplier); 60 | writer.WriteCArgb(mfog.FogColor); 61 | writer.Write(mfog.Unk1); 62 | writer.Write(mfog.Unk2); 63 | writer.WriteCArgb(mfog.FogColor2); 64 | } 65 | 66 | return stream.ToArray(); 67 | } 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /MultiConverter.Lib/Converters/WMO/Chunks/MODD.cs: -------------------------------------------------------------------------------- 1 | using MultiConverter.Lib.Converters.Base; 2 | using MultiConverter.Lib.Converters.WMO.Entries; 3 | using MultiConverter.Lib.Util; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.IO; 7 | using System.Linq; 8 | using System.Text; 9 | 10 | namespace MultiConverter.Lib.Converters.WMO.Chunks 11 | { 12 | public class MODD : IChunk 13 | { 14 | public string Signature => "MODD"; 15 | public uint Length => (uint)Write().Length; 16 | public uint Order => 15; 17 | 18 | /// 19 | /// List of 20 | /// 21 | public List MODDs = new List(); 22 | 23 | /// 24 | /// List of all filenames 25 | /// 26 | public Dictionary Filenames = new Dictionary(); 27 | 28 | private uint doodadOffset = 0; 29 | 30 | public void Read(byte[] inData) 31 | { 32 | using (var stream = new MemoryStream(inData)) 33 | using (var reader = new BinaryReader(stream)) 34 | { 35 | var moddSize = inData.Length / 40; 36 | for (var i = 0; i < moddSize; ++i) 37 | { 38 | var finalNameBytes = new byte[4]; 39 | var nameOffsetBytes = reader.ReadBytes(3); 40 | Buffer.BlockCopy(nameOffsetBytes, 0, finalNameBytes, 0, 3); 41 | 42 | var modd = new MODDEntry 43 | { 44 | NameIndex = BitConverter.ToInt32(finalNameBytes, 0), 45 | Flags = reader.ReadByte(), 46 | Position = reader.ReadC3Vector(), 47 | Rotation = reader.ReadC3Vector(), 48 | RotationW = reader.ReadSingle(), 49 | Scale = reader.ReadSingle(), 50 | Color = reader.ReadCArgb() 51 | }; 52 | 53 | var filename = AddFilename(MODI.DoodadFileIds[modd.NameIndex]); 54 | if (filename != string.Empty) 55 | { 56 | var idx = Filenames[filename]; 57 | nameOffsetBytes = BitConverter.GetBytes(idx); 58 | 59 | Buffer.BlockCopy(nameOffsetBytes, 0, finalNameBytes, 0, 3); 60 | modd.NameIndex = BitConverter.ToInt32(finalNameBytes, 0); 61 | } 62 | else 63 | modd.NameIndex = -1; 64 | 65 | MODDs.Add(modd); 66 | } 67 | } 68 | } 69 | 70 | public byte[] Write() 71 | { 72 | using (var stream = new MemoryStream()) 73 | using (var writer = new BinaryWriter(stream)) 74 | { 75 | // Disable doodads. 76 | if (!WMOFile.DisableDoodads) 77 | { 78 | foreach (var modd in MODDs) 79 | { 80 | var nameOffsetBytes = BitConverter.GetBytes(modd.NameIndex); 81 | var finalNameOffsetBytes = new byte[3]; 82 | Buffer.BlockCopy(nameOffsetBytes, 0, finalNameOffsetBytes, 0, 3); 83 | 84 | writer.Write(finalNameOffsetBytes); 85 | writer.Write(modd.Flags); 86 | writer.WriteC3Vector(modd.Position); 87 | writer.WriteC3Vector(modd.Rotation); 88 | writer.Write(modd.RotationW); 89 | writer.Write(modd.Scale); 90 | writer.WriteCArgb(modd.Color); 91 | } 92 | } 93 | 94 | return stream.ToArray(); 95 | } 96 | } 97 | 98 | private string AddFilename(uint fdid) 99 | { 100 | if (fdid != 0) 101 | { 102 | var textureFilename = Listfile.LookupFilename(fdid, ".wmo").Replace('/', '\\') + "\0"; 103 | 104 | if (!Filenames.ContainsKey(textureFilename)) 105 | { 106 | Filenames.Add(textureFilename, doodadOffset); 107 | doodadOffset += (uint)textureFilename.Length; 108 | } 109 | 110 | return textureFilename; 111 | } 112 | 113 | return string.Empty; 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /MultiConverter.Lib/Converters/WMO/Chunks/MODI.cs: -------------------------------------------------------------------------------- 1 | using MultiConverter.Lib.Converters.Base; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | 6 | namespace MultiConverter.Lib.Converters.WMO.Chunks 7 | { 8 | public class MODI : IChunk 9 | { 10 | public string Signature => "MODI"; 11 | public uint Length => 0; 12 | public uint Order => 0; 13 | 14 | public static uint[] DoodadFileIds; 15 | public static Dictionary DoodadNames = new Dictionary(); 16 | 17 | public void Read(byte[] inData) 18 | { 19 | using (var stream = new MemoryStream(inData)) 20 | using (var reader = new BinaryReader(stream)) 21 | { 22 | var modiSize = inData.Length / 4; 23 | DoodadFileIds = new uint[modiSize]; 24 | 25 | for (var i = 0; i < modiSize; ++i) 26 | { 27 | var filedataId = reader.ReadUInt32(); 28 | var filename = Listfile.LookupFilename(filedataId, ".wmo", "m2").Replace("m2", "mdx").Replace("/", "\\") + "\0"; 29 | 30 | if (!DoodadNames.ContainsKey(filedataId)) 31 | DoodadNames.Add(filedataId, filename); 32 | 33 | DoodadFileIds[i] = filedataId; 34 | } 35 | } 36 | 37 | if (WMOFile.DisableDoodads) 38 | WMOFile.Chunks.Add(new MODN()); 39 | else 40 | WMOFile.Chunks.Add(new MODN { DoodadFilenames = DoodadNames.Values.ToList() }); 41 | } 42 | 43 | public byte[] Write() => new byte[0]; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /MultiConverter.Lib/Converters/WMO/Chunks/MODN.cs: -------------------------------------------------------------------------------- 1 | using MultiConverter.Lib.Converters.Base; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | 5 | namespace MultiConverter.Lib.Converters.WMO.Chunks 6 | { 7 | public class MODN : IChunk 8 | { 9 | public string Signature => "MODN"; 10 | public uint Length => (uint)Write().Length; 11 | public uint Order => 14; 12 | 13 | /// 14 | /// List of DoodadFilenames. 15 | /// 16 | public List DoodadFilenames = new List(); 17 | 18 | public void Read(byte[] inData) { } 19 | 20 | public byte[] Write() 21 | { 22 | using (var stream = new MemoryStream()) 23 | using (var writer = new BinaryWriter(stream)) 24 | { 25 | // O(n^2), really don't care at this point. 26 | foreach (var filename in DoodadFilenames) 27 | foreach (var fileChar in filename) 28 | writer.Write(fileChar); 29 | 30 | return stream.ToArray(); 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /MultiConverter.Lib/Converters/WMO/Chunks/MODS.cs: -------------------------------------------------------------------------------- 1 | using MultiConverter.Lib.Converters.Base; 2 | using MultiConverter.Lib.Converters.WMO.Entries; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Text; 7 | 8 | namespace MultiConverter.Lib.Converters.WMO.Chunks 9 | { 10 | public class MODS : IChunk 11 | { 12 | public string Signature => "MODS"; 13 | public uint Length => (uint)Write().Length; 14 | public uint Order => 13; 15 | 16 | /// 17 | /// List of 18 | /// 19 | public List MODSs = new List(); 20 | 21 | public void Read(byte[] inData) 22 | { 23 | using (var stream = new MemoryStream(inData)) 24 | using (var reader = new BinaryReader(stream)) 25 | { 26 | var modsSize = inData.Length / 32; 27 | for (var i = 0; i < modsSize; ++i) 28 | { 29 | var mods = new MODSEntry 30 | { 31 | SetName = new string(reader.ReadChars(20)), 32 | FirstDoodadInSet = reader.ReadUInt32(), 33 | DoodadInSetCount = reader.ReadUInt32(), 34 | Padding = reader.ReadUInt32() 35 | }; 36 | 37 | if (WMOFile.DisableDoodads) 38 | mods.DoodadInSetCount = 0; 39 | 40 | MODSs.Add(mods); 41 | } 42 | } 43 | } 44 | 45 | public byte[] Write() 46 | { 47 | using (var stream = new MemoryStream()) 48 | using (var writer = new BinaryWriter(stream)) 49 | { 50 | foreach (var mods in MODSs) 51 | { 52 | for (var i = 0; i < 20; ++i) 53 | writer.Write(mods.SetName[i]); 54 | 55 | writer.Write(mods.FirstDoodadInSet); 56 | writer.Write(mods.DoodadInSetCount); 57 | writer.Write(mods.Padding); 58 | } 59 | 60 | return stream.ToArray(); 61 | } 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /MultiConverter.Lib/Converters/WMO/Chunks/MOGI.cs: -------------------------------------------------------------------------------- 1 | using MultiConverter.Lib.Converters.Base; 2 | using MultiConverter.Lib.Converters.WMO.Entries; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | 6 | namespace MultiConverter.Lib.Converters.WMO.Chunks 7 | { 8 | public class MOGI : IChunk 9 | { 10 | public string Signature => "MOGI"; 11 | public uint Length => (uint)Write().Length; 12 | public uint Order => 5; 13 | 14 | /// 15 | /// List of 16 | /// 17 | public List MOGIs = new List(); 18 | 19 | public void Read(byte[] inData) 20 | { 21 | using (var stream = new MemoryStream(inData)) 22 | using (var reader = new BinaryReader(stream)) 23 | { 24 | var mogiSize = inData.Length / 32; 25 | for (var i = 0; i < mogiSize; ++i) 26 | { 27 | var mogi = new MOGIEntry(); 28 | mogi.Flags = reader.ReadUInt32(); 29 | mogi.Flags &= 0x7FFFFF7F; 30 | 31 | for (var j = 0; j < 3; ++j) 32 | mogi.BBoxCorner1[j] = reader.ReadSingle(); 33 | 34 | for (var j = 0; j < 3; ++j) 35 | mogi.BBoxCorner2[j] = reader.ReadSingle(); 36 | 37 | mogi.NameOffset = reader.ReadInt32(); 38 | 39 | MOGIs.Add(mogi); 40 | } 41 | } 42 | } 43 | 44 | public byte[] Write() 45 | { 46 | using (var stream = new MemoryStream()) 47 | using (var writer = new BinaryWriter(stream)) 48 | { 49 | foreach (var mogi in MOGIs) 50 | { 51 | writer.Write(mogi.Flags); 52 | 53 | for (var i = 0; i < 3; ++i) 54 | writer.Write(mogi.BBoxCorner1[i]); 55 | 56 | for (var i = 0; i < 3; ++i) 57 | writer.Write(mogi.BBoxCorner2[i]); 58 | 59 | writer.Write(mogi.NameOffset); 60 | } 61 | 62 | return stream.ToArray(); 63 | } 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /MultiConverter.Lib/Converters/WMO/Chunks/MOGN.cs: -------------------------------------------------------------------------------- 1 | using MultiConverter.Lib.Converters.Base; 2 | using System.IO; 3 | 4 | namespace MultiConverter.Lib.Converters.WMO.Chunks 5 | { 6 | public class MOGN : IChunk 7 | { 8 | public string Signature => "MOGN"; 9 | public uint Length => (uint)Write().Length; 10 | public uint Order => 4; 11 | 12 | /// 13 | /// Group Names 14 | /// 15 | public byte[] GroupNames { get; set; } 16 | 17 | public void Read(byte[] inData) 18 | { 19 | using (var stream = new MemoryStream(inData)) 20 | using (var reader = new BinaryReader(stream)) 21 | { 22 | GroupNames = reader.ReadBytes(inData.Length); 23 | } 24 | } 25 | 26 | public byte[] Write() 27 | { 28 | using (var stream = new MemoryStream()) 29 | using (var writer = new BinaryWriter(stream)) 30 | { 31 | writer.Write(GroupNames, 0, GroupNames.Length); 32 | 33 | return stream.ToArray(); 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /MultiConverter.Lib/Converters/WMO/Chunks/MOHD.cs: -------------------------------------------------------------------------------- 1 | using MultiConverter.Lib.Converters.Base; 2 | using MultiConverter.Lib.Converters.WMO.Entries; 3 | using MultiConverter.Lib.Util; 4 | using System.IO; 5 | 6 | namespace MultiConverter.Lib.Converters.WMO.Chunks 7 | { 8 | public class MOHD : IChunk 9 | { 10 | public string Signature => "MOHD"; 11 | public uint Length => (uint)Write().Length; 12 | public uint Order => 1; 13 | 14 | public MOHDEntry MOHDEntry { get; set; } = new MOHDEntry(); 15 | 16 | public void Read(byte[] inData) 17 | { 18 | using (var stream = new MemoryStream(inData)) 19 | using (var reader = new BinaryReader(stream)) 20 | { 21 | MOHDEntry.MaterialCount = reader.ReadUInt32(); 22 | MOHDEntry.GroupCount = reader.ReadUInt32(); 23 | MOHDEntry.PortalCount = reader.ReadUInt32(); 24 | MOHDEntry.LightCount = reader.ReadUInt32(); 25 | MOHDEntry.ModelCount = reader.ReadUInt32(); 26 | MOHDEntry.DoodadCount = reader.ReadUInt32(); 27 | MOHDEntry.SetCount = reader.ReadUInt32(); 28 | 29 | MOHDEntry.Color = reader.ReadCArgb(); 30 | MOHDEntry.WMOId = reader.ReadUInt32(); 31 | 32 | for (var i = 0; i < 3; ++i) 33 | MOHDEntry.BBoxCorner1[i] = reader.ReadSingle(); 34 | 35 | for (var i = 0; i < 3; ++i) 36 | MOHDEntry.BBoxCorner2[i] = reader.ReadSingle(); 37 | 38 | MOHDEntry.FlagLod = reader.ReadUInt16(); 39 | MOHDEntry.LodCount = reader.ReadUInt16(); 40 | 41 | if (WMOFile.DisableDoodads) 42 | { 43 | MOHDEntry.DoodadCount = 0; 44 | MOHDEntry.ModelCount = 0; 45 | } 46 | } 47 | } 48 | 49 | public byte[] Write() 50 | { 51 | using (var stream = new MemoryStream()) 52 | using (var writer = new BinaryWriter(stream)) 53 | { 54 | writer.Write(MOHDEntry.MaterialCount); 55 | writer.Write(MOHDEntry.GroupCount); 56 | writer.Write(MOHDEntry.PortalCount); 57 | writer.Write(MOHDEntry.LightCount); 58 | writer.Write(MOHDEntry.ModelCount); 59 | writer.Write(MOHDEntry.DoodadCount); 60 | writer.Write(MOHDEntry.SetCount); 61 | 62 | writer.WriteCArgb(MOHDEntry.Color); 63 | writer.Write(MOHDEntry.WMOId); 64 | 65 | for (var i = 0; i < 3; ++i) 66 | writer.Write(MOHDEntry.BBoxCorner1[i]); 67 | 68 | for (var i = 0; i < 3; ++i) 69 | writer.Write(MOHDEntry.BBoxCorner2[i]); 70 | 71 | writer.Write(MOHDEntry.FlagLod); 72 | writer.Write(MOHDEntry.LodCount); 73 | 74 | return stream.ToArray(); 75 | } 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /MultiConverter.Lib/Converters/WMO/Chunks/MOLT.cs: -------------------------------------------------------------------------------- 1 | using MultiConverter.Lib.Converters.Base; 2 | using MultiConverter.Lib.Converters.WMO.Entries; 3 | using MultiConverter.Lib.Util; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.IO; 7 | using System.Text; 8 | 9 | namespace MultiConverter.Lib.Converters.WMO.Chunks 10 | { 11 | public class MOLT : IChunk 12 | { 13 | public string Signature => "MOLT"; 14 | public uint Length => (uint)Write().Length; 15 | public uint Order => 12; 16 | 17 | /// 18 | /// List of . 19 | /// 20 | public List MOLTs = new List(); 21 | 22 | public void Read(byte[] inData) 23 | { 24 | using (var stream = new MemoryStream(inData)) 25 | using (var reader = new BinaryReader(stream)) 26 | { 27 | var moltSize = inData.Length / 48; 28 | for (var i = 0; i < moltSize; ++i) 29 | { 30 | var molt = new MOLTEntry(); 31 | molt.Type = reader.ReadByte(); 32 | 33 | for (var j = 0; j < 3; ++j) 34 | molt.Flags[j] = reader.ReadByte(); 35 | 36 | molt.Color = reader.ReadCArgb(); 37 | molt.Position = reader.ReadC3Vector(); 38 | molt.Intensity = reader.ReadSingle(); 39 | 40 | for (var j = 0; j < 4; ++j) 41 | molt.UnkShit[j] = reader.ReadSingle(); 42 | 43 | molt.AttenStart = reader.ReadSingle(); 44 | molt.AttenEnd = reader.ReadSingle(); 45 | } 46 | } 47 | } 48 | 49 | public byte[] Write() 50 | { 51 | using (var stream = new MemoryStream()) 52 | using (var writer = new BinaryWriter(stream)) 53 | { 54 | foreach (var molt in MOLTs) 55 | { 56 | writer.Write(molt.Type); 57 | writer.Write(molt.Flags); 58 | writer.WriteCArgb(molt.Color); 59 | writer.WriteC3Vector(molt.Position); 60 | writer.Write(molt.Intensity); 61 | 62 | for (var j = 0; j < 4; ++j) 63 | writer.Write(molt.UnkShit[j]); 64 | 65 | writer.Write(molt.AttenStart); 66 | writer.Write(molt.AttenEnd); 67 | } 68 | 69 | return stream.ToArray(); 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /MultiConverter.Lib/Converters/WMO/Chunks/MOMT.cs: -------------------------------------------------------------------------------- 1 | using MultiConverter.Lib.Converters.Base; 2 | using MultiConverter.Lib.Converters.WMO.Entries; 3 | using MultiConverter.Lib.Util; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Linq; 7 | 8 | namespace MultiConverter.Lib.Converters.WMO.Chunks 9 | { 10 | public class MOMT : IChunk 11 | { 12 | public string Signature => "MOMT"; 13 | public uint Length => (uint)Write().Length; 14 | public uint Order => 3; 15 | 16 | /// 17 | /// List of all filenames 18 | /// 19 | public Dictionary Filenames = new Dictionary(); 20 | 21 | /// 22 | /// List of 23 | /// 24 | public List MOMTs = new List(); 25 | 26 | private uint textureOffset = 0; 27 | 28 | public void Read(byte[] inData) 29 | { 30 | using (var stream = new MemoryStream(inData)) 31 | using (var reader = new BinaryReader(stream)) 32 | { 33 | var momtSize = inData.Length / 64; 34 | 35 | for (var i = 0; i < momtSize; ++i) 36 | { 37 | var momt = new MOMTEntry 38 | { 39 | Flags1 = reader.ReadUInt32(), 40 | ShaderType = reader.ReadUInt32(), 41 | BlendMode = reader.ReadUInt32(), 42 | TextureId1 = reader.ReadUInt32(), 43 | SidnColor = reader.ReadCArgb(), 44 | FrameSidnColor = reader.ReadCArgb(), 45 | TextureId2 = reader.ReadUInt32(), 46 | DiffColor = reader.ReadCArgb(), 47 | GroundType = reader.ReadUInt32(), 48 | TextureId3 = reader.ReadUInt32(), 49 | Color = reader.ReadCArgb(), 50 | Flags2 = reader.ReadUInt32() 51 | }; 52 | 53 | momt.Flags1 &= 0xFF; 54 | 55 | for (var j = 0; j < 4; ++j) 56 | momt.RunTimeData[j] = reader.ReadUInt32(); 57 | 58 | var filename = AddFilename(momt.TextureId1); 59 | if (filename != string.Empty) 60 | { 61 | var idx = Filenames[filename]; 62 | momt.TextureId1 = idx; 63 | } 64 | else 65 | momt.TextureId1 = 0; 66 | 67 | filename = AddFilename(momt.TextureId2); 68 | if (filename != string.Empty) 69 | { 70 | var idx = Filenames[filename]; 71 | momt.TextureId2 = idx; 72 | } 73 | else 74 | momt.TextureId2 = 0; 75 | 76 | filename = AddFilename(momt.TextureId3); 77 | if (filename != string.Empty) 78 | { 79 | var idx = Filenames[filename]; 80 | momt.TextureId3 = idx; 81 | } 82 | else 83 | momt.TextureId3 = 0; 84 | 85 | switch (momt.ShaderType) 86 | { 87 | case 13: 88 | case 14: 89 | case 15: 90 | case 16: 91 | case 7: momt.ShaderType = 6; break; 92 | case 9: momt.ShaderType = 0; break; 93 | case 12: momt.ShaderType = 5; break; 94 | default: 95 | if (momt.ShaderType >= 13) 96 | momt.ShaderType = 4; 97 | break; 98 | } 99 | 100 | MOMTs.Add(momt); 101 | } 102 | } 103 | 104 | var motx = new MOTX { Filenames = Filenames.Keys.ToList() }; 105 | WMOFile.Chunks.Add(motx); 106 | } 107 | 108 | public byte[] Write() 109 | { 110 | using (var stream = new MemoryStream()) 111 | using (var writer = new BinaryWriter(stream)) 112 | { 113 | foreach (var momt in MOMTs) 114 | { 115 | writer.Write(momt.Flags1); 116 | writer.Write(momt.ShaderType); 117 | writer.Write(momt.BlendMode); 118 | writer.Write(momt.TextureId1); 119 | writer.WriteCArgb(momt.SidnColor); 120 | writer.WriteCArgb(momt.FrameSidnColor); 121 | writer.Write(momt.TextureId2); 122 | writer.WriteCArgb(momt.DiffColor); 123 | writer.Write(momt.GroundType); 124 | writer.Write(momt.TextureId3); 125 | writer.WriteCArgb(momt.Color); 126 | writer.Write(momt.Flags2); 127 | 128 | for (var i = 0; i < 4; i++) 129 | writer.Write(momt.RunTimeData[i]); 130 | } 131 | 132 | return stream.ToArray(); 133 | } 134 | } 135 | 136 | private string AddFilename(uint fdid) 137 | { 138 | if (fdid != 0) 139 | { 140 | var textureFilename = Listfile.LookupFilename(fdid, ".wmo").Replace('/', '\\') + "\0"; 141 | 142 | if (!Filenames.ContainsKey(textureFilename)) 143 | { 144 | Filenames.Add(textureFilename, textureOffset); 145 | textureOffset += (uint)textureFilename.Length; 146 | } 147 | 148 | return textureFilename; 149 | } 150 | 151 | return string.Empty; 152 | } 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /MultiConverter.Lib/Converters/WMO/Chunks/MOPR.cs: -------------------------------------------------------------------------------- 1 | using MultiConverter.Lib.Converters.Base; 2 | using MultiConverter.Lib.Converters.WMO.Entries; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Text; 7 | 8 | namespace MultiConverter.Lib.Converters.WMO.Chunks 9 | { 10 | public class MOPR : IChunk 11 | { 12 | public string Signature => "MOPR"; 13 | public uint Length => (uint)Write().Length; 14 | public uint Order => 9; 15 | 16 | /// 17 | /// List of . 18 | /// 19 | public List MOPRs = new List(); 20 | 21 | public void Read(byte[] inData) 22 | { 23 | using (var stream = new MemoryStream(inData)) 24 | using (var reader = new BinaryReader(stream)) 25 | { 26 | var moprSize = inData.Length / 8; 27 | for (var i = 0; i < moprSize; ++i) 28 | { 29 | MOPRs.Add(new MOPREntry 30 | { 31 | PortalIndex = reader.ReadUInt16(), 32 | WMOGroupIndex = reader.ReadUInt16(), 33 | Direction = reader.ReadInt16(), 34 | AlwaysZero = reader.ReadUInt16(), 35 | }); 36 | } 37 | } 38 | } 39 | 40 | public byte[] Write() 41 | { 42 | using (var stream = new MemoryStream()) 43 | using (var writer = new BinaryWriter(stream)) 44 | { 45 | foreach (var mopr in MOPRs) 46 | { 47 | writer.Write(mopr.PortalIndex); 48 | writer.Write(mopr.WMOGroupIndex); 49 | writer.Write(mopr.Direction); 50 | writer.Write(mopr.AlwaysZero); 51 | } 52 | 53 | return stream.ToArray(); 54 | } 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /MultiConverter.Lib/Converters/WMO/Chunks/MOPT.cs: -------------------------------------------------------------------------------- 1 | using MultiConverter.Lib.Converters.Base; 2 | using MultiConverter.Lib.Converters.WMO.Entries; 3 | using MultiConverter.Lib.Util; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.IO; 7 | using System.Text; 8 | 9 | namespace MultiConverter.Lib.Converters.WMO.Chunks 10 | { 11 | public class MOPT : IChunk 12 | { 13 | public string Signature => "MOPT"; 14 | public uint Length => (uint)Write().Length; 15 | public uint Order => 8; 16 | 17 | /// 18 | /// A list of . 19 | /// 20 | public List MOPTs = new List(); 21 | 22 | public void Read(byte[] inData) 23 | { 24 | using (var stream = new MemoryStream(inData)) 25 | using (var reader = new BinaryReader(stream)) 26 | { 27 | var moptSize = inData.Length / 20; 28 | for (var i = 0; i < moptSize; ++i) 29 | { 30 | var mopt = new MOPTEntry 31 | { 32 | StartVertex = reader.ReadUInt16(), 33 | Count = reader.ReadUInt16(), 34 | Plane = reader.ReadC4Plane() 35 | }; 36 | 37 | MOPTs.Add(mopt); 38 | } 39 | } 40 | } 41 | 42 | public byte[] Write() 43 | { 44 | using (var stream = new MemoryStream()) 45 | using (var writer = new BinaryWriter(stream)) 46 | { 47 | foreach (var mopt in MOPTs) 48 | { 49 | writer.Write(mopt.StartVertex); 50 | writer.Write(mopt.Count); 51 | writer.WriteC4Plane(mopt.Plane); 52 | } 53 | 54 | return stream.ToArray(); 55 | } 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /MultiConverter.Lib/Converters/WMO/Chunks/MOPV.cs: -------------------------------------------------------------------------------- 1 | using MultiConverter.Lib.Converters.Base; 2 | using MultiConverter.Lib.Converters.WMO.Entries; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Text; 7 | 8 | namespace MultiConverter.Lib.Converters.WMO.Chunks 9 | { 10 | public class MOPV : IChunk 11 | { 12 | public string Signature => "MOPV"; 13 | public uint Length => (uint)Write().Length; 14 | public uint Order => 7; 15 | 16 | /// 17 | /// List of . 18 | /// 19 | public List MOPVs = new List(); 20 | 21 | public void Read(byte[] inData) 22 | { 23 | using (var stream = new MemoryStream(inData)) 24 | using (var reader = new BinaryReader(stream)) 25 | { 26 | var mopvSize = inData.Length / 48; 27 | for (var i = 0; i < mopvSize; ++i) 28 | { 29 | var mopv = new MOPVEntry(); 30 | 31 | for (var j = 0; j < 3; ++j) 32 | mopv.Corner1[j] = reader.ReadSingle(); 33 | 34 | for (var j = 0; j < 3; ++j) 35 | mopv.Corner2[j] = reader.ReadSingle(); 36 | 37 | for (var j = 0; j < 3; ++j) 38 | mopv.Corner3[j] = reader.ReadSingle(); 39 | 40 | for (var j = 0; j < 3; ++j) 41 | mopv.Corner4[j] = reader.ReadSingle(); 42 | 43 | MOPVs.Add(mopv); 44 | } 45 | } 46 | } 47 | 48 | public byte[] Write() 49 | { 50 | using (var stream = new MemoryStream()) 51 | using (var writer = new BinaryWriter(stream)) 52 | { 53 | foreach (var mopv in MOPVs) 54 | { 55 | for (var j = 0; j < 3; ++j) 56 | writer.Write(mopv.Corner1[j]); 57 | 58 | for (var j = 0; j < 3; ++j) 59 | writer.Write(mopv.Corner2[j]); 60 | 61 | for (var j = 0; j < 3; ++j) 62 | writer.Write(mopv.Corner3[j]); 63 | 64 | for (var j = 0; j < 3; ++j) 65 | writer.Write(mopv.Corner4[j]); 66 | } 67 | 68 | return stream.ToArray(); 69 | } 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /MultiConverter.Lib/Converters/WMO/Chunks/MOSB.cs: -------------------------------------------------------------------------------- 1 | using MultiConverter.Lib.Converters.Base; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Text; 6 | 7 | namespace MultiConverter.Lib.Converters.WMO.Chunks 8 | { 9 | public class MOSB : IChunk 10 | { 11 | public string Signature => "MOSB"; 12 | public uint Length => (uint)Write().Length; 13 | public uint Order => 6; 14 | 15 | /// 16 | /// Originaly the skybox filename. 17 | /// 18 | public uint Padding { get; set; } 19 | 20 | public void Read(byte[] inData) 21 | { 22 | using (var stream = new MemoryStream(inData)) 23 | using (var reader = new BinaryReader(stream)) 24 | { 25 | Padding = reader.ReadUInt32(); 26 | } 27 | } 28 | 29 | public byte[] Write() 30 | { 31 | using (var stream = new MemoryStream()) 32 | using (var writer = new BinaryWriter(stream)) 33 | { 34 | writer.Write(Padding); 35 | 36 | return stream.ToArray(); 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /MultiConverter.Lib/Converters/WMO/Chunks/MOTX.cs: -------------------------------------------------------------------------------- 1 | using MultiConverter.Lib.Converters.Base; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | 6 | namespace MultiConverter.Lib.Converters.WMO.Chunks 7 | { 8 | public class MOTX : IChunk 9 | { 10 | public string Signature => "MOTX"; 11 | public uint Length => (uint)Write().Length; 12 | public uint Order => 2; 13 | 14 | public List Filenames = new List(); 15 | 16 | public void Read(byte[] inData) 17 | { 18 | using (var stream = new MemoryStream(inData)) 19 | using (var reader = new BinaryReader(stream)) 20 | { 21 | throw new Exception("I am pleb, come back later"); 22 | } 23 | } 24 | 25 | public byte[] Write() 26 | { 27 | using (var stream = new MemoryStream()) 28 | using (var writer = new BinaryWriter(stream)) 29 | { 30 | // O(n^2), really don't care at this point. 31 | foreach (var filename in Filenames) 32 | foreach (var fileChar in filename) 33 | writer.Write(fileChar); 34 | 35 | return stream.ToArray(); 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /MultiConverter.Lib/Converters/WMO/Chunks/MOVB.cs: -------------------------------------------------------------------------------- 1 | using MultiConverter.Lib.Converters.Base; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace MultiConverter.Lib.Converters.WMO.Chunks 7 | { 8 | public class MOVB : IChunk 9 | { 10 | public string Signature => "MOVB"; 11 | public uint Length => (uint)Write().Length; 12 | public uint Order => 11; 13 | 14 | public void Read(byte[] inData) { } 15 | 16 | public byte[] Write() => new byte[0]; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /MultiConverter.Lib/Converters/WMO/Chunks/MOVV.cs: -------------------------------------------------------------------------------- 1 | using MultiConverter.Lib.Converters.Base; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Text; 6 | 7 | namespace MultiConverter.Lib.Converters.WMO.Chunks 8 | { 9 | public class MOVV : IChunk 10 | { 11 | public string Signature => "MOVV"; 12 | public uint Length => (uint)Write().Length; 13 | public uint Order => 10; 14 | 15 | public void Read(byte[] inData) { } 16 | 17 | public byte[] Write() => new byte[0]; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /MultiConverter.Lib/Converters/WMO/Chunks/MVER.cs: -------------------------------------------------------------------------------- 1 | using MultiConverter.Lib.Converters.Base; 2 | using System.IO; 3 | 4 | namespace MultiConverter.Lib.Converters.WMO.Chunks 5 | { 6 | public class MVER : IChunk 7 | { 8 | public string Signature => "MVER"; 9 | public uint Length => (uint)Write().Length; 10 | public uint Order => 0; 11 | 12 | /// 13 | /// The Version of . 14 | /// 15 | public uint Version { get; set; } 16 | 17 | public void Read(byte[] inData) 18 | { 19 | using (var stream = new MemoryStream(inData)) 20 | using (var reader = new BinaryReader(stream)) 21 | { 22 | Version = reader.ReadUInt32(); 23 | } 24 | } 25 | 26 | public byte[] Write() 27 | { 28 | using (var stream = new MemoryStream()) 29 | using (var writer = new BinaryWriter(stream)) 30 | { 31 | writer.Write(Version); 32 | 33 | return stream.ToArray(); 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /MultiConverter.Lib/Converters/WMO/Entries/MFOGEntry.cs: -------------------------------------------------------------------------------- 1 | using MultiConverter.Lib.Common; 2 | 3 | namespace MultiConverter.Lib.Converters.WMO.Entries 4 | { 5 | public class MFOGEntry 6 | { 7 | public uint Flags { get; set; } 8 | public C3Vector Position { get; set; } 9 | public float SmallRadius { get; set; } 10 | public float LargeRadius { get; set; } 11 | public float FogEnd { get; set; } 12 | public float FogStartMultiplier { get; set; } 13 | public CArgb FogColor { get; set; } 14 | public float Unk1 { get; set; } 15 | public float Unk2 { get; set; } 16 | public CArgb FogColor2 { get; set; } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /MultiConverter.Lib/Converters/WMO/Entries/MODDEntry.cs: -------------------------------------------------------------------------------- 1 | using MultiConverter.Lib.Common; 2 | 3 | namespace MultiConverter.Lib.Converters.WMO.Entries 4 | { 5 | public class MODDEntry 6 | { 7 | public int NameIndex { get; set; } 8 | public byte Flags { get; set; } 9 | public C3Vector Position { get; set; } 10 | public C3Vector Rotation { get; set; } 11 | public float RotationW { get; set; } 12 | public float Scale { get; set; } 13 | public CArgb Color { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /MultiConverter.Lib/Converters/WMO/Entries/MODSEntry.cs: -------------------------------------------------------------------------------- 1 | namespace MultiConverter.Lib.Converters.WMO.Entries 2 | { 3 | public class MODSEntry 4 | { 5 | public string SetName { get; set; } 6 | public uint FirstDoodadInSet { get; set; } 7 | public uint DoodadInSetCount { get; set; } 8 | public uint Padding { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /MultiConverter.Lib/Converters/WMO/Entries/MOGIEntry.cs: -------------------------------------------------------------------------------- 1 | namespace MultiConverter.Lib.Converters.WMO.Entries 2 | { 3 | public class MOGIEntry 4 | { 5 | public uint Flags { get; set; } 6 | public float[] BBoxCorner1 { get; set; } = new float[3]; 7 | public float[] BBoxCorner2 { get; set; } = new float[3]; 8 | public int NameOffset { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /MultiConverter.Lib/Converters/WMO/Entries/MOHDEntry.cs: -------------------------------------------------------------------------------- 1 | using MultiConverter.Lib.Common; 2 | 3 | namespace MultiConverter.Lib.Converters.WMO.Entries 4 | { 5 | public class MOHDEntry 6 | { 7 | public uint MaterialCount { get; set; } 8 | public uint GroupCount { get; set; } 9 | public uint PortalCount { get; set; } 10 | public uint LightCount { get; set; } 11 | public uint ModelCount { get; set; } 12 | public uint DoodadCount { get; set; } 13 | public uint SetCount { get; set; } 14 | public CArgb Color { get; set; } 15 | public uint WMOId { get; set; } 16 | public float[] BBoxCorner1 { get; set; } = new float[3]; 17 | public float[] BBoxCorner2 { get; set; } = new float[3]; 18 | public ushort FlagLod { get; set; } 19 | public ushort LodCount { get; set; } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /MultiConverter.Lib/Converters/WMO/Entries/MOLTEntry.cs: -------------------------------------------------------------------------------- 1 | using MultiConverter.Lib.Common; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace MultiConverter.Lib.Converters.WMO.Entries 7 | { 8 | public class MOLTEntry 9 | { 10 | public byte Type { get; set; } 11 | public byte[] Flags { get; set; } = new byte[3]; 12 | public CArgb Color { get; set; } 13 | public C3Vector Position { get; set; } 14 | public float Intensity { get; set; } 15 | public float[] UnkShit { get; set; } = new float[4]; 16 | public float AttenStart { get; set; } 17 | public float AttenEnd { get; set; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /MultiConverter.Lib/Converters/WMO/Entries/MOMTEntry.cs: -------------------------------------------------------------------------------- 1 | using MultiConverter.Lib.Common; 2 | 3 | namespace MultiConverter.Lib.Converters.WMO.Entries 4 | { 5 | public class MOMTEntry 6 | { 7 | public uint Flags1 { get; set; } 8 | public uint ShaderType { get; set; } 9 | public uint BlendMode { get; set; } 10 | public uint TextureId1 { get; set; } 11 | public CArgb SidnColor { get; set; } 12 | public CArgb FrameSidnColor { get; set; } 13 | public uint TextureId2 { get; set; } 14 | public CArgb DiffColor { get; set; } 15 | public uint GroundType { get; set; } 16 | public uint TextureId3 { get; set; } 17 | public CArgb Color { get; set; } 18 | public uint Flags2 { get; set; } 19 | public uint[] RunTimeData { get; set; } = new uint[4]; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /MultiConverter.Lib/Converters/WMO/Entries/MOPREntry.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace MultiConverter.Lib.Converters.WMO.Entries 6 | { 7 | public class MOPREntry 8 | { 9 | public ushort PortalIndex { get; set; } 10 | public ushort WMOGroupIndex { get; set; } 11 | public short Direction { get; set; } 12 | public ushort AlwaysZero { get; set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /MultiConverter.Lib/Converters/WMO/Entries/MOPTEntry.cs: -------------------------------------------------------------------------------- 1 | using MultiConverter.Lib.Common; 2 | 3 | namespace MultiConverter.Lib.Converters.WMO.Entries 4 | { 5 | public class MOPTEntry 6 | { 7 | public ushort StartVertex { get; set; } 8 | public ushort Count { get; set; } 9 | public C4Plane Plane { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /MultiConverter.Lib/Converters/WMO/Entries/MOPVEntry.cs: -------------------------------------------------------------------------------- 1 | namespace MultiConverter.Lib.Converters.WMO.Entries 2 | { 3 | public class MOPVEntry 4 | { 5 | public float[] Corner1 { get; set; } = new float[3]; 6 | public float[] Corner2 { get; set; } = new float[3]; 7 | public float[] Corner3 { get; set; } = new float[3]; 8 | public float[] Corner4 { get; set; } = new float[3]; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /MultiConverter.Lib/Converters/WMO/WMOFile.cs: -------------------------------------------------------------------------------- 1 | using MultiConverter.Lib.Converters.Base; 2 | using MultiConverter.Lib.Converters.WMO.Chunks; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Linq; 7 | 8 | namespace MultiConverter.Lib.Converters.WMO 9 | { 10 | public class WMOFile : IConverter 11 | { 12 | public static List Chunks = new List(); 13 | public static bool DisableDoodads = true; 14 | 15 | public void Read(byte[] data) 16 | { 17 | // Clear chunks to prevent double data. 18 | Chunks.Clear(); 19 | 20 | using (var stream = new MemoryStream(data)) 21 | using (var reader = new BinaryReader(stream)) 22 | { 23 | while (reader.BaseStream.Position < reader.BaseStream.Length) 24 | { 25 | var chunkId = (WMOChunkId)reader.ReadUInt32(); 26 | var chunkSize = reader.ReadUInt32(); 27 | 28 | var chunkData = new byte[chunkSize]; 29 | Buffer.BlockCopy(stream.ToArray(), (int)reader.BaseStream.Position, chunkData, 0, (int)chunkSize); 30 | 31 | IChunk chunk = null; 32 | switch (chunkId) 33 | { 34 | case WMOChunkId.MVER: chunk = new MVER(); break; 35 | case WMOChunkId.MOHD: chunk = new MOHD(); break; 36 | case WMOChunkId.MOTX: chunk = new MOTX(); break; 37 | case WMOChunkId.MOMT: chunk = new MOMT(); break; 38 | case WMOChunkId.MOGN: chunk = new MOGN(); break; 39 | case WMOChunkId.MOGI: chunk = new MOGI(); break; 40 | case WMOChunkId.MOPV: chunk = new MOPV(); break; 41 | case WMOChunkId.MOPT: chunk = new MOPT(); break; 42 | case WMOChunkId.MOPR: chunk = new MOPR(); break; 43 | case WMOChunkId.MOLT: chunk = new MOLT(); break; 44 | case WMOChunkId.MODS: chunk = new MODS(); break; 45 | case WMOChunkId.MODI: chunk = new MODI(); break; 46 | case WMOChunkId.MODD: chunk = new MODD(); break; 47 | case WMOChunkId.MFOG: chunk = new MFOG(); break; 48 | default: Console.WriteLine($"Skipping {chunkId} (0x{(uint)chunkId:X})"); break; 49 | } 50 | 51 | if (chunk != null) 52 | { 53 | chunk.Read(chunkData); 54 | Chunks.Add(chunk); 55 | } 56 | 57 | reader.BaseStream.Position += chunkSize; 58 | } 59 | 60 | // Add mandatory chunks. 61 | Chunks.Add(new MOSB()); 62 | Chunks.Add(new MOVV()); 63 | Chunks.Add(new MOVB()); 64 | 65 | // Close the streams so they can be written. 66 | reader.Close(); 67 | stream.Close(); 68 | } 69 | } 70 | 71 | public void Write(string filename) 72 | { 73 | Chunks = Chunks.OrderBy(x => x.Order).ToList(); 74 | 75 | using (var stream = new MemoryStream()) 76 | using (var writer = new BinaryWriter(stream)) 77 | { 78 | foreach (var chunk in Chunks) 79 | { 80 | // Ignore this chunk because it does not have to be written 81 | if (chunk.Signature == "MODI") 82 | continue; 83 | 84 | var reversedSignature = chunk.Signature.Reverse().ToArray(); 85 | 86 | foreach (var signatureChar in reversedSignature) 87 | writer.Write(signatureChar); 88 | 89 | writer.Write(chunk.Length); 90 | writer.Write(chunk.Write()); 91 | } 92 | 93 | File.WriteAllBytes(filename, stream.ToArray()); 94 | } 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /MultiConverter.Lib/Converters/WMOGroupConverter.cs: -------------------------------------------------------------------------------- 1 | using MultiConverter.Lib.Converters.Base; 2 | using System; 3 | 4 | namespace MultiConverter.Lib.Converters 5 | { 6 | public enum GroupChunk 7 | { 8 | MOGP = 1297041232, 9 | MOPY = 1297043545, 10 | MOVI = 1297045065, 11 | MOVT = 1297045076, 12 | MONR = 1297043026, 13 | MOTV = 1297044566, 14 | MOBA = 1297039937, 15 | MOLR = 1297042514, 16 | MODR = 1297040466, 17 | MOBN = 1297039950, 18 | MOBR = 1297039954, 19 | MOCR = 1297039954, 20 | MOCV = 1297040214, 21 | MLIQ = 1296845137 22 | }; 23 | 24 | public class WMOGroupConverter : ChunkedWowFile 25 | { 26 | private int posMOVT = 0; 27 | private bool wod; 28 | 29 | public WMOGroupConverter(string wmo, bool wod = false) : base(wmo) 30 | { 31 | this.wod = wod; 32 | } 33 | 34 | private bool FixWod() 35 | { 36 | int pos_moba = CheckChunk(0xC, GroupChunk.MOTV, false, false); 37 | FixMOBA(pos_moba); 38 | 39 | return true; 40 | } 41 | 42 | private bool FixLK() 43 | { 44 | int pos = 0xC, posMOBA = 0, posMLIQ = 0; 45 | 46 | uint flags = ReadUInt(0x1C); 47 | WriteUInt(0x1C, flags & 0x7FFFFFF); 48 | 49 | // MOPY pos 50 | pos = 0x58; 51 | 52 | // Mandatory chunks 53 | pos = CheckChunk(pos, GroupChunk.MOPY); 54 | pos = CheckChunk(pos, GroupChunk.MOVI); posMOVT = pos; 55 | pos = CheckChunk(pos, GroupChunk.MOVT); 56 | pos = CheckChunk(pos, GroupChunk.MONR); 57 | pos = CheckChunk(pos, GroupChunk.MOTV); posMOBA = pos; 58 | pos = CheckChunk(pos, GroupChunk.MOBA); 59 | 60 | // Optionnal chunks 61 | if ((flags & 0x200) != 0) 62 | { 63 | pos = CheckChunk(pos, GroupChunk.MOLR); 64 | } 65 | if ((flags & 0x800) != 0) 66 | { 67 | pos = CheckChunk(pos, GroupChunk.MODR); 68 | } 69 | if ((flags & 0x1) != 0) 70 | { 71 | int pos_mobn = FindChunk(pos, GroupChunk.MOBN); 72 | int pos_mobr = FindChunk(pos, GroupChunk.MOBR); 73 | 74 | if (pos_mobn == -1 && pos_mobr == -1) 75 | { 76 | // remove flag (fix client freezing) 77 | WriteInt(0x1C, (int)flags & ~0x1); 78 | } 79 | else 80 | { 81 | pos = CheckChunk(pos, GroupChunk.MOBN); 82 | pos = CheckChunk(pos, GroupChunk.MOBR); 83 | } 84 | } 85 | if ((flags & 0x4) != 0) 86 | { 87 | pos = CheckChunk(pos, GroupChunk.MOCV); 88 | } 89 | if ((flags & 0x1000) != 0) 90 | { 91 | posMLIQ = pos; 92 | pos = CheckChunk(pos, GroupChunk.MLIQ); 93 | } 94 | if ((flags & 0x2000000) != 0) 95 | { 96 | pos = CheckChunk(pos, GroupChunk.MOTV); 97 | } 98 | if ((flags & 0x1000000) != 0) 99 | { 100 | pos = CheckChunk(pos, GroupChunk.MOCV); 101 | } 102 | 103 | // Cleanup 104 | RemoveBytes(pos, Size() - pos); 105 | 106 | FixMOBA(posMOBA); 107 | 108 | int liquidID = ReadInt(0x48); 109 | if (liquidID > 181) 110 | { 111 | WriteInt(0x48, 5); 112 | } 113 | 114 | return true; 115 | } 116 | 117 | public bool Fix() 118 | { 119 | if (!Valid || Size() < 0x58 || !IsChunk(0xC, "MOGP")) 120 | { 121 | return false; 122 | } 123 | 124 | return wod ? FixWod() : FixLK(); 125 | } 126 | 127 | private void FixMOBA(int pos) 128 | { 129 | int size = ReadInt(pos + 0x4); 130 | int n = size / 0x18; 131 | pos += 0x8; 132 | 133 | 134 | 135 | for (int i = 0; i < n; i++) 136 | { 137 | if ((Data[pos + 0x16] & 2) != 0) 138 | { 139 | Data[pos + 0x16] = 0; 140 | Data[pos + 0x17] = Data[pos + 0xA]; 141 | FixMOBA_box(pos, ReadUShort(pos + 0x12), ReadUShort(pos + 0x14)); 142 | } 143 | pos += 0x18; 144 | } 145 | } 146 | 147 | private void GetVerticeCoord(ushort id, out float x, out float y, out float z) 148 | { 149 | int pos = posMOVT + 0x8 + 0xC * id; 150 | 151 | x = ReadFloat(pos); 152 | y = ReadFloat(pos + 0x4); 153 | z = ReadFloat(pos + 0x8); 154 | } 155 | 156 | private void FixMOBA_box(int box, ushort start, ushort end) 157 | { 158 | float[] f = { float.MaxValue, float.MaxValue, float.MaxValue, float.MinValue, float.MinValue, float.MinValue }; 159 | 160 | for (ushort i = start; i <= end; i++) 161 | { 162 | for (int k = 0; k < 3; ++k) 163 | { 164 | float x, y, z; 165 | 166 | GetVerticeCoord(i, out x, out y, out z); 167 | 168 | f[0] = Math.Min(x, f[0]); 169 | f[3] = Math.Max(x, f[3]); 170 | 171 | f[1] = Math.Min(y, f[1]); 172 | f[4] = Math.Max(y, f[4]); 173 | 174 | f[2] = Math.Min(z, f[2]); 175 | f[5] = Math.Max(z, f[5]); 176 | } 177 | } 178 | 179 | for (int i = 0; i < 6; i++) 180 | { 181 | WriteShort(box + 2 * i, (short)((i < 3 ? Math.Floor(f[i]) : Math.Ceiling(f[i])))); 182 | } 183 | } 184 | 185 | private int FindChunk(int pos, GroupChunk chunk) 186 | { 187 | int found = -1; 188 | for (int i = pos; i + 8 <= Size(); i += (ReadInt(i + 0x4) + 0x8)) 189 | { 190 | if (ReadInt(i) == (int)chunk) 191 | { 192 | found = i; 193 | break; 194 | } 195 | } 196 | 197 | return found; 198 | } 199 | 200 | 201 | /// 202 | /// Check if the chunk is present, if not it'll be created with a size of 0 if create is true 203 | /// Additionnal chunks between the starting pos and the chunk will be deleted 204 | /// 205 | /// starting pos for the search 206 | /// magic value of the wanted chunk 207 | /// if this is set to true and the chunk isn't there it will create it empty 208 | /// the new pos after the chunk 209 | private int CheckChunk(int pos, GroupChunk chunk, bool create = true, bool delete = true) 210 | { 211 | int found = FindChunk(pos, chunk); 212 | 213 | if (found == -1 && create) 214 | { 215 | AddEmptyBytes(pos, 8); 216 | WriteInt(pos, (int)chunk); 217 | return pos + 0x8; 218 | } 219 | if (found > pos) 220 | { 221 | if (delete) 222 | { 223 | RemoveBytes(pos, found - pos); 224 | } 225 | else 226 | { 227 | pos = found; 228 | } 229 | } 230 | 231 | if (found != -1) 232 | { 233 | pos += ReadInt(pos + 0x4) + 0x8; 234 | } 235 | 236 | // return the current pos 237 | return pos; 238 | } 239 | } 240 | } 241 | -------------------------------------------------------------------------------- /MultiConverter.Lib/MultiConverter.Lib.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.1 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | false 19 | false 20 | 21 | 22 | 23 | ..\bin\Debug\ 24 | 25 | 26 | ..\bin\Release\ 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /MultiConverter.Lib/Updater/Update.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | 4 | namespace MultiConverter.Lib.Updater 5 | { 6 | public class Update 7 | { 8 | public string VersionString { get; set; } 9 | public string DownloadUrl { get; set; } 10 | public string Changelog { get; set; } 11 | 12 | [NonSerialized] 13 | public WebClient WebClient; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /MultiConverter.Lib/Updater/UpdateManager.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Diagnostics; 5 | using System.Net; 6 | using System.Text; 7 | 8 | namespace MultiConverter.Lib.Updater 9 | { 10 | public static class UpdateManager 11 | { 12 | public const string UpdateUrl = "https://raw.githubusercontent.com/MaxtorCoder/MultiConverter/master/update.json"; 13 | public const string BetaUpdateUrl = "https://raw.githubusercontent.com/MaxtorCoder/MultiConverter/master/update_beta.json"; 14 | 15 | public static (bool, string) HasUpdates(string versionString, bool hasBeta = false) 16 | { 17 | using (var webclient = new WebClient()) 18 | { 19 | var reponseString = webclient.DownloadString(hasBeta ? BetaUpdateUrl : UpdateUrl); 20 | 21 | var update = JsonConvert.DeserializeObject(reponseString); 22 | if (update.VersionString == versionString) 23 | return (false, string.Empty); 24 | 25 | return (true, update.VersionString); 26 | } 27 | } 28 | 29 | public static string GetChangelog(bool hasBeta = false) 30 | { 31 | using (var webclient = new WebClient()) 32 | { 33 | var reponseString = webclient.DownloadString(hasBeta ? BetaUpdateUrl : UpdateUrl); 34 | 35 | var update = JsonConvert.DeserializeObject(reponseString); 36 | return update.Changelog; 37 | } 38 | } 39 | 40 | public static void StartUpdater(bool hasBeta = false) 41 | { 42 | Process.Start("MultiConverter.Updater.exe", $"-b \"{(hasBeta ? true : false)}\""); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /MultiConverter.Lib/Util/Extensions.cs: -------------------------------------------------------------------------------- 1 | using MultiConverter.Lib.Common; 2 | using System; 3 | using System.IO; 4 | using System.Text; 5 | 6 | namespace MultiConverter.Lib.Util 7 | { 8 | public static class Extensions 9 | { 10 | public static CAaBox ReadCAaBox(this BinaryReader reader) 11 | { 12 | return new CAaBox 13 | { 14 | Min = reader.ReadC3Vector(), 15 | Max = reader.ReadC3Vector() 16 | }; 17 | } 18 | public static void WriteCAaBox(this BinaryWriter writer, CAaBox box) 19 | { 20 | writer.WriteC3Vector(box.Min); 21 | writer.WriteC3Vector(box.Max); 22 | } 23 | 24 | public static CArgb ReadCArgb(this BinaryReader reader) 25 | { 26 | return new CArgb 27 | { 28 | R = reader.ReadByte(), 29 | G = reader.ReadByte(), 30 | B = reader.ReadByte(), 31 | A = reader.ReadByte(), 32 | }; 33 | } 34 | public static void WriteCArgb(this BinaryWriter writer, CArgb color) 35 | { 36 | writer.Write(color.R); 37 | writer.Write(color.G); 38 | writer.Write(color.B); 39 | writer.Write(color.A); 40 | } 41 | 42 | public static C3Vector ReadC3Vector(this BinaryReader reader) 43 | { 44 | return new C3Vector 45 | { 46 | X = reader.ReadSingle(), 47 | Y = reader.ReadSingle(), 48 | Z = reader.ReadSingle(), 49 | }; 50 | } 51 | public static void WriteC3Vector(this BinaryWriter writer, C3Vector vector) 52 | { 53 | writer.Write(vector.X); 54 | writer.Write(vector.Y); 55 | writer.Write(vector.Z); 56 | } 57 | 58 | public static C4Plane ReadC4Plane(this BinaryReader reader) 59 | { 60 | return new C4Plane 61 | { 62 | Normal = reader.ReadC3Vector(), 63 | Distance = reader.ReadSingle() 64 | }; 65 | } 66 | public static void WriteC4Plane(this BinaryWriter writer, C4Plane plane) 67 | { 68 | writer.WriteC3Vector(plane.Normal); 69 | writer.Write(plane.Distance); 70 | } 71 | 72 | public static string ReadNullTerminatedString(this BinaryReader reader) 73 | { 74 | var sb = new StringBuilder(); 75 | char c; 76 | 77 | while ((c = Convert.ToChar(reader.ReadByte())) != 0) 78 | sb.Append(c); 79 | 80 | return sb.ToString(); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /MultiConverter.Lib/Util/Listfile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Net; 5 | 6 | namespace MultiConverter.Lib 7 | { 8 | public static class Listfile 9 | { 10 | private static WebClient webClient = new WebClient(); 11 | private static string buildConfig = ""; 12 | private static string listfile = "listfile.csv"; 13 | private static string listUrl = "https://wow.tools/casc/listfile/download/csv/unverified"; 14 | private static Dictionary FiledataPair = new Dictionary(); 15 | 16 | public static bool IsInitialized = false; 17 | 18 | public static void Initialize() 19 | { 20 | // Download listfile if file does not exist. 21 | if (!File.Exists(listfile)) 22 | webClient.DownloadFile(listUrl, listfile); 23 | else 24 | { 25 | using (var reader = new StreamReader(listfile)) 26 | { 27 | while (!reader.EndOfStream) 28 | { 29 | var line = reader.ReadLine(); 30 | var array = line.Split(';'); 31 | 32 | FiledataPair.Add(uint.Parse(array[0]), array[1]); 33 | } 34 | 35 | IsInitialized = true; 36 | } 37 | } 38 | 39 | // Check latest buildconfig. 40 | using (var stream = new MemoryStream(webClient.DownloadData("http://us.patch.battle.net:1119/wow_beta/versions"))) 41 | using (var reader = new StreamReader(stream)) 42 | { 43 | // Read useless lines. 44 | reader.ReadLine(); 45 | reader.ReadLine(); 46 | 47 | var line = reader.ReadLine(); 48 | var array = line.Split('|'); 49 | 50 | // second element of the array 51 | // us|3f483ee25f283e9072d1a9dceb0160c2|230ddf963c980e2d5ec9882c2a8a00ce||32861|8.3.0.32861|a96756c514489774e38ef1edbc17dcc5 52 | buildConfig = array[1]; 53 | } 54 | } 55 | 56 | public static string LookupFilename(uint id, string extension, string downloadExtension = "blp") 57 | { 58 | // Lookup the Id in the listfile, if it does not exist 59 | // download and place in blp/// 60 | if (FiledataPair.TryGetValue(id, out string filename)) 61 | { 62 | Console.WriteLine($"Filename: {filename} (Length: {filename.Length} ID: {id})"); 63 | return filename; 64 | } 65 | else 66 | { 67 | if (id != 0) 68 | { 69 | var newFilename = $"{id}.{downloadExtension}"; 70 | var newExtension = extension.Remove(0, 1); 71 | var pathName = $"Unk/{downloadExtension}/{newExtension}/{newFilename}"; 72 | 73 | if (!Directory.Exists($"Unk/{downloadExtension}")) 74 | Directory.CreateDirectory($"Unk/{downloadExtension}"); 75 | if (!Directory.Exists($"Unk/{downloadExtension}/{newExtension}")) 76 | Directory.CreateDirectory($"Unk/{downloadExtension}/{newExtension}"); 77 | 78 | if (File.Exists(pathName)) 79 | { 80 | Console.WriteLine($"Filename: {pathName} (Length: {pathName.Length} ID: {id})"); 81 | } 82 | else 83 | { 84 | Console.WriteLine($"Downloading: {newFilename} (Id: {id})"); 85 | webClient.DownloadFile($"https://wow.tools/casc/file/fdid?buildconfig={buildConfig}&filename={newFilename}&filedataid={id}", pathName); 86 | } 87 | 88 | return pathName; 89 | } 90 | } 91 | 92 | return string.Empty; 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /MultiConverter.Lib/Util/Utils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Text.RegularExpressions; 4 | 5 | namespace MultiConverter.Lib 6 | { 7 | public class Utils 8 | { 9 | public static bool IsCorrectFile(string s) 10 | { 11 | return s.EndsWith(".m2", StringComparison.OrdinalIgnoreCase) 12 | || s.EndsWith(".anim", StringComparison.OrdinalIgnoreCase) 13 | || s.EndsWith(".wmo", StringComparison.OrdinalIgnoreCase) 14 | || s.EndsWith(".adt", StringComparison.OrdinalIgnoreCase) 15 | || s.EndsWith(".wdt", StringComparison.OrdinalIgnoreCase) 16 | || s.EndsWith(".skin", StringComparison.OrdinalIgnoreCase); 17 | } 18 | 19 | public static bool IsChunk(ref byte[] buff, int pos, int magic) 20 | { 21 | return BitConverter.ToInt32(buff, pos) == magic; 22 | } 23 | 24 | public static void CopyInt(ref byte[] buff, int pos, int value) 25 | { 26 | Buffer.BlockCopy(BitConverter.GetBytes(value), 0, buff, pos, 4); 27 | } 28 | 29 | public static void RemoveBytes(ref byte[] buff, int start, int count) 30 | { 31 | int size = buff.Length; 32 | 33 | if (size <= start + count || count <= 0) 34 | { 35 | return; 36 | } 37 | 38 | byte[] tmp = new byte[size - count]; 39 | if (start > 0) 40 | { 41 | Buffer.BlockCopy(buff, 0, tmp, 0, start); 42 | } 43 | Buffer.BlockCopy(buff, start + count, tmp, start, size - count - start); 44 | buff = tmp; 45 | } 46 | 47 | public static void AddEmptyBytes(ref byte[] buff, int start, int count) 48 | { 49 | int size = buff.Length; 50 | byte[] tmp = new byte[size + count]; 51 | Buffer.BlockCopy(buff, 0, tmp, 0, start); 52 | Buffer.BlockCopy(buff, start, tmp, start + count, size - start); 53 | buff = tmp; 54 | } 55 | 56 | public static void InsertBytes(ref byte[] buff, int start, byte[] bytes) 57 | { 58 | AddEmptyBytes(ref buff, start, bytes.Length); 59 | Buffer.BlockCopy(bytes, 0, buff, start, bytes.Length); 60 | } 61 | 62 | public static void RemoveUnwantedChunks(ref byte[] tab, int start, int magic) 63 | { 64 | if (tab.Length < start + 9) 65 | { 66 | return; 67 | } 68 | 69 | int header = BitConverter.ToInt32(tab, start); 70 | int end = start; 71 | // check to prevent out of bound exception 72 | while (header != magic && tab.Length > end + 8) 73 | { 74 | if (header < 1291845632) 75 | { 76 | end += 0x4; 77 | } 78 | else 79 | { 80 | end += BitConverter.ToInt32(tab, start + 0x4) + 0x8; 81 | } 82 | if (tab.Length < end + 4) 83 | { 84 | break; 85 | } 86 | header = BitConverter.ToInt32(tab, end); 87 | } 88 | RemoveBytes(ref tab, start, end - start); 89 | } 90 | 91 | public static void DeleteFile(string path) 92 | { 93 | if (File.Exists(path)) 94 | { 95 | File.Delete(path); 96 | } 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /MultiConverter.Updater/MainForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace MultiConverter.Updater 2 | { 3 | partial class MainForm 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.boxChangelog = new System.Windows.Forms.RichTextBox(); 32 | this.label1 = new System.Windows.Forms.Label(); 33 | this.boxStatus = new System.Windows.Forms.RichTextBox(); 34 | this.progressBar = new System.Windows.Forms.ProgressBar(); 35 | this.SuspendLayout(); 36 | // 37 | // boxChangelog 38 | // 39 | this.boxChangelog.Location = new System.Drawing.Point(12, 27); 40 | this.boxChangelog.Name = "boxChangelog"; 41 | this.boxChangelog.ReadOnly = true; 42 | this.boxChangelog.Size = new System.Drawing.Size(268, 411); 43 | this.boxChangelog.TabIndex = 0; 44 | this.boxChangelog.Text = ""; 45 | // 46 | // label1 47 | // 48 | this.label1.AutoSize = true; 49 | this.label1.Location = new System.Drawing.Point(12, 5); 50 | this.label1.Name = "label1"; 51 | this.label1.Size = new System.Drawing.Size(68, 15); 52 | this.label1.TabIndex = 1; 53 | this.label1.Text = "Changelog:"; 54 | // 55 | // boxStatus 56 | // 57 | this.boxStatus.Location = new System.Drawing.Point(286, 27); 58 | this.boxStatus.Name = "boxStatus"; 59 | this.boxStatus.ReadOnly = true; 60 | this.boxStatus.Size = new System.Drawing.Size(435, 382); 61 | this.boxStatus.TabIndex = 2; 62 | this.boxStatus.Text = ""; 63 | // 64 | // progressBar 65 | // 66 | this.progressBar.Location = new System.Drawing.Point(286, 415); 67 | this.progressBar.Name = "progressBar"; 68 | this.progressBar.Size = new System.Drawing.Size(435, 23); 69 | this.progressBar.TabIndex = 3; 70 | // 71 | // MainForm 72 | // 73 | this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); 74 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 75 | this.ClientSize = new System.Drawing.Size(728, 450); 76 | this.Controls.Add(this.progressBar); 77 | this.Controls.Add(this.boxStatus); 78 | this.Controls.Add(this.label1); 79 | this.Controls.Add(this.boxChangelog); 80 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow; 81 | this.MaximizeBox = false; 82 | this.MinimizeBox = false; 83 | this.Name = "MainForm"; 84 | this.Text = "MultiConverter - Updater"; 85 | this.ResumeLayout(false); 86 | this.PerformLayout(); 87 | 88 | } 89 | 90 | #endregion 91 | 92 | private System.Windows.Forms.RichTextBox boxChangelog; 93 | private System.Windows.Forms.Label label1; 94 | private System.Windows.Forms.RichTextBox boxStatus; 95 | private System.Windows.Forms.ProgressBar progressBar; 96 | } 97 | } 98 | 99 | -------------------------------------------------------------------------------- /MultiConverter.Updater/MainForm.cs: -------------------------------------------------------------------------------- 1 | using MultiConverter.Updater.Updater; 2 | using Newtonsoft.Json; 3 | using System; 4 | using System.ComponentModel; 5 | using System.Diagnostics; 6 | using System.IO; 7 | using System.IO.Compression; 8 | using System.Net; 9 | using System.Threading; 10 | using System.Windows.Forms; 11 | 12 | namespace MultiConverter.Updater 13 | { 14 | public partial class MainForm : Form 15 | { 16 | private bool hasBeta = false; 17 | private BackgroundWorker updateWorker; 18 | 19 | public MainForm(string[] args) 20 | { 21 | InitializeComponent(); 22 | 23 | // for (var i = 0; i < args.Length; ++i) 24 | // { 25 | // if (args[i] == "-b") 26 | // hasBeta = bool.Parse(args[++i]); 27 | // } 28 | 29 | boxChangelog.Text = UpdateManager.GetChangelog(hasBeta); 30 | DownloadUpdate(); 31 | } 32 | 33 | private void DownloadUpdate() 34 | { 35 | updateWorker = new BackgroundWorker(); 36 | updateWorker.WorkerReportsProgress = true; 37 | updateWorker.DoWork += UpdateWorker_DoWork; 38 | updateWorker.ProgressChanged += UpdateWorker_ProgressChanged; 39 | updateWorker.RunWorkerCompleted += UpdateWorker_RunWorkerCompleted; 40 | 41 | using (var webClient = new WebClient()) 42 | { 43 | var reponseString = webClient.DownloadString(hasBeta ? UpdateManager.BetaUpdateUrl : UpdateManager.UpdateUrl); 44 | var update = JsonConvert.DeserializeObject(reponseString); 45 | 46 | update.WebClient = webClient; 47 | 48 | updateWorker.RunWorkerAsync(update); 49 | } 50 | } 51 | 52 | private void UpdateWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 53 | { 54 | Thread.Sleep(5000); 55 | Process.Start("MultiConverter.GUI.exe"); 56 | Close(); 57 | } 58 | 59 | private void UpdateWorker_ProgressChanged(object sender, ProgressChangedEventArgs e) 60 | { 61 | progressBar.Value = e.ProgressPercentage; 62 | boxStatus.AppendText($"[{DateTime.Now}] {e.UserState}\n"); 63 | } 64 | 65 | private void UpdateWorker_DoWork(object sender, DoWorkEventArgs e) 66 | { 67 | // Let it load for a minute.. 68 | Thread.Sleep(2000); 69 | 70 | var update = e.Argument as Update; 71 | 72 | updateWorker.ReportProgress(0, "Downloading update..."); 73 | 74 | // https://github.com/MaxtorCoder/MultiConverter/releases/download/3.6.1/MultiConverter3.6.1.rar 75 | update.WebClient.DownloadFile($"{update.DownloadUrl}/{update.VersionString}/MultiConverter{update.VersionString}", "update.zip"); 76 | 77 | updateWorker.ReportProgress(45, "Downloaded update.. Extracting update.."); 78 | 79 | var zip = new ZipArchive(File.OpenRead("update.zip")); 80 | 81 | var currentIdx = 0; 82 | foreach (var file in zip.Entries) 83 | { 84 | updateWorker.ReportProgress(45 + (++currentIdx), $"Extracting file: {file.FullName}"); 85 | 86 | File.Delete(file.FullName); 87 | using (var stream = file.Open()) 88 | { 89 | var data = new byte[file.Length]; 90 | stream.Read(data, 0, (int)file.Length); 91 | 92 | File.WriteAllBytes(file.FullName, data); 93 | } 94 | } 95 | 96 | zip.Dispose(); 97 | File.Delete("update.zip"); 98 | 99 | updateWorker.ReportProgress(100, "Done extracting update.. Closing this in 5 seconds!"); 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /MultiConverter.Updater/MainForm.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /MultiConverter.Updater/MultiConverter.Updater.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | WinExe 5 | netcoreapp3.1 6 | true 7 | 8 | 9 | 10 | false 11 | false 12 | 13 | 14 | 15 | ..\bin\Debug\ 16 | 17 | 18 | ..\bin\Release\ 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /MultiConverter.Updater/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using System.Windows.Forms; 6 | 7 | namespace MultiConverter.Updater 8 | { 9 | static class Program 10 | { 11 | /// 12 | /// The main entry point for the application. 13 | /// 14 | [STAThread] 15 | static void Main(string[] args) 16 | { 17 | Application.SetHighDpiMode(HighDpiMode.SystemAware); 18 | Application.EnableVisualStyles(); 19 | Application.SetCompatibleTextRenderingDefault(false); 20 | Application.Run(new MainForm(args)); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /MultiConverter.Updater/Updater/Update.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | 4 | namespace MultiConverter.Updater.Updater 5 | { 6 | public class Update 7 | { 8 | public string VersionString { get; set; } 9 | public string DownloadUrl { get; set; } 10 | public string Changelog { get; set; } 11 | 12 | [NonSerialized] 13 | public WebClient WebClient; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /MultiConverter.Updater/Updater/UpdateManager.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Diagnostics; 5 | using System.Net; 6 | using System.Text; 7 | 8 | namespace MultiConverter.Updater.Updater 9 | { 10 | public static class UpdateManager 11 | { 12 | public const string UpdateUrl = "https://raw.githubusercontent.com/MaxtorCoder/MultiConverter/master/update.json"; 13 | public const string BetaUpdateUrl = "https://raw.githubusercontent.com/MaxtorCoder/MultiConverter/master/update_beta.json"; 14 | 15 | public static (bool, string) HasUpdates(string versionString, bool hasBeta = false) 16 | { 17 | using (var webclient = new WebClient()) 18 | { 19 | var reponseString = webclient.DownloadString(hasBeta ? BetaUpdateUrl : UpdateUrl); 20 | 21 | var update = JsonConvert.DeserializeObject(reponseString); 22 | if (update.VersionString == versionString) 23 | return (false, string.Empty); 24 | 25 | return (true, update.VersionString); 26 | } 27 | } 28 | 29 | public static string GetChangelog(bool hasBeta = false) 30 | { 31 | using (var webclient = new WebClient()) 32 | { 33 | var reponseString = webclient.DownloadString(hasBeta ? BetaUpdateUrl : UpdateUrl); 34 | 35 | var update = JsonConvert.DeserializeObject(reponseString); 36 | return update.Changelog; 37 | } 38 | } 39 | 40 | public static void StartUpdater(bool hasBeta = false) 41 | { 42 | Process.Start("MultiConverter.Updater.exe", $"-b \"{(hasBeta ? true : false)}\""); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /MultiConverter.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30014.187 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MultiConverter.GUI", "MultiConverter.GUI\MultiConverter.GUI.csproj", "{D338BB83-9455-4328-825E-4FD8A72F4B67}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MultiConverter.Lib", "MultiConverter.Lib\MultiConverter.Lib.csproj", "{00D3B1F6-46F1-4505-8E90-97B83DC436B6}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MultiConverter.Updater", "MultiConverter.Updater\MultiConverter.Updater.csproj", "{FF8E2C84-435D-468F-8958-A465588F8981}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Release|Any CPU = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {D338BB83-9455-4328-825E-4FD8A72F4B67}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {D338BB83-9455-4328-825E-4FD8A72F4B67}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {D338BB83-9455-4328-825E-4FD8A72F4B67}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {D338BB83-9455-4328-825E-4FD8A72F4B67}.Release|Any CPU.Build.0 = Release|Any CPU 22 | {00D3B1F6-46F1-4505-8E90-97B83DC436B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {00D3B1F6-46F1-4505-8E90-97B83DC436B6}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {00D3B1F6-46F1-4505-8E90-97B83DC436B6}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {00D3B1F6-46F1-4505-8E90-97B83DC436B6}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {FF8E2C84-435D-468F-8958-A465588F8981}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {FF8E2C84-435D-468F-8958-A465588F8981}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {FF8E2C84-435D-468F-8958-A465588F8981}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {FF8E2C84-435D-468F-8958-A465588F8981}.Release|Any CPU.Build.0 = Release|Any CPU 30 | EndGlobalSection 31 | GlobalSection(SolutionProperties) = preSolution 32 | HideSolutionNode = FALSE 33 | EndGlobalSection 34 | GlobalSection(ExtensibilityGlobals) = postSolution 35 | SolutionGuid = {0D3C26A0-0518-4F3B-98F8-A5C1B1B2CC18} 36 | EndGlobalSection 37 | EndGlobal 38 | -------------------------------------------------------------------------------- /README.MD: -------------------------------------------------------------------------------- 1 | # Multiconverter - WoW 3.3.5a 2 | ## Information 3 | Originally written by [Adspartan](https://github.com/Adspartan "Adspartan's Github") 4 | 5 | ## Support 6 | For support please go to the Discord linked at the bottom, and go to the #support channel. 😄 7 | 8 | ## How To 9 | To use it just open it then drag and drop the files you want to convert (or a folder containing some, subfolder included) and click on "Fix", the files will be overwritten and it will delete the files that are unused on wotlk. 10 | If the .skin files are in the same folder they will be converted too. 11 | 12 | ## Requirements 13 | * Visual Studio 2019 (.NET Core 3.1) 14 | 15 | ## File Support 16 | | Format | BFA (Above 26629)| Shadowlands | 17 | |:--------:|:----------------:|:-----------:| 18 | | M2 | ✔️ |✔️ | 19 | | WMO | ✔️ |❌ | 20 | | ADT | ❌ |❌ | 21 | | WDT | ❌ |❌ | 22 | 23 | ## To-Do 24 | * Animation particles 25 | * Set WMOs liquid types that correspond when the ID is too high 26 | * Set fel liquid to green lava on adt for a better / more accurate look 27 | * ADT BFA support 28 | * WDT BFA support 29 | 30 | ## Links 31 | - [Discord](https://discord.gg/vcpwDVN) 32 | - [Model Changing](https://model-changing.net/) 33 | -------------------------------------------------------------------------------- /update.json: -------------------------------------------------------------------------------- 1 | {"VersionString": "3.6.2.0","DownloadUrl": "https://github.com/MaxtorCoder/MultiConverter/releases/download/","Changelog": ""} -------------------------------------------------------------------------------- /update_beta.json: -------------------------------------------------------------------------------- 1 | {"VersionString": "3.6.2.0","DownloadUrl": "https://github.com/MaxtorCoder/MultiConverter/releases/download/","Changelog": ""} --------------------------------------------------------------------------------