diff --git a/App.config b/App.config index 8e15646..660c48a 100644 --- a/App.config +++ b/App.config @@ -1,6 +1,21 @@  + + +
+ + + + + + + + + engine + + + \ No newline at end of file diff --git a/Forms/Launcher.Designer.cs b/Forms/Launcher.Designer.cs new file mode 100644 index 0000000..f0a69ef --- /dev/null +++ b/Forms/Launcher.Designer.cs @@ -0,0 +1,328 @@ + +namespace GettingUpTool.Forms +{ + partial class Launcher + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Launcher)); + this.btnRun = new System.Windows.Forms.Button(); + this.menuStrip1 = new System.Windows.Forms.MenuStrip(); + this.textureToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); + this.levelToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.pakToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.helpToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.cmbLevelSelect = new System.Windows.Forms.ComboBox(); + this.lblLevelSelect = new System.Windows.Forms.Label(); + this.chkClearAssetCache = new System.Windows.Forms.CheckBox(); + this.txtArgs = new System.Windows.Forms.TextBox(); + this.lblArgs = new System.Windows.Forms.Label(); + this.txtCmdLine = new System.Windows.Forms.TextBox(); + this.lblCmdLine = new System.Windows.Forms.Label(); + this.lblCharSelect = new System.Windows.Forms.Label(); + this.cmbCharSelect = new System.Windows.Forms.ComboBox(); + this.lblGameRoot = new System.Windows.Forms.Label(); + this.cmbRootSelect = new System.Windows.Forms.ComboBox(); + this.lblGamePath = new System.Windows.Forms.Label(); + this.txtGamePath = new System.Windows.Forms.TextBox(); + this.btnGamePathBrowse = new System.Windows.Forms.Button(); + this.folderBrowser = new System.Windows.Forms.FolderBrowserDialog(); + this.menuStrip1.SuspendLayout(); + this.SuspendLayout(); + // + // btnRun + // + this.btnRun.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.btnRun.Location = new System.Drawing.Point(12, 415); + this.btnRun.Name = "btnRun"; + this.btnRun.Size = new System.Drawing.Size(287, 23); + this.btnRun.TabIndex = 0; + this.btnRun.Text = "Run"; + this.btnRun.UseVisualStyleBackColor = true; + this.btnRun.Click += new System.EventHandler(this.btnRun_Click); + // + // menuStrip1 + // + this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.textureToolStripMenuItem1, + this.levelToolStripMenuItem, + this.helpToolStripMenuItem}); + this.menuStrip1.Location = new System.Drawing.Point(0, 0); + this.menuStrip1.Name = "menuStrip1"; + this.menuStrip1.Size = new System.Drawing.Size(311, 24); + this.menuStrip1.TabIndex = 1; + this.menuStrip1.Text = "menuStrip1"; + // + // textureToolStripMenuItem1 + // + this.textureToolStripMenuItem1.Name = "textureToolStripMenuItem1"; + this.textureToolStripMenuItem1.Size = new System.Drawing.Size(136, 22); + this.textureToolStripMenuItem1.Text = "Texture tool"; + this.textureToolStripMenuItem1.Click += new System.EventHandler(this.textureToolStripMenuItem1_Click); + // + // levelToolStripMenuItem + // + this.levelToolStripMenuItem.Name = "levelToolStripMenuItem"; + this.levelToolStripMenuItem.Size = new System.Drawing.Size(136, 22); + this.levelToolStripMenuItem.Text = "Level tool"; + this.levelToolStripMenuItem.Click += new System.EventHandler(this.levelToolStripMenuItem_Click); + // + // pakToolStripMenuItem + // + this.pakToolStripMenuItem.Name = "pakToolStripMenuItem"; + this.pakToolStripMenuItem.Size = new System.Drawing.Size(136, 22); + this.pakToolStripMenuItem.Text = "PAK tool"; + this.pakToolStripMenuItem.Click += new System.EventHandler(this.pakToolStripMenuItem_Click); + // + // helpToolStripMenuItem + // + this.helpToolStripMenuItem.Name = "helpToolStripMenuItem"; + this.helpToolStripMenuItem.Size = new System.Drawing.Size(44, 20); + this.helpToolStripMenuItem.Text = "Help"; + this.helpToolStripMenuItem.Click += new System.EventHandler(this.helpToolStripMenuItem_Click); + // + // cmbLevelSelect + // + this.cmbLevelSelect.FormattingEnabled = true; + this.cmbLevelSelect.Location = new System.Drawing.Point(12, 196); + this.cmbLevelSelect.Name = "cmbLevelSelect"; + this.cmbLevelSelect.Size = new System.Drawing.Size(170, 21); + this.cmbLevelSelect.TabIndex = 2; + this.cmbLevelSelect.SelectionChangeCommitted += new System.EventHandler(this.comboBox_CmdArg_SelectionChangeCommitted); + // + // lblLevelSelect + // + this.lblLevelSelect.AutoSize = true; + this.lblLevelSelect.Location = new System.Drawing.Point(12, 180); + this.lblLevelSelect.Name = "lblLevelSelect"; + this.lblLevelSelect.Size = new System.Drawing.Size(64, 13); + this.lblLevelSelect.TabIndex = 3; + this.lblLevelSelect.Text = "Level select"; + // + // chkClearAssetCache + // + this.chkClearAssetCache.AutoSize = true; + this.chkClearAssetCache.Checked = true; + this.chkClearAssetCache.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkClearAssetCache.Location = new System.Drawing.Point(188, 198); + this.chkClearAssetCache.Name = "chkClearAssetCache"; + this.chkClearAssetCache.Size = new System.Drawing.Size(111, 17); + this.chkClearAssetCache.TabIndex = 0; + this.chkClearAssetCache.Text = "Clear asset cache"; + this.chkClearAssetCache.UseVisualStyleBackColor = true; + // + // txtArgs + // + this.txtArgs.Location = new System.Drawing.Point(12, 313); + this.txtArgs.Name = "txtArgs"; + this.txtArgs.Size = new System.Drawing.Size(287, 20); + this.txtArgs.TabIndex = 5; + // + // lblArgs + // + this.lblArgs.AutoSize = true; + this.lblArgs.Location = new System.Drawing.Point(12, 297); + this.lblArgs.Name = "lblArgs"; + this.lblArgs.Size = new System.Drawing.Size(105, 13); + this.lblArgs.TabIndex = 6; + this.lblArgs.Text = "Additional arguments"; + // + // txtCmdLine + // + this.txtCmdLine.Location = new System.Drawing.Point(12, 352); + this.txtCmdLine.Multiline = true; + this.txtCmdLine.Name = "txtCmdLine"; + this.txtCmdLine.ReadOnly = true; + this.txtCmdLine.Size = new System.Drawing.Size(287, 48); + this.txtCmdLine.TabIndex = 7; + // + // lblCmdLine + // + this.lblCmdLine.AutoSize = true; + this.lblCmdLine.Location = new System.Drawing.Point(12, 336); + this.lblCmdLine.Name = "lblCmdLine"; + this.lblCmdLine.Size = new System.Drawing.Size(73, 13); + this.lblCmdLine.TabIndex = 8; + this.lblCmdLine.Text = "Command-line"; + // + // lblCharSelect + // + this.lblCharSelect.AutoSize = true; + this.lblCharSelect.Location = new System.Drawing.Point(12, 131); + this.lblCharSelect.Name = "lblCharSelect"; + this.lblCharSelect.Size = new System.Drawing.Size(84, 13); + this.lblCharSelect.TabIndex = 10; + this.lblCharSelect.Text = "Character select"; + // + // cmbCharSelect + // + this.cmbCharSelect.FormattingEnabled = true; + this.cmbCharSelect.Items.AddRange(new object[] { + "Trane", + "ConWorker", + "Cope2", + "Dip", + "Dog", + "Gabe", + "ManfredsArmy", + "Kry1", + "MeatWorker", + "OrangeGuardHeavy", + "OrangeGuardLight", + "PoliceChief", + "SecurityGuard", + "ShannaRay", + "SilverGuardHeavy", + "SilverGuardLight", + "Spleen", + "Stake", + "VandalSquad", + "VandalSquadBoss", + "VanR", + "VanRHeavy", + "Welder", + "WhiteMike", + "WorkBum", + "WWAHeavy"}); + this.cmbCharSelect.Location = new System.Drawing.Point(12, 147); + this.cmbCharSelect.Name = "cmbCharSelect"; + this.cmbCharSelect.Size = new System.Drawing.Size(139, 21); + this.cmbCharSelect.TabIndex = 9; + this.cmbCharSelect.SelectionChangeCommitted += new System.EventHandler(this.comboBox_CmdArg_SelectionChangeCommitted); + // + // lblGameRoot + // + this.lblGameRoot.AutoSize = true; + this.lblGameRoot.Location = new System.Drawing.Point(12, 82); + this.lblGameRoot.Name = "lblGameRoot"; + this.lblGameRoot.Size = new System.Drawing.Size(56, 13); + this.lblGameRoot.TabIndex = 12; + this.lblGameRoot.Text = "Game root"; + // + // cmbRootSelect + // + this.cmbRootSelect.FormattingEnabled = true; + this.cmbRootSelect.Items.AddRange(new object[] { + "engine", + "beta"}); + this.cmbRootSelect.Location = new System.Drawing.Point(12, 98); + this.cmbRootSelect.Name = "cmbRootSelect"; + this.cmbRootSelect.Size = new System.Drawing.Size(139, 21); + this.cmbRootSelect.TabIndex = 11; + this.cmbRootSelect.SelectionChangeCommitted += new System.EventHandler(this.cmbRootSelect_SelectionChangeCommitted); + // + // lblGamePath + // + this.lblGamePath.AutoSize = true; + this.lblGamePath.Location = new System.Drawing.Point(12, 33); + this.lblGamePath.Name = "lblGamePath"; + this.lblGamePath.Size = new System.Drawing.Size(59, 13); + this.lblGamePath.TabIndex = 14; + this.lblGamePath.Text = "Game path"; + // + // txtGamePath + // + this.txtGamePath.Location = new System.Drawing.Point(12, 49); + this.txtGamePath.Name = "txtGamePath"; + this.txtGamePath.Size = new System.Drawing.Size(215, 20); + this.txtGamePath.TabIndex = 13; + // + // btnGamePathBrowse + // + this.btnGamePathBrowse.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.btnGamePathBrowse.Location = new System.Drawing.Point(233, 48); + this.btnGamePathBrowse.Name = "btnGamePathBrowse"; + this.btnGamePathBrowse.Size = new System.Drawing.Size(66, 22); + this.btnGamePathBrowse.TabIndex = 15; + this.btnGamePathBrowse.Text = "Browse"; + this.btnGamePathBrowse.UseVisualStyleBackColor = true; + this.btnGamePathBrowse.Click += new System.EventHandler(this.btnGamePathBrowse_Click); + // + // Launcher + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(311, 450); + this.Controls.Add(this.btnGamePathBrowse); + this.Controls.Add(this.lblGamePath); + this.Controls.Add(this.txtGamePath); + this.Controls.Add(this.lblGameRoot); + this.Controls.Add(this.cmbRootSelect); + this.Controls.Add(this.lblCharSelect); + this.Controls.Add(this.cmbCharSelect); + this.Controls.Add(this.lblCmdLine); + this.Controls.Add(this.txtCmdLine); + this.Controls.Add(this.lblArgs); + this.Controls.Add(this.lblLevelSelect); + this.Controls.Add(this.chkClearAssetCache); + this.Controls.Add(this.cmbLevelSelect); + this.Controls.Add(this.txtArgs); + this.Controls.Add(this.btnRun); + this.Controls.Add(this.menuStrip1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.MainMenuStrip = this.menuStrip1; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "Launcher"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; + this.Text = "MEGU Launcher"; + this.Load += new System.EventHandler(this.Launcher_Load); + this.menuStrip1.ResumeLayout(false); + this.menuStrip1.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Button btnRun; + private System.Windows.Forms.MenuStrip menuStrip1; + private System.Windows.Forms.ToolStripMenuItem textureToolStripMenuItem1; + private System.Windows.Forms.ToolStripMenuItem levelToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem pakToolStripMenuItem; + private System.Windows.Forms.ComboBox cmbLevelSelect; + private System.Windows.Forms.Label lblLevelSelect; + private System.Windows.Forms.CheckBox chkClearAssetCache; + private System.Windows.Forms.ToolStripMenuItem helpToolStripMenuItem; + private System.Windows.Forms.TextBox txtArgs; + private System.Windows.Forms.Label lblArgs; + private System.Windows.Forms.TextBox txtCmdLine; + private System.Windows.Forms.Label lblCmdLine; + private System.Windows.Forms.Label lblCharSelect; + private System.Windows.Forms.ComboBox cmbCharSelect; + private System.Windows.Forms.Label lblGameRoot; + private System.Windows.Forms.ComboBox cmbRootSelect; + private System.Windows.Forms.Label lblGamePath; + private System.Windows.Forms.TextBox txtGamePath; + private System.Windows.Forms.Button btnGamePathBrowse; + private System.Windows.Forms.FolderBrowserDialog folderBrowser; + } +} \ No newline at end of file diff --git a/Forms/Launcher.cs b/Forms/Launcher.cs new file mode 100644 index 0000000..2d2da7e --- /dev/null +++ b/Forms/Launcher.cs @@ -0,0 +1,278 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.IO; +using System.Text; +using System.Threading; +using System.Windows.Forms; + +namespace GettingUpTool.Forms +{ + public partial class Launcher : Form + { + #region Public variables + #endregion + + #region Private variables + private TextureTool _textureTool; + private LevelTool _levelTool; + private PakTool _pakTool; + + private DirectoryInfo _gamePath; + private string _gameRoot = "engine"; + private string _exePath = string.Empty; + + private Properties.Settings _settings = Properties.Settings.Default; + #endregion + + #region Constructor + public Launcher() + { + InitializeComponent(); + } + + public Launcher(TextureTool frm) + { + _textureTool = frm; + InitializeComponent(); + } + #endregion + + #region Load event + private void Launcher_Load(object sender, EventArgs e) + { + // Use current system font, rather than WinForms default font + this.Font = SystemFonts.MessageBoxFont; + + // So we can just do Encoding GetString and not worry about newlines etc. + Encoding.GetEncoding("Latin1"); + + if (!string.IsNullOrWhiteSpace(_settings.GamePath)) + { + _gamePath = new DirectoryInfo(_settings.GamePath); + } + + if (_gamePath == null || !GameFinder.ValidateGamePath(_gamePath)) + { + _gamePath = null; + + try + { + if (_textureTool != null) + _gamePath = _textureTool.GamePath; + } + catch (NullReferenceException _) { } + try + { + _gamePath = GameFinder.LocateGamePath(); + } + catch (DirectoryNotFoundException _) { + MessageBox.Show("Failed to find the game, cannot continue."); + Application.Exit(); + return; + } + + _settings.GamePath = _gamePath.FullName; + _settings.Save(); + } + + _exePath = Path.Combine(_gamePath.FullName, @"_Bin\GettingUp.exe"); + + if (!string.IsNullOrWhiteSpace(_settings.GameRoot.ToString())) + { + _gameRoot = _settings.GameRoot.ToString(); + cmbRootSelect.SelectedText = _gameRoot; + } + + // TODO: Read default_pc.cfg and vars_pc.cfg + + PopulateLevelSelect(cmbLevelSelect, _gamePath, _gameRoot); + + txtCmdLine.Text = BuildCommandLine(); + + txtGamePath.Text = _gamePath.FullName; + } + #endregion + + private string BuildCmdArg(string arg, string value) + { + if (value == string.Empty) return string.Empty; + return string.IsNullOrWhiteSpace(value) ? string.Empty : $"{arg}:\"{value}\""; + } + + private string BuildCmdArg(string arg, int value) + { + return $"{arg}:{value}"; + } + + private string BuildCommandArgs() + { + List args = new List(); + + args.Add(BuildCmdArg("game", "rhapsody")); + args.Add(BuildCmdArg("root", $"..\\{_gameRoot}")); // cmbRootSelect.SelectedIndex >= 0 ? $"..\\{cmbRootSelect.SelectedItem.ToString()}" : string.Empty)); + + /* + rnd_bones=1 + rnd_brushes=true + rnd_particleaxis=true + rnd_particlebounds=true + rnd_particles=true + rnd_portals=true + rnd_reflections=true + rnd_shadows=true + rnd_skybox=true + rnd_stripfx=true + rnd_water=true + rnd_wire=true + */ + args.Add(BuildCmdArg("map", cmbLevelSelect.SelectedIndex >= 0 ? cmbLevelSelect.SelectedItem.ToString() : string.Empty)); + args.Add(BuildCmdArg("player", cmbCharSelect.SelectedIndex >= 0 ? cmbCharSelect.SelectedItem.ToString() : string.Empty)); + + string argstr = string.Join(" ", args.ToArray()); + + if (string.IsNullOrWhiteSpace(argstr)) + argstr = txtArgs.Text.Trim(); + else + argstr = $"{argstr.Trim()} {txtArgs.Text.Trim()}"; + + return argstr; + } + + private string BuildCommandLine() + { + string exe = _exePath; + return $"\"{exe}\" {BuildCommandArgs()}".Trim(); + } + + private void btnRun_Click(object sender, EventArgs e) + { + if (chkClearAssetCache.Checked) + { + string path = Path.Combine(_gamePath.FullName, $@"{_gameRoot}\allassets.pak"); + if (File.Exists(path)) + File.Delete(path); + } + + _settings.GamePath = _gamePath.FullName; + _settings.GameRoot = _gameRoot; + _settings.Save(); + + var procGame = new Process(); + procGame.StartInfo.FileName = _exePath; + procGame.StartInfo.WorkingDirectory = Path.Combine(_gamePath.FullName, "_Bin"); + procGame.StartInfo.UseShellExecute = true; + + string args = BuildCommandArgs(); + + procGame.StartInfo.Arguments = args; + + procGame.Start(); + + /* + Thread.Sleep(2000); + + for (int timeout = 0; timeout < 20; timeout++) + { + if (GameFinder.IsGameRunning()) + Application.Exit(); + + Thread.Sleep(500); + } + */ + + Application.Exit(); + } + + private void btnGamePathBrowse_Click(object sender, EventArgs e) + { + folderBrowser.Description = "Choose the game folder. This should be the folder containing the \"_Bin\" and \"engine\" folders"; + folderBrowser.ShowNewFolderButton = false; + + DialogResult dresFindGame = folderBrowser.ShowDialog(); + + if (dresFindGame == DialogResult.OK && !string.IsNullOrWhiteSpace(folderBrowser.SelectedPath)) + { + DirectoryInfo inpath = new DirectoryInfo(folderBrowser.SelectedPath); + + if (GameFinder.ValidateGamePath(inpath)) + { + _settings.GamePath = inpath.FullName; + _settings.Save(); + txtCmdLine.Text = BuildCommandLine(); + } + else + { + this.Focus(); + MessageBox.Show("Game not found. Please try again", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + } + + private void PopulateLevelSelect(ComboBox cmbLevelSelect, DirectoryInfo gamePath, string gameRoot) + { + cmbLevelSelect.Items.Clear(); + + FileInfo[] files = gamePath.GetFiles($"{gameRoot}/Levels/*.slp", SearchOption.AllDirectories); + foreach (FileInfo file in files) + { + cmbLevelSelect.Items.Add(Path.GetFileNameWithoutExtension(file.FullName).ToLower()); + } + } + + #region Control events + private void comboBox_CmdArg_SelectionChangeCommitted(object sender, EventArgs e) + { + txtCmdLine.Text = BuildCommandLine(); + } + + private void cmbRootSelect_SelectionChangeCommitted(object sender, EventArgs e) + { + _gameRoot = cmbRootSelect.SelectedIndex >= 0 ? cmbRootSelect.SelectedItem.ToString() : string.Empty; + + if (!string.IsNullOrWhiteSpace(_gameRoot)) + { + _settings.GameRoot = _gameRoot; + _settings.Save(); + } + + PopulateLevelSelect(cmbLevelSelect, _gamePath, _gameRoot); + + comboBox_CmdArg_SelectionChangeCommitted(sender, e); + } + + private void textureToolStripMenuItem1_Click(object sender, EventArgs e) + { + if (_textureTool == null) + _textureTool = new TextureTool(); + this.Hide(); + _textureTool.ShowDialog(); + this.Show(); + } + + private void levelToolStripMenuItem_Click(object sender, EventArgs e) + { + if (_levelTool == null) + _levelTool = new LevelTool(); + this.Hide(); + _levelTool.ShowDialog(); + this.Show(); + } + + private void pakToolStripMenuItem_Click(object sender, EventArgs e) + { + if (_pakTool == null) + _pakTool = new PakTool(); + this.Hide(); + _pakTool.ShowDialog(); + this.Show(); + } + + private void helpToolStripMenuItem_Click(object sender, EventArgs e) + { + Process.Start(UI.HelpUrl); + } + #endregion + } +} diff --git a/Forms/Launcher.resx b/Forms/Launcher.resx new file mode 100644 index 0000000..99ae67d --- /dev/null +++ b/Forms/Launcher.resx @@ -0,0 +1,260 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + + + 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 + NP+LRyT/i0ck/1kuF//LaDT/y2g0/8toNP/LaDT/y2g0/8toNP8AAAD9AAAA2AAAAGkAAAAAAAAAAAAA + AAAAAAAsAAAAdwAAANEAAAD5dj0e/04oFP0AAAD5AAAA/F8xGf6PSSX/j0kl/4ZFI/9DIhH+hkUj/8to + NP/LaDT/i0ck/4tHJP9MJhP/WS4X/5FKJf+RSiX/y2g0/8toNP/LaDT/y2g0/0MiEf0AAADmAAAAkQAA + AAAAAAAAAAAAGAAAAG0AAACpAAAA9hkNB/yPSyX/j0sl/1QsFv4AAAD5hkUj/4ZFI/+GRSP/sFou/5ZN + J/98QCD/y2g0/8toNP+jUyr/y2g0/49JJf+PSyX/o1Uq/6NVKv/LaDT/gkMi/8RkMv/EZDL/AAAA/AAA + AN0AAABfAAAAAAAAAAAAAABtAAAAqQAAAOkAAAD2VCwW/49LJf/LajT/y2o0/4ZFI//LaDT/y2g0/8to + NP/LaDT/y2g0/8toNP/LaDT/y2g0/7deL/+3Xi//y2g0/8toNP+3Xy//y2g0/8toNP/EZDL/xGQy/wAA + APwAAAD2AAAAvAAAAF8AAAAAAAAAAAAAAKkAAADpAAAA9mIyGf+PSyX/y2o0/8tqNP/LajT/y2g0/8to + NP/LaDT/y2g0/8toNP+wWi7/y2g0/8toNP/LaDT/y2g0/8toNP/LaDT/y2g0/6NVKv+3Xy//t18v/8Rk + Mv9BIRH+AAAA9gAAAOoAAACGAAAANAAAAAAAAAAAAAAA0QAAAPZBIRH8YjIZ/xkNB/2PSyX/VCwW/8tq + NP/LaDT/y2g0/8toNP/LaDT/y2g0/8toNP/LaDT/y2g0/8toNP/LaDT/y2g0/8toNP/LaDT/y2g0/8to + NP/LaDT/xGQy/wAAAPwAAAD2AAAAsgAAADQAAAAAAAAAAAAAAAAAAADeQyIR/stoNP/LaDT/iUYj/8to + NP/LaDT/y2g0/8toNP+0XS//tF0v/8toNP/LaDT/y2g0/8toNP/LaDT/xmUz/8hmNP/LaDT/y2g0/8to + NP/LaDT/y2g0/8toNP9DIhH+AAAA/AAAAPMAAACUAAAASgAAAAAAAAAAAAAAAAAAAN5DIhH+y2g0/8to + NP/LaDT/y2g0/8toNP/LaDT/n1Ep/7RdL/+0XS//y2g0/8toNP/LaDT/y2g0/8toNP/GZTP/xmUz/8to + NP/LaDT/y2g0/8toNP/LaDT/j0kl/wAAAPwAAAD8AAAA/AAAAMUAAACGAAAASgAAAAAAAAAAAAAAugAA + APEAAAD7hkUj/8toNP+JRiP/SCUS/kglEv6fUSn/iUYj/7RdL//LaDT/y2g0/8toNP/LaDT/y2g0/8to + NP/EZDL/y2g0/8toNP/LaDT/y2g0/8toNP/LaDT/hkUj/gAAAPwAAAD8AAAA/AAAAM8AAACGAAAASgAA + AAAAAACAAAAAugAAAPEAAAD7BgMC+QYDAv6JRiP/SCUS/olGI/+JRiP/tF0v/8toNP/LaDT/y2g0/7de + L//LaDT/y2g0/8hmNP/IZjT/y2g0/8toNP/LaDT/y2g0/8toNP/LaDT/y2g0/4ZFI/4AAAD8AAAA+QAA + AOQAAACwAAAASgAAADAAAACAAAAAtwAAANkAAADyAAAA+gAAAPpvORz/n1Ep/3M7Hv/LaDT/y2g0/8to + NP/GZTP/vWEx/8ZlM//GZTP/y2g0/8toNP/LaDT/y2g0/8toNP/LaDT/y2g0/8toNP/LaDT/y2g0/8to + NP8AAAD8AAAA/AAAAOMAAACUAAAAAAAAADAAAAAwAAAAXAAAAKYAAADkAAAA+gAAAPpIJRL+y2g0/8to + NP/LaDT/y2g0/8toNP/LaDT/xmUz/8toNP/LaDT/y2g0/8toNP/LaDT/y2g0/8toNP/LaDT/y2g0/8to + NP/LaDT/y2g0/8toNP+GRSP/AAAA/AAAAMUAAAAAAAAAAAAAAAAAAAAwAAAAcgAAAOQAAAD6AAAA+sto + NP/LaDT/y2g0/8toNP/LaDT/y2g0/8toNP/LaDT/y2g0/8toNP/EZDL/y2g0/8toNP/LaDT/y2g0/8to + NP/LaDT/y2g0/8toNP/LaDT/y2g0/8toNP8AAAD8AAAA4wAAAAAAAAAAAAAAAAAAADAAAACmAAAA8gAA + APpvORz/y2g0/8toNP/LaDT/y2g0/8toNP/LaDT/y2g0/8toNP/LaDT/y2g0/8hmNP/LaDT/y2g0/8to + NP/LaDT/y2g0/8toNP/LaDT/y2g0/8toNP/LaDT/y2g0/wAAAPwAAADjAAAAAAAAAAAAAAAAAAAAZAAA + ANMAAAD6AAAA+stoNP/LaDT/y2g0/8toNP/LaDT/y2g0/8toNP/LaDT/y2g0/8toNP/LaDT/y2g0/8to + NP/LaDT/y2g0/8toNP/LaDT/y2g0/8toNP/LaDT/y2g0/8toNP8AAAD+AAAA+AAAAMcAAAAAAAAAAAAA + ADcAAACoAAAA8wAAAPrLaDT/y2g0/8toNP/LaDT/y2g0/8toNP/LaDT/y2g0/8toNP/LaDT/y2g0/8to + NP/LaDT/y2g0/8toNP/LaDT/y2g0/8toNP/LaDT/y2g0/8toNP/LaDT/y2g0/wAAAPgAAAD4AAAAigAA + AAAAAAAAAAAAZAAAANIAAAD6QyIR/ctoNP/LaDT/y2g0/8toNP/LaDT/y2g0/8toNP/LaDT/y2g0/8to + NP/LaDT/y2g0/8toNP/LaDT/y2g0/8toNP/LaDT/y2g0/8toNP/LaDT/y2g0/8toNP8AAAD4AAAA+AAA + AMcAAAAmAAAAAAAAAAAAAABkAAAA4AAAAPrLaDT/y2g0/8toNP/LaDT/y2g0/8toNP/LaDT/y2g0/8to + NP/LaDT/y2g0/8toNP98QiD/sFwu/8toNP/LaDT/y2g0/8toNP/LaDT/y2g0/8toNP/LaDT/aDUb/wAA + APgAAADoAAAAigAAACYAAAAAAAAAAAAAAGIAAADeAAAA+8toNP/LaDT/y2g0/8toNP/LaDT/y2g0/8to + NP/LaDT/y2g0/8toNP/LaDT/vWEx/wAAAPkAAAD5AAAA/stoNP/LaDT/y2g0/8toNP/LaDT/y2g0/8to + NP8AAAD8AAAA+QAAALAAAABKAAAAAAAAAAAAAAAAAAAAYgAAALwAAAD7AAAA+8toNP/LaDT/y2g0/8to + NP/LaDT/y2g0/8toNP/LaDT/y2g0/8toNP8AAAD5AAAA+QAAAPkAAAD5AAAA9UMiEf7LaDT/y2g0/8to + NP/LaDT/AAAA/AAAAPUAAADPAAAAhgAAAAAAAAAAAAAAAAAAAAAAAAA0AAAAhgAAAOAAAADzAAAA+0Mi + Ef7LaDT/y2g0/8toNP/LaDT/y2g0/8toNP/LaDT/BgMC/AAAAPkAAAD5AAAA1gAAANYAAAD1AAAA9QAA + APxDIhH8y2g0/4ZFI/4AAAD1AAAA5wAAAIYAAABKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0AAAAjAAA + AL8AAADzAAAA8w0EA/vLaDT/y2g0/8toNP/LaDT/y2g0/8toNP8GAwL6AAAA+QAAAKsAAABnAAAAZwAA + AKgAAADoAAAA9QAAAPUAAAD8AAAA9QAAAOcAAAClAAAASgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + ABQAAAAwAAAAfAAAAJgAAADVAAAA9wAAAPcAAAD3y2g0/8toNP/LaDT/AAAA+QAAAPkAAADVAAAAWQAA + ADAAAAAAAAAARwAAAGQAAACXAAAAvAAAAMUAAAC0AAAAigAAAE0AAAAbAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAwAAAAWQAAAHwAAAC/AAAA5QAAAPcAAAD3y2g0/8toNP8AAAD5AAAA7gAA + AJgAAAAwAAAAAAAAAAAAAAAAAAAAAAAAACYAAABHAAAATQAAAE0AAAAqAAAAKgAAAAQAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAHwAAAB8AAAAvwAAAOUAAADuAAAA7gAA + ANMAAAClAAAAWQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABAAAAB8AAAAfAAA + AKUAAAClAAAApQAAAFkAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= + + + \ No newline at end of file diff --git a/Forms/LevelTool.Designer.cs b/Forms/LevelTool.Designer.cs new file mode 100644 index 0000000..8e44f8c --- /dev/null +++ b/Forms/LevelTool.Designer.cs @@ -0,0 +1,220 @@ + +namespace GettingUpTool.Forms +{ + partial class LevelTool + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.treeGameFiles = new System.Windows.Forms.TreeView(); + this.textDebugLog = new System.Windows.Forms.TextBox(); + this.textDebugLog2 = new System.Windows.Forms.TextBox(); + this.splitContainer1 = new System.Windows.Forms.SplitContainer(); + this.splitContainer2 = new System.Windows.Forms.SplitContainer(); + this.label1 = new System.Windows.Forms.Label(); + this.textMeshes = new System.Windows.Forms.TextBox(); + this.label2 = new System.Windows.Forms.Label(); + this.textTextures = new System.Windows.Forms.TextBox(); + this.panel1 = new System.Windows.Forms.Panel(); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); + this.splitContainer1.Panel1.SuspendLayout(); + this.splitContainer1.Panel2.SuspendLayout(); + this.splitContainer1.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer2)).BeginInit(); + this.splitContainer2.Panel1.SuspendLayout(); + this.splitContainer2.Panel2.SuspendLayout(); + this.splitContainer2.SuspendLayout(); + this.SuspendLayout(); + // + // treeGameFiles + // + this.treeGameFiles.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left))); + this.treeGameFiles.Location = new System.Drawing.Point(12, 12); + this.treeGameFiles.Name = "treeGameFiles"; + this.treeGameFiles.Size = new System.Drawing.Size(240, 612); + this.treeGameFiles.TabIndex = 15; + this.treeGameFiles.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.treeGameFiles_AfterSelect); + // + // textDebugLog + // + this.textDebugLog.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textDebugLog.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.textDebugLog.Location = new System.Drawing.Point(3, 3); + this.textDebugLog.MaxLength = 3276700; + this.textDebugLog.Multiline = true; + this.textDebugLog.Name = "textDebugLog"; + this.textDebugLog.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; + this.textDebugLog.Size = new System.Drawing.Size(344, 423); + this.textDebugLog.TabIndex = 16; + this.textDebugLog.WordWrap = false; + // + // textDebugLog2 + // + this.textDebugLog2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textDebugLog2.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.textDebugLog2.Location = new System.Drawing.Point(3, 3); + this.textDebugLog2.MaxLength = 3276700; + this.textDebugLog2.Multiline = true; + this.textDebugLog2.Name = "textDebugLog2"; + this.textDebugLog2.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; + this.textDebugLog2.Size = new System.Drawing.Size(344, 419); + this.textDebugLog2.TabIndex = 17; + this.textDebugLog2.TabStop = false; + this.textDebugLog2.WordWrap = false; + // + // splitContainer1 + // + this.splitContainer1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.splitContainer1.Location = new System.Drawing.Point(614, 12); + this.splitContainer1.Name = "splitContainer1"; + this.splitContainer1.Orientation = System.Windows.Forms.Orientation.Horizontal; + // + // splitContainer1.Panel1 + // + this.splitContainer1.Panel1.Controls.Add(this.textDebugLog); + // + // splitContainer1.Panel2 + // + this.splitContainer1.Panel2.Controls.Add(this.textDebugLog2); + this.splitContainer1.Size = new System.Drawing.Size(350, 858); + this.splitContainer1.SplitterDistance = 429; + this.splitContainer1.TabIndex = 18; + // + // splitContainer2 + // + this.splitContainer2.Location = new System.Drawing.Point(258, 12); + this.splitContainer2.Name = "splitContainer2"; + this.splitContainer2.Orientation = System.Windows.Forms.Orientation.Horizontal; + // + // splitContainer2.Panel1 + // + this.splitContainer2.Panel1.Controls.Add(this.label1); + this.splitContainer2.Panel1.Controls.Add(this.textMeshes); + // + // splitContainer2.Panel2 + // + this.splitContainer2.Panel2.Controls.Add(this.label2); + this.splitContainer2.Panel2.Controls.Add(this.textTextures); + this.splitContainer2.Size = new System.Drawing.Size(350, 858); + this.splitContainer2.SplitterDistance = 429; + this.splitContainer2.TabIndex = 19; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(3, 3); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(106, 13); + this.label1.TabIndex = 1; + this.label1.Text = "Meshes used in level"; + // + // textMeshes + // + this.textMeshes.Dock = System.Windows.Forms.DockStyle.Bottom; + this.textMeshes.Location = new System.Drawing.Point(0, 23); + this.textMeshes.MaxLength = 3276700; + this.textMeshes.Multiline = true; + this.textMeshes.Name = "textMeshes"; + this.textMeshes.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; + this.textMeshes.Size = new System.Drawing.Size(350, 406); + this.textMeshes.TabIndex = 0; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(3, 3); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(110, 13); + this.label2.TabIndex = 2; + this.label2.Text = "Textures used in level"; + // + // textTextures + // + this.textTextures.Dock = System.Windows.Forms.DockStyle.Bottom; + this.textTextures.Location = new System.Drawing.Point(0, 19); + this.textTextures.MaxLength = 3276700; + this.textTextures.Multiline = true; + this.textTextures.Name = "textTextures"; + this.textTextures.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; + this.textTextures.Size = new System.Drawing.Size(350, 406); + this.textTextures.TabIndex = 1; + // + // panel1 + // + this.panel1.Location = new System.Drawing.Point(12, 630); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(240, 240); + this.panel1.TabIndex = 20; + // + // LevelTool + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(976, 881); + this.Controls.Add(this.panel1); + this.Controls.Add(this.splitContainer2); + this.Controls.Add(this.splitContainer1); + this.Controls.Add(this.treeGameFiles); + this.Name = "LevelTool"; + this.Text = "Level Tool"; + this.Load += new System.EventHandler(this.LevelTool_Load); + this.splitContainer1.Panel1.ResumeLayout(false); + this.splitContainer1.Panel1.PerformLayout(); + this.splitContainer1.Panel2.ResumeLayout(false); + this.splitContainer1.Panel2.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit(); + this.splitContainer1.ResumeLayout(false); + this.splitContainer2.Panel1.ResumeLayout(false); + this.splitContainer2.Panel1.PerformLayout(); + this.splitContainer2.Panel2.ResumeLayout(false); + this.splitContainer2.Panel2.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer2)).EndInit(); + this.splitContainer2.ResumeLayout(false); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.TreeView treeGameFiles; + private System.Windows.Forms.TextBox textDebugLog; + private System.Windows.Forms.TextBox textDebugLog2; + private System.Windows.Forms.SplitContainer splitContainer1; + private System.Windows.Forms.SplitContainer splitContainer2; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.TextBox textMeshes; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.TextBox textTextures; + private System.Windows.Forms.Panel panel1; + } +} \ No newline at end of file diff --git a/Forms/LevelTool.cs b/Forms/LevelTool.cs new file mode 100644 index 0000000..f385697 --- /dev/null +++ b/Forms/LevelTool.cs @@ -0,0 +1,363 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Runtime.InteropServices; +using System.Text; +using System.Windows.Forms; + +namespace GettingUpTool.Forms +{ + public partial class LevelTool : Form + { + #region Public variables + #endregion + + #region Private variables + private DirectoryInfo _gamePath; + private string _gameRoot = "engine"; + private string[] _targetFileExtensions = { ".slp" }; + + private Properties.Settings _settings = Properties.Settings.Default; + + private SLP slp; + private SLS sls; + #endregion + + #region Constructor + public LevelTool() + { + InitializeComponent(); + } + #endregion + + private static string StringFromByteArray(byte[] array, int index, int length) + { + return Encoding.ASCII.GetString(array, index, length).Replace('\0', ' ').Replace('\t', '?').Replace('\r', '?').Replace('\n', '?'); + } + + private static string HexLine(ref Int32 offset, ArraySegment bytes, Type type = null, string comment = "", bool show_bytes = true, bool show_chars = true) + { + string str = $"{offset:X4}"; + + if (show_bytes == true) + { + str += $"\t"; + List bstr = new List(); + for (int i = 0; i < bytes.Count; i++) + bstr.Add($"{bytes.Array[bytes.Offset + i]:X2}"); + str += string.Join(" ", bstr.ToArray()).PadRight(11); + } + + if (show_chars == true && (type == null || type.FullName != "System.String")) + { + str += $"\t"; + // List bstr = new List(); + for (int i = 0; i < bytes.Count; i++) + { + if (bytes.Offset + i >= bytes.Array.Length - 1) continue; + char chr = BitConverter.ToChar(bytes.Array, bytes.Offset + i); + if (chr < 0x20 || chr > 0x7E) chr = '.'; + str += chr; + // bstr.Add($"{bytes.Array[bytes.Offset + i]}"); + } + // str += string.Join(" ", bstr.ToArray()).PadRight(11); + } + + if (type == null) + str += $"\t{BitConverter.ToInt32(bytes.Array, bytes.Offset),12}\t{BitConverter.ToSingle(bytes.Array, bytes.Offset),12}"; + else if (type.FullName == "System.String") + str += $"\t{StringFromByteArray(bytes.Array, bytes.Offset, bytes.Count)}"; + else if (type.FullName == "System.Char") + str += $"\t{BitConverter.ToChar(bytes.Array, bytes.Offset)}"; + else if (type.FullName == "System.Int16") + str += $"\t{BitConverter.ToInt16(bytes.Array, bytes.Offset)}"; + else if (type.FullName == "System.Int32") + str += $"\t{BitConverter.ToInt32(bytes.Array, bytes.Offset)}"; + else if (type.FullName == "System.UInt16") + str += $"\t{BitConverter.ToUInt16(bytes.Array, bytes.Offset)}"; + else if (type.FullName == "System.UInt32") + str += $"\t{BitConverter.ToUInt32(bytes.Array, bytes.Offset)}"; + else if (type.FullName == "System.Single") + str += $"\t{BitConverter.ToSingle(bytes.Array, bytes.Offset)}"; + + if (comment != "") + str += $"\t{comment}"; + + str += Environment.NewLine; + + offset += bytes.Count; + + return str; + } + + private class Level + { + public bool Valid = false; + + public string Path = string.Empty; + public string FileName = string.Empty; + public int FileSize = 0; + + public byte[] Data; + + public string Name = string.Empty; + public Int32 Offset = 0; + + [Serializable] + [StructLayout(LayoutKind.Sequential, Pack = 0)] + private unsafe struct LevelFile + { + // Offsets based on m02_hoo_subway_2.slp + public Int32 Version; // 0000 + public string Header; // 0004 3DF! + public Int16 _0008; // 0008 + public Int16 _000A; // 000A + public Int32 NameLength; // 000C + public string Name; // 0010 + public UInt32 Checksum; // Checksum? + public Int32 _0048; // 1 + public Int32 _004C; // 0 + public Int32 _0050; // 1 + public Int32 _0054; + public Int32 _0058; + public Int32 _005C; + public Int32 _0060; + } + private LevelFile Struct; + + private Int16 DataReadInt16(int index) + { + byte[] bytes = new byte[2]; + Buffer.BlockCopy(Data, index, bytes, 0, 2); + return BitConverter.ToInt16(bytes, 0); + } + + private Int32 DataReadInt32(int index) + { + byte[] bytes = new byte[4]; + Buffer.BlockCopy(Data, index, bytes, 0, 4); + return BitConverter.ToInt32(bytes, 0); + } + + private UInt32 DataReadUInt32(int index) + { + byte[] bytes = new byte[4]; + Buffer.BlockCopy(Data, index, bytes, 0, 4); + return BitConverter.ToUInt32(bytes, 0); + } + + public Level(string path) + { + Path = path; + + if (!File.Exists(path)) + return; + + Valid = true; + + FileInfo fi = new FileInfo(path); + FileSize = (int)fi.Length; + FileName = fi.Name; + + Data = File.ReadAllBytes(path); + + Struct.Version = DataReadInt32(0x00); // 4 + + Struct.Header = Encoding.ASCII.GetString(Data, 0x04, 4); // 3DF! + + Struct._0008 = DataReadInt16(0x08); + Struct._000A = DataReadInt16(0x0A); + + Struct.NameLength = DataReadInt32(0x0C); + + Name = StringFromByteArray(Data, 0x10, Struct.NameLength); + + Offset = 0x10 + Struct.NameLength; + + Struct.Checksum = DataReadUInt32(Offset + 0x00); + Struct._0048 = DataReadInt32(Offset + 0x04); + Struct._004C = DataReadInt32(Offset + 0x08); + Struct._0050 = DataReadInt32(Offset + 0x0C); + } + + private static bool Equals(byte[] source, byte[] separator, int index) + { + for (int i = 0; i < separator.Length; ++i) + if (index + i >= source.Length || source[index + i] != separator[i]) + return false; + return true; + } + + private static byte[][] Separate(byte[] source, byte[] separator) + { + var Parts = new List(); + var Index = 0; + byte[] Part; + + for (var I = 0; I < source.Length; ++I) + { + if (Equals(source, separator, I)) + { + Part = new byte[I - Index]; + Array.Copy(source, Index, Part, 0, Part.Length); + Parts.Add(Part); + Index = I + separator.Length; + I += separator.Length - 1; + } + } + + Part = new byte[source.Length - Index]; + Array.Copy(source, Index, Part, 0, Part.Length); + Parts.Add(Part); + + return Parts.ToArray(); + } + + public string Analyze() + { + if (!Valid) + return string.Empty; + + string output = string.Empty; + int offset = 0; + + output += $"File\t{FileName}" + Environment.NewLine; + output += $"FSize\t{FileSize} / {FileSize.ToString("X")}" + Environment.NewLine; + + output += $"Version\t{Struct.Version}" + Environment.NewLine; + output += $"Header\t{Struct.Header}" + Environment.NewLine; + output += $"Name\t{Name}" + Environment.NewLine; + + output += Environment.NewLine; + + output += $"{Offset:X4}\t{Struct.Checksum:X4}\t{Struct.Checksum}" + Environment.NewLine; + + System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); + sw.Start(); + for (offset = Offset + 4; offset < FileSize / 4;) + { + if (FileSize - offset < 4) + break; + else + output += HexLine(ref offset, new ArraySegment(Data, offset, 4)); + } + sw.Stop(); + output += Environment.NewLine + $"{sw.Elapsed.TotalSeconds}"; + + output += Environment.NewLine; + + return output; + /////////////////////////////////////////////////////////////// + + // TODO: Read the entire file and split by 0xFFFF + // ArraySegment(Data, offset, 4); + byte[] splitter = { 0xFF, 0xFF }; + var segments = Separate(Data, splitter); + + output += $"Segs.\t{segments.Length}" + Environment.NewLine; + + offset = Offset; + for (int n = 1; n < segments.Length; n++) + { + output += $"{offset:X4}"; + output += $"\t"; + + List bstr = new List(); + + int i = 0; + for (i = 0; i < segments[n].Length; i++) + bstr.Add($"{segments[n][i]:X2}"); + offset += segments[n].Length; + + output += string.Join(" ", bstr.ToArray()).PadRight(11); + + output += Environment.NewLine; + } + + return output; + } + } + + private class SLS : Level + { + public SLS(string path) : base(path) { } + } + + private class SLP : Level + { + public SLP(string path) : base(path) { } + } + + private void LevelTool_Load(object sender, EventArgs e) + { + // Use current system font, rather than WinForms default font + this.Font = SystemFonts.MessageBoxFont; + + // So we can just do Encoding GetString and not worry about newlines etc. + Encoding.GetEncoding("Latin1"); + + if (!string.IsNullOrWhiteSpace(_settings.GamePath)) + { + _gamePath = new DirectoryInfo(_settings.GamePath); + } + + if (!string.IsNullOrWhiteSpace(_settings.GameRoot)) + { + _gameRoot = _settings.GameRoot; + } + + DirectoryInfo levelsDir = new DirectoryInfo(Path.Combine(_gamePath.FullName, $@"{_gameRoot}\Levels")); + + treeGameFiles.SuspendLayout(); + treeGameFiles.Nodes.Clear(); + foreach (FileInfo file in levelsDir.GetFiles("*.slp", SearchOption.AllDirectories)) + { + treeGameFiles.Nodes.Add(file.FullName, file.FullName.Replace(levelsDir.FullName, "")); + } + treeGameFiles.SelectedNode = null; + treeGameFiles.ResumeLayout(); + } + + // + // Load level from file + // + private bool LoadLevel(string path) + { + FileInfo fileInfo = new FileInfo(path); + + string pathNoExt = Path.Combine(fileInfo.DirectoryName, fileInfo.Name); + + slp = new SLP(path); + sls = new SLS(Path.ChangeExtension(path, ".sls")); + + textDebugLog.Text = slp.Analyze(); + // textDebugLog2.Text = sls.Analyze(); + + textMeshes.Text = ""; + textTextures.Text = ""; + + return true; + } + + // + // Load selected file when selecting in the tree view + // + bool firstRun = true; + private void treeGameFiles_AfterSelect(object sender, TreeViewEventArgs e) + { + if (firstRun) + { + firstRun = false; + return; + } + + string path = treeGameFiles.SelectedNode.Name; + + if (string.IsNullOrWhiteSpace(path) || !File.Exists(path)) + return; + + LoadLevel(path); + } + } +} diff --git a/Forms/LevelTool.resx b/Forms/LevelTool.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/Forms/LevelTool.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Forms/PakTool.Designer.cs b/Forms/PakTool.Designer.cs new file mode 100644 index 0000000..03d7d57 --- /dev/null +++ b/Forms/PakTool.Designer.cs @@ -0,0 +1,48 @@ + +namespace GettingUpTool.Forms +{ + partial class PakTool + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.SuspendLayout(); + // + // PakViewer + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(800, 450); + this.Name = "PakViewer"; + this.Text = "PAK Viewer"; + this.Load += new System.EventHandler(this.PakViewer_Load); + this.ResumeLayout(false); + + } + + #endregion + } +} \ No newline at end of file diff --git a/Forms/PakTool.cs b/Forms/PakTool.cs new file mode 100644 index 0000000..3dce8e9 --- /dev/null +++ b/Forms/PakTool.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace GettingUpTool.Forms +{ + public partial class PakTool : Form + { + #region Public variables + #endregion + + #region Private variables + private TextureTool _mainForm; + private DirectoryInfo _gamePath; + #endregion + + #region Constructor + public PakTool() + { + InitializeComponent(); + } + + public PakTool(TextureTool frm) + { + _mainForm = frm; + InitializeComponent(); + } + #endregion + + private void PakViewer_Load(object sender, EventArgs e) + { + // Use current system font, rather than WinForms default font + this.Font = SystemFonts.MessageBoxFont; + + // So we can just do Encoding GetString and not worry about newlines etc. + Encoding.GetEncoding("Latin1"); + + if (_gamePath == null) + { + try + { + if (_mainForm != null) + _gamePath = _mainForm.GamePath; + } + catch (NullReferenceException _) { } + try + { + _gamePath = GameFinder.LocateGamePath(); + } + catch (DirectoryNotFoundException _) { } + } + + if (_gamePath != null) { + string path = Path.Combine(_gamePath.FullName, @"engine\allassets.pak"); + byte[] data = File.ReadAllBytes(path); + } + } + } +} diff --git a/Forms/PakTool.resx b/Forms/PakTool.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/Forms/PakTool.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Forms/TextureTool.Designer.cs b/Forms/TextureTool.Designer.cs index 2df40f7..dc4e45d 100644 --- a/Forms/TextureTool.Designer.cs +++ b/Forms/TextureTool.Designer.cs @@ -1,4 +1,4 @@ -namespace GettingUpTool +namespace GettingUpTool.Forms { partial class TextureTool { @@ -55,6 +55,8 @@ private void InitializeComponent() this.panelDebug = new System.Windows.Forms.Panel(); this.comboDXTOverride = new System.Windows.Forms.ComboBox(); this.textTextureName = new System.Windows.Forms.TextBox(); + this.chkTreeViewFlat = new System.Windows.Forms.CheckBox(); + this.btnRefreshTreeView = new System.Windows.Forms.Button(); ((System.ComponentModel.ISupportInitialize)(this.picAlpha)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.picRGB)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.picPixelColor)).BeginInit(); @@ -137,7 +139,7 @@ private void InitializeComponent() | System.Windows.Forms.AnchorStyles.Left))); this.treeGameFiles.Location = new System.Drawing.Point(12, 9); this.treeGameFiles.Name = "treeGameFiles"; - this.treeGameFiles.Size = new System.Drawing.Size(214, 720); + this.treeGameFiles.Size = new System.Drawing.Size(214, 694); this.treeGameFiles.TabIndex = 14; this.treeGameFiles.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.treeGameFiles_AfterSelect); // @@ -321,11 +323,37 @@ private void InitializeComponent() this.textTextureName.Size = new System.Drawing.Size(200, 20); this.textTextureName.TabIndex = 45; // + // chkTreeViewFlat + // + this.chkTreeViewFlat.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.chkTreeViewFlat.AutoSize = true; + this.chkTreeViewFlat.Location = new System.Drawing.Point(12, 710); + this.chkTreeViewFlat.Name = "chkTreeViewFlat"; + this.chkTreeViewFlat.Size = new System.Drawing.Size(58, 17); + this.chkTreeViewFlat.TabIndex = 46; + this.chkTreeViewFlat.Text = "Flatten"; + this.chkTreeViewFlat.UseVisualStyleBackColor = true; + this.chkTreeViewFlat.CheckedChanged += new System.EventHandler(this.chkTreeViewFlat_CheckedChanged); + // + // btnRefreshTreeView + // + this.btnRefreshTreeView.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.btnRefreshTreeView.Font = new System.Drawing.Font("Segoe UI Symbol", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.btnRefreshTreeView.Location = new System.Drawing.Point(202, 705); + this.btnRefreshTreeView.Name = "btnRefreshTreeView"; + this.btnRefreshTreeView.Size = new System.Drawing.Size(24, 24); + this.btnRefreshTreeView.TabIndex = 47; + this.btnRefreshTreeView.Text = "🔃"; + this.btnRefreshTreeView.UseVisualStyleBackColor = true; + this.btnRefreshTreeView.Click += new System.EventHandler(this.btnRefreshTreeView_Click); + // // TextureTool // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(1136, 741); + this.Controls.Add(this.btnRefreshTreeView); + this.Controls.Add(this.chkTreeViewFlat); this.Controls.Add(this.textTextureName); this.Controls.Add(this.comboDXTOverride); this.Controls.Add(this.panelDebug); @@ -390,6 +418,8 @@ private void InitializeComponent() private System.Windows.Forms.Panel panelDebug; private System.Windows.Forms.ComboBox comboDXTOverride; private System.Windows.Forms.TextBox textTextureName; + private System.Windows.Forms.CheckBox chkTreeViewFlat; + private System.Windows.Forms.Button btnRefreshTreeView; } } diff --git a/Forms/TextureTool.cs b/Forms/TextureTool.cs index 2364fe1..6f88f41 100644 --- a/Forms/TextureTool.cs +++ b/Forms/TextureTool.cs @@ -1,4 +1,5 @@ -using System; +using MonoGame; +using System; using System.Diagnostics; using System.Drawing; using System.Drawing.Drawing2D; @@ -8,7 +9,7 @@ using System.Text.RegularExpressions; using System.Windows.Forms; -namespace GettingUpTool +namespace GettingUpTool.Forms { public partial class TextureTool : Form { @@ -17,32 +18,16 @@ public TextureTool() InitializeComponent(); } + #region Public variables + public DirectoryInfo GamePath; + #endregion + #region Private variables - private string _gamePath; private Texture _texture; private Bitmap bmpAlpha, bmpRGB; - private string _githubUrl = "https://github.com/Asbra/GettingUpTool"; - private string _helpUrl = "https://github.com/Asbra/GettingUpTool/wiki/Replacing-textures-graffiti-in-Marc-Ecko%27s-Getting-Up"; - #endregion - - private void BuildTree(DirectoryInfo directoryInfo, TreeNodeCollection addInMe) - { - TreeNode curNode = addInMe.Add(directoryInfo.Name); - - foreach (FileInfo file in directoryInfo.GetFiles()) - { - string filext = file.Extension.ToLower(); - if (filext == ".st") // || filext == ".bir" || filext == ".dds" || filext == ".st2") - { - curNode.Nodes.Add(file.FullName, file.Name); - } - } - foreach (DirectoryInfo subdir in directoryInfo.GetDirectories()) - { - BuildTree(subdir, curNode.Nodes); - } - } + private string[] _targetFileExtensions = { ".st", ".stx", ".dds" }; + #endregion #region Texture functions // @@ -73,27 +58,31 @@ private bool LoadTexture(string path) // // Get file information // - // @TODO: Fix this inheritance + // TODO: Fix this inheritance _texture = new Texture(path); - if (_texture.Type == TextureType.ST) - { - _texture = new ST(path);// _texture.Data); - } - else if (_texture.Type == TextureType.ST2) - { - _texture = new ST2(path);//_texture.Data); - } - else if (_texture.Type == TextureType.DDS) - { - _texture = new DDS(path);//_texture.Data); - } - else + try { - // Other file extension - MessageBox.Show("Unknown file format", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information); - return false; + if (_texture.Type == TextureType.ST) + { + _texture = new ST(path);// _texture.Data); + } + else if (_texture.Type == TextureType.ST2) + { + _texture = new ST2(path);//_texture.Data); + } + else if (_texture.Type == TextureType.DDS) + { + _texture = new DDS(path);//_texture.Data); + } + else + { + // Other file extension + MessageBox.Show("Unknown file format", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information); + return false; + } } + catch (Exception _) { MessageBox.Show(_.ToString()); } // Debug output if (chkDebug.Checked) @@ -128,7 +117,7 @@ private bool LoadTexture(string path) } else { - compression = "Unknown"; + compression = ""; } string textureFormat = $"DDS {compression}"; @@ -162,7 +151,7 @@ private void TextureTool_Load(object sender, EventArgs e) DirectoryInfo path = null; - // @TODO: Implement a config file + // TODO: Implement a config file try { @@ -211,22 +200,16 @@ private void TextureTool_Load(object sender, EventArgs e) { if (path != null && path.Exists) { - _gamePath = path.FullName; - openFileDialog.InitialDirectory = _gamePath; + GamePath = path; + openFileDialog.InitialDirectory = GamePath.FullName; - BuildTree(path, treeGameFiles.Nodes); - if (treeGameFiles.Nodes.Count > 0) - { - treeGameFiles.Nodes[0].Expand(); - if (treeGameFiles.Nodes[0].Nodes.Count > 0) - treeGameFiles.Nodes[0].Nodes[0].Expand(); - } + UI.RebuildFileTree(GamePath, treeGameFiles.Nodes, _targetFileExtensions); } else throw new DirectoryNotFoundException(); } catch (Exception ex) { - MessageBox.Show($"Invalid game folder, please report the following error at {_githubUrl}/issues" + Environment.NewLine + ex.ToString()); + MessageBox.Show($"Invalid game folder, please report the following error at {UI.GithubUrl}/issues" + Environment.NewLine + ex.ToString()); } } @@ -252,7 +235,7 @@ private void UpdatePreviews() if (_texture.DXT > 0) { - // @TODO: Detect file format + // TODO: Detect file format byte[] ddsBytes = null; if (_texture.Type == TextureType.ST) { @@ -282,7 +265,21 @@ private void UpdatePreviews() Array.Copy(_texture.Data, TextureUtil.DDS_HEADER_SIZE, ddsBytes, 0, _texture.Data.Length - TextureUtil.DDS_HEADER_SIZE); } - byte[] bmpBytes = _texture.DXT == 1 ? DxtUtil.DecompressDxt1(ddsBytes, _texture.Width, _texture.Height) : (_texture.DXT >= 4 ? DxtUtil.DecompressDxt5(ddsBytes, _texture.Width, _texture.Height) : DxtUtil.DecompressDxt3(ddsBytes, _texture.Width, _texture.Height)); + byte[] bmpBytes = null; + switch (_texture.DXT) + { + case 1: + bmpBytes = DxtUtil.DecompressDxt1(ddsBytes, _texture.Width, _texture.Height); + break; + case 3: + bmpBytes = DxtUtil.DecompressDxt3(ddsBytes, _texture.Width, _texture.Height); + break; + case 5: + bmpBytes = DxtUtil.DecompressDxt5(ddsBytes, _texture.Width, _texture.Height); + break; + default: + throw new ArgumentException($"Unsupported texture compression DXT{_texture.DXT}"); + } int idx = 0; for (int y = 0; y < _texture.Height; y++) @@ -303,6 +300,31 @@ private void UpdatePreviews() } } } + else + { + // Uncompressed RGB data + int idx = 0; + for (int y = 0; y < _texture.Height; y++) + { + for (int x = 0; x < _texture.Width; x++) + { + byte r = _texture.Pixels[idx + 0]; + byte g = _texture.Pixels[idx + 1]; + byte b = _texture.Pixels[idx + 2]; + byte a = _texture.Pixels[idx + 3]; + Color color = Color.FromArgb(a, r, g, b); + + bmpRGB.SetPixel(x, y, color); + + bmpAlpha.SetPixel(x, y, Color.FromArgb(a, 255, 255, 255)); + + idx += 4; + } + } + + // buttonExportTexture.Enabled = true; + // buttonReplaceTexture.Enabled = true; + } picAlpha.Image = bmpAlpha; picRGB.Image = bmpRGB; @@ -470,7 +492,7 @@ private void linkFile_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e if (string.IsNullOrWhiteSpace(path) || !File.Exists(path)) return; - Process.Start("explorer.exe", $"/select,\"{path}\""); + // Process.Start("explorer.exe", $"/select,\"{path}\""); } // @@ -551,6 +573,14 @@ private void buttonReplaceTexture_Click(object sender, EventArgs e) File.Move(_texture.Path, _texture.Path + filext); } + if (_texture.Type == TextureType.ST) + { + // ((ST)_texture).Width + } + else + { + } + // Replace texture data in memory for (int i = TextureUtil.DDS_HEADER_SIZE; i < fileBytes.Length; i++) { @@ -579,23 +609,11 @@ private void buttonExportTexture_Click(object sender, EventArgs e) switch (saveFileDialog.FilterIndex) { case 1: // DDS - try - { - byte[] outBytes = TextureUtil.STtoDDS(_texture.Data); + byte[] outBytes = TextureUtil.STtoDDS(_texture.Data); - using (Stream fileStream = saveFileDialog.OpenFile()) - { - fileStream.Write(outBytes, 0, outBytes.Length); - } - - // Write metadata to other file - // @NOTE: We shouldn't need this anymore - // string pathOutMetadata = Path.Combine(Path.GetDirectoryName(_texture.Path), Path.GetFileNameWithoutExtension(_texture.Path) + ".dat"); - // File.WriteAllBytes(pathOutMetadata, TextureConversion.STmetadata(_texture.Data)); - } - catch (Exception) + using (Stream fileStream = saveFileDialog.OpenFile()) { - throw; + fileStream.Write(outBytes, 0, outBytes.Length); } break; case 2: // PNG @@ -632,12 +650,24 @@ private void chkDebug_CheckedChanged(object sender, EventArgs e) // private void linkGithub_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) { - Process.Start(_githubUrl); + Process.Start(UI.GithubUrl); } private void linkReadme_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) { - Process.Start(_helpUrl); + Process.Start(UI.HelpUrl); + } + #endregion + + #region Controls for the tree view + private void chkTreeViewFlat_CheckedChanged(object sender, EventArgs e) + { + UI.RebuildFileTree(GamePath, treeGameFiles.Nodes, _targetFileExtensions, chkTreeViewFlat.Checked); + } + + private void btnRefreshTreeView_Click(object sender, EventArgs e) + { + UI.RebuildFileTree(GamePath, treeGameFiles.Nodes, _targetFileExtensions); } #endregion } diff --git a/GettingUpTool.csproj b/GettingUpTool.csproj index c87700a..6d70c3a 100644 --- a/GettingUpTool.csproj +++ b/GettingUpTool.csproj @@ -36,6 +36,7 @@ DEBUG;TRACE prompt 4 + true AnyCPU @@ -45,6 +46,7 @@ TRACE prompt 4 + true Resources\GettingUp.ico @@ -62,6 +64,24 @@ + + Form + + + Launcher.cs + + + Form + + + LevelTool.cs + + + Form + + + PakTool.cs + True @@ -77,8 +97,18 @@ - + + + + Launcher.cs + + + LevelTool.cs + + + PakTool.cs + TextureTool.cs diff --git a/Textures/MonoGame-DxtUtil.cs b/MonoGame/DxtUtil.cs similarity index 99% rename from Textures/MonoGame-DxtUtil.cs rename to MonoGame/DxtUtil.cs index 8a342d0..c2f035f 100644 --- a/Textures/MonoGame-DxtUtil.cs +++ b/MonoGame/DxtUtil.cs @@ -41,7 +41,7 @@ using System; using System.IO; -namespace GettingUpTool +namespace MonoGame { internal static class DxtUtil { diff --git a/Program.cs b/Program.cs index 45949e3..f9ee558 100644 --- a/Program.cs +++ b/Program.cs @@ -1,10 +1,7 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; using System.Windows.Forms; -namespace GettingUpTool +namespace GettingUpTool.Forms { static class Program { @@ -14,9 +11,19 @@ static class Program [STAThread] static void Main() { + while (GameFinder.IsGameRunning()) + { + DialogResult res = MessageBox.Show("Game is already running!\r\nClose game and press OK to continue.", "MEGU Launcher", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning); + if (res != DialogResult.OK) + { + Application.Exit(); + return; + } + } + Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); - Application.Run(new TextureTool()); + Application.Run(new Launcher()); } } } diff --git a/Properties/Settings.Designer.cs b/Properties/Settings.Designer.cs index 82b8b72..9aba07c 100644 --- a/Properties/Settings.Designer.cs +++ b/Properties/Settings.Designer.cs @@ -1,7 +1,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.18408 +// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -12,7 +12,7 @@ namespace GettingUpTool.Properties { [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.10.0.0")] internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); @@ -22,5 +22,29 @@ public static Settings Default { return defaultInstance; } } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string GamePath { + get { + return ((string)(this["GamePath"])); + } + set { + this["GamePath"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("engine")] + public string GameRoot { + get { + return ((string)(this["GameRoot"])); + } + set { + this["GameRoot"] = value; + } + } } } diff --git a/Properties/Settings.settings b/Properties/Settings.settings index 3964565..4a2a64c 100644 --- a/Properties/Settings.settings +++ b/Properties/Settings.settings @@ -1,7 +1,12 @@  - - - - - - + + + + + + + + engine + + + \ No newline at end of file diff --git a/Resources/GettingUp.png b/Resources/GettingUp.png new file mode 100644 index 0000000..5ba411d Binary files /dev/null and b/Resources/GettingUp.png differ diff --git a/Screenshots/01.jpg b/Screenshots/01.jpg new file mode 100644 index 0000000..46e74a6 Binary files /dev/null and b/Screenshots/01.jpg differ diff --git a/Screenshots/02.jpg b/Screenshots/02.jpg new file mode 100644 index 0000000..d8a9607 Binary files /dev/null and b/Screenshots/02.jpg differ diff --git a/Screenshots/03.jpg b/Screenshots/03.jpg new file mode 100644 index 0000000..b1888da Binary files /dev/null and b/Screenshots/03.jpg differ diff --git a/Screenshots/04.jpg b/Screenshots/04.jpg new file mode 100644 index 0000000..dc3a241 Binary files /dev/null and b/Screenshots/04.jpg differ diff --git a/Screenshots/05.jpg b/Screenshots/05.jpg new file mode 100644 index 0000000..f9b0d95 Binary files /dev/null and b/Screenshots/05.jpg differ diff --git a/Textures/TextureUtil.cs b/Textures/TextureUtil.cs index 5a4444e..69aeb3f 100644 --- a/Textures/TextureUtil.cs +++ b/Textures/TextureUtil.cs @@ -21,6 +21,7 @@ public class Texture public const int ST_TEXTURE_OFFSET = 0x184; public byte[] Data; + public byte[] Pixels; public string Path = string.Empty; public string FileName = string.Empty; @@ -33,6 +34,284 @@ public class Texture public int DXT = 0; public int Width = 0; public int Height = 0; + public int AlphaBitDepth = 0; + + public static T BytesToStructure(byte[] bytes) + { + int size = Marshal.SizeOf(typeof(T)); + if (bytes.Length < size) + throw new ArgumentException("Invalid parameter"); + + IntPtr ptr = IntPtr.Zero; + try + { + ptr = Marshal.AllocHGlobal(size); + + Marshal.Copy(bytes, 0, ptr, size); + + return (T)Marshal.PtrToStructure(ptr, typeof(T)); + } + finally + { + Marshal.FreeHGlobal(ptr); + } + } + + public static byte[] StructureToBytes(T structure) + { + int size = Marshal.SizeOf(typeof(T)); + byte[] bytes = new byte[size]; + + IntPtr ptr = IntPtr.Zero; + try + { + ptr = Marshal.AllocHGlobal(size); + + // Marshal.StructureToPtr(structure, ptr, false); + Marshal.Copy(ptr, bytes, 0, size); + } + finally + { + Marshal.FreeHGlobal(ptr); + } + + return bytes; + } + + [Serializable] + [StructLayout(LayoutKind.Sequential, Pack = 0)] + public unsafe struct DDS_PIXELFORMAT + { + public Int32 dwSize; + public Int32 dwFlags; + public Int32 dwFourCC; + public Int32 dwRGBBitCount; + public Int32 dwRBitMask; + public Int32 dwGBitMask; + public Int32 dwBBitMask; + public Int32 dwABitMask; + } + + [Serializable] + [StructLayout(LayoutKind.Sequential, Pack = 0)] + public unsafe struct DDSfile + { + public fixed char DDS[4]; // 0000 + public Int32 dwSize; // 0004 + public Int32 dwFlags; // 0008 + public Int32 dwHeight; // 000C + public Int32 dwWidth; // 0010 + public Int32 dwPitchOrLinearSize; // 0014 + public Int32 dwDepth; // 0018 + public Int32 dwMipMapCount; // 001C + public fixed Int32 dwReserved[11]; // 0020 + public DDS_PIXELFORMAT PixelFormat; // 0x004C + public Int32 dwCaps; // 006C + public Int32 dwCaps2; + public Int32 dwCaps3; + public Int32 dwCaps4; + public Int32 dwReserved2; + public byte[] Texture; // 0080 + } + + [Serializable] + [StructLayout(LayoutKind.Sequential, Pack = 0)] + public unsafe struct STfile + { + public fixed char ST[4]; // 0000 + public Int32 _0004 { get; set; } + public Int32 Compression { get; set; } // 0008 + public Int32 Width { get; set; } // 000C + public Int32 Height { get; set; } // 0010 + public Int32 Width2 { get; set; } // 0014 + public Int32 Height2 { get; set; } // 0018 + public Int32 _001C { get; set; } // 001C + public Int32 _0020 { get; set; } // 0020 + public Int32 _0024 { get; set; } // 0024 + public Int32 _0028 { get; set; } // 0028 + public Int32 _002C { get; set; } // 002C + public Int32 _0030 { get; set; } // 0030 + public Int32 DdsSize { get; set; } // 0034 + public Int32 _0038 { get; set; } // 0038 + public Int32 Unknown { get; set; } // 003C + public fixed char Name[32]; // 0040 + public Int32 _0060 { get; set; } // 0060 + public Int32 _0064 { get; set; } // 0064 + public Int32 _0068 { get; set; } // 0068 + public Int32 _006C { get; set; } // 006C + public Int32 _0070 { get; set; } // 0070 + public Int32 _0074 { get; set; } // 0074 + public Int32 _0078 { get; set; } // 0078 + public Int32 _007C { get; set; } // 007C + public Int32 _0080 { get; set; } // 0080 + public Int32 DdsSize2 { get; set; } // 0084 + public Int32 _0088 { get; set; } // 0088 + public Int32 DdsSize3 { get; set; } // 008C + public Int32 DdsSize4 { get; set; } // 0090 + public Int32 _0094 { get; set; } // 0094 + public Int32 _0098 { get; set; } // 0098 + public Int32 _009C { get; set; } // 009C + public Int32 _00A0 { get; set; } // 00A0 + public Int32 _00A4 { get; set; } // 00A4 + public Int32 _00A8 { get; set; } // 00A8 + public Int32 _00AC { get; set; } // 00AC + public Int32 _00B0 { get; set; } // 00B0 + public Int32 _00B4 { get; set; } // 00B4 + public Int32 _00B8 { get; set; } // 00B8 + public Int32 _00BC { get; set; } // 00BC + public Int32 _00C0 { get; set; } // 00C0 + public Int32 _00C4 { get; set; } // 00C4 + public Int32 _00C8 { get; set; } // 00C8 + public Int32 _00CC { get; set; } // 00CC + public Int32 _00D0 { get; set; } // 00D0 + public Int32 _00D4 { get; set; } // 00D4 + public Int32 _00D8 { get; set; } // 00D8 + public Int32 _00DC { get; set; } // 00DC + public Int32 _00E0 { get; set; } // 00E0 + public Int32 _00E4 { get; set; } // 00E4 + public Int32 _00E8 { get; set; } // 00E8 + public Int32 _00EC { get; set; } // 00EC + public Int32 _00F0 { get; set; } // 00F0 + public Int32 _00F4 { get; set; } // 00F4 + public Int32 _00F8 { get; set; } // 00F8 + public Int32 _00FC { get; set; } // 00FC + public Int32 _0100 { get; set; } // 0100 + public fixed char BIR[4]; // 0104 + public Int32 _0108 { get; set; } // 0108 + public Int32 _010C { get; set; } // 010C + public Int32 _0110 { get; set; } // 0110 + public Int32 _0114 { get; set; } // 0114 + public Int32 _0118 { get; set; } // 0118 + public Int32 _011C { get; set; } // 011C + public Int32 _0120 { get; set; } // 0120 + public Int32 _0124 { get; set; } // 0124 + public Int32 _0128 { get; set; } // 0128 + public Int32 _012C { get; set; } // 012C + public Int32 _0130 { get; set; } // 0130 + public Int32 _0134 { get; set; } // 0134 + public Int32 _0138 { get; set; } // 0138 + public Int32 _013C { get; set; } // 013C + public Int32 _0140 { get; set; } // 0140 + public Int32 _0144 { get; set; } // 0144 + public Int32 _0148 { get; set; } // 0148 + public Int32 _014C { get; set; } // 014C + public Int32 _0150 { get; set; } // 0150 + public Int32 _0154 { get; set; } // 0154 + public Int32 _0158 { get; set; } // 0158 + public Int32 _015C { get; set; } // 015C + public Int32 _0160 { get; set; } // 0160 + public Int32 _0164 { get; set; } // 0164 + public Int32 _0168 { get; set; } // 0168 + public Int32 _016C { get; set; } // 016C + public Int32 _0170 { get; set; } // 0170 + public Int32 _0174 { get; set; } // 0174 + public Int32 _0178 { get; set; } // 0178 + public Int32 _017C { get; set; } // 017C + public Int32 _0180 { get; set; } // 0180 + public byte[] Texture { get; set; } // 0184 + } + + public static DDSfile DdsFromBytes(byte[] bytes) + { + int size = Marshal.SizeOf(typeof(DDSfile)); + if (bytes.Length < size) + throw new ArgumentException("Invalid parameter"); + + DDSfile result = new DDSfile(); + IntPtr ptr = IntPtr.Zero; + + try + { + ptr = Marshal.AllocHGlobal(size); + + Marshal.Copy(bytes, 0, ptr, size); + + var dataSize = bytes.Length - size; + result.Texture = new byte[dataSize]; + Array.Copy(bytes, size, result.Texture, 0, dataSize); + + return result; + } + finally + { + Marshal.FreeHGlobal(ptr); + } + } + + public static byte[] DdsToBytes(DDSfile structure) + { + int size = Marshal.SizeOf(typeof(DDSfile)); + byte[] bytes = new byte[size + structure.Texture.Length]; + + IntPtr ptr = IntPtr.Zero; + try + { + ptr = Marshal.AllocHGlobal(size); + + // Marshal.StructureToPtr(structure, ptr, false); + Marshal.Copy(ptr, bytes, 0, size); + + var dataSize = bytes.Length - size; + Array.Copy(structure.Texture, 0, bytes, size, structure.Texture.Length); + } + finally + { + Marshal.FreeHGlobal(ptr); + } + + return bytes; + } + + public static STfile StFromBytes(byte[] bytes) + { + int size = Marshal.SizeOf(typeof(STfile)); + if (bytes.Length < size) + throw new ArgumentException("Invalid parameter"); + + STfile result = new STfile(); + IntPtr ptr = IntPtr.Zero; + + try + { + ptr = Marshal.AllocHGlobal(size); + + Marshal.Copy(bytes, 0, ptr, size); + + var dataSize = bytes.Length - size; + result.Texture = new byte[dataSize]; + Array.Copy(bytes, size, result.Texture, 0, dataSize); + + return result; + } + finally + { + Marshal.FreeHGlobal(ptr); + } + } + + public static byte[] StToBytes(STfile structure) + { + int size = Marshal.SizeOf(typeof(STfile)); + byte[] bytes = new byte[size + structure.Texture.Length]; + + IntPtr ptr = IntPtr.Zero; + try + { + ptr = Marshal.AllocHGlobal(size); + + // Marshal.StructureToPtr(structure, ptr, false); + Marshal.Copy(ptr, bytes, 0, size); + + var dataSize = bytes.Length - size; + Array.Copy(structure.Texture, 0, bytes, size, structure.Texture.Length); + } + finally + { + Marshal.FreeHGlobal(ptr); + } + + return bytes; + } public Texture(string path) { @@ -78,25 +357,6 @@ public virtual void Initialize() break; default: break; } - - /* - if (HeaderString == "ST2") // fileBytes[0] == 'S' && fileBytes[1] == 'T' && fileBytes[2] == '2') - { - Type = TextureType.ST2; - } - else if (fileBytes[0] == 'S' && fileBytes[1] == 'T') - { - Type = TextureType.ST; - } - else if (fileBytes[0] == 'B' && fileBytes[1] == 'I' && fileBytes[2] == 'R') - { - Type = TextureType.BIR; - } - else if (fileBytes[0] == 'D' && fileBytes[1] == 'D' && fileBytes[2] == 'S') - { - Type = TextureType.DDS; - } - */ } } @@ -106,6 +366,8 @@ public ST(string path) : base(path) { } public ST(byte[] fileBytes) : base(fileBytes) { } + public STfile Struct; + public override void Initialize() { base.Initialize(); @@ -115,15 +377,23 @@ public override void Initialize() Name += (char)Data[i]; } - Width = Data[0xC] | Data[0xD] << 8 | Data[0xE] << 16 | Data[0xF] << 24; - Height = Data[0x10] | Data[0x11] << 8 | Data[0x12] << 16 | Data[0x13] << 24; + Width = BitConverter.ToInt32(Data, 0x0C); // Data[0xC] | Data[0xD] << 8 | Data[0xE] << 16 | Data[0xF] << 24; + Height = BitConverter.ToInt32(Data, 0x10); // Data[0x10] | Data[0x11] << 8 | Data[0x12] << 16 | Data[0x13] << 24; + + int textureLength = BitConverter.ToInt32(Data, 0x34); + int birOffset = Data.Length - textureLength; + int textureOffset = birOffset + 0x80; + int pixelsSize = Data.Length - textureOffset; + + Pixels = new byte[pixelsSize]; + Array.Copy(Data, textureOffset, Pixels, 0, pixelsSize); - // DXT = Data[0x1C] > 0 ? 5 : 1; - // DXT = Data[0x1C] == 0 ? 1 : Data[0x1C]; + Struct = StFromBytes(Data); + /* byte[] fmtNibble = { (byte)((Data[0x3C] & 0xF0) >> 4), (byte)(Data[0x3C] & 0x0F) }; // Second nibble is 0=DXT1, 1=DXT3?, 2=DXT5 - // First nibble ?? 1 offset image, 4 used in DXT1, 5/6 used in DXT5 + // First nibble ?? 1 offset image?, 4 used in DXT1, 5/6 used in DXT5 if (fmtNibble[1] == 0) { @@ -137,9 +407,19 @@ public override void Initialize() { DXT = 5; } - else + */ + switch (Data[0x08]) { - throw new FormatException($"Unknown texture compression {Data[0x3C]:X2}"); + case 3: + DXT = 1; + break; + case 4: + DXT = 5; + break; + default: + DXT = 0; + break; + // throw new FormatException($"Unknown texture compression {Data[0x08]:X2}"); } } } @@ -162,25 +442,16 @@ public override void Initialize() Width = BitConverter.ToInt32(Data, 0x0C); Height = BitConverter.ToInt32(Data, 0x10); - byte[] fmtNibble = { (byte)((Data[0x38] & 0xF0) >> 4), (byte)(Data[0x38] & 0x0F) }; - // Second nibble is 0=DXT1, 1=DXT3?, 2=DXT5 - // First nibble ?? 1 offset image, 4 used in DXT1, 5/6 used in DXT5 - - if (fmtNibble[1] == 0) - { - DXT = 1; - } - else if (fmtNibble[1] == 1) - { - DXT = 3; - } - else if (fmtNibble[1] == 2) - { - DXT = 5; - } - else + switch (Data[0x08]) { - throw new FormatException($"Unknown texture compression {Data[0x38]:X2} ({fmtNibble[0]:X} {fmtNibble[1]:X})"); + case 3: + DXT = 1; + break; + case 4: + DXT = 5; + break; + default: + throw new FormatException($"Unknown texture compression {Data[0x08]:X2}"); } } } @@ -191,10 +462,29 @@ public DDS(string path) : base(path) { } public DDS(byte[] fileBytes) : base(fileBytes) { } + public DDSfile Struct; + public override void Initialize() { base.Initialize(); + Struct = DdsFromBytes(Data); + + /* + switch (Struct.PixelFormat.dwFourCC) + { + case 827611204: // DXT1 + DXT = 1; + break; + case 861165636: // DXT3 + DXT = 3; + break; + case 894720068: // DXT5 + DXT = 5; + break; + } + */ + if (Data[0x57] == '5') DXT = 5; else if (Data[0x57] == '1') DXT = 1; else if (Data[0x57] == '3') DXT = 3; @@ -210,6 +500,39 @@ public class TextureUtil public const int DDS_HEADER_SIZE = 128; public const int ST_BIR_OFFSET = 0x104; public const int ST_TEXTURE_OFFSET = 0x184; + + // https://github.com/zigox/arturas-kalonline-coding/blob/master/KDE/KDE/XNAGraphics/DDSLib.cs + private const int DDSD_CAPS = 0x1; //Required in every .dds file. + private const int DDSD_HEIGHT = 0x2; //Required in every .dds file. + private const int DDSD_WIDTH = 0x4; //Required in every .dds file. + private const int DDSD_PITCH = 0x8; //Required when pitch is provided for an uncompressed texture. + private const int DDSD_PIXELFORMAT = 0x1000; //Required in every .dds file. + private const int DDSD_MIPMAPCOUNT = 0x20000; //Required in a mipmapped texture. + private const int DDSD_LINEARSIZE = 0x80000; //Required when pitch is provided for a compressed texture. + private const int DDSD_DEPTH = 0x800000; //Required in a depth texture. + + private const int DDPF_ALPHAPIXELS = 0x1; //Texture contains alpha data; dwRGBAlphaBitMask contains valid data. + private const int DDPF_ALPHA = 0x2; //Used in some older DDS files for alpha channel only uncompressed data (dwRGBBitCount contains the alpha channel bitcount; dwABitMask contains valid data) + private const int DDPF_FOURCC = 0x4; //Texture contains compressed RGB data; dwFourCC contains valid data. + private const int DDPF_RGB = 0x40; //Texture contains uncompressed RGB data; dwRGBBitCount and the RGB masks (dwRBitMask, dwRBitMask, dwRBitMask) contain valid data. + private const int DDPF_YUV = 0x200; //Used in some older DDS files for YUV uncompressed data (dwRGBBitCount contains the YUV bit count; dwRBitMask contains the Y mask, dwGBitMask contains the U mask, dwBBitMask contains the V mask) + private const int DDPF_LUMINANCE = 0x2000; //Used in some older DDS files for single channel color uncompressed data (dwRGBBitCount contains the luminance channel bit count; dwRBitMask contains the channel mask). Can be combined with DDPF_ALPHAPIXELS for a two channel DDS file. + private const int DDPF_Q8W8V8U8 = 0x00080000; //Used by Microsoft tools when a Q8W8V8U8 is present, this is not a documeneted flag. + + private const int DDSCAPS_COMPLEX = 0x8; //Optional; must be used on any file that contains more than one surface (a mipmap, a cubic environment map, or mipmapped volume texture). + private const int DDSCAPS_MIPMAP = 0x400000; //Optional; should be used for a mipmap. + private const int DDSCAPS_TEXTURE = 0x1000; //Required + + private const int DDSCAPS2_CUBEMAP = 0x200; //Required for a cube map. + private const int DDSCAPS2_CUBEMAP_POSITIVEX = 0x400; //Required when these surfaces are stored in a cube map. + private const int DDSCAPS2_CUBEMAP_NEGATIVEX = 0x800; //Required when these surfaces are stored in a cube map. + private const int DDSCAPS2_CUBEMAP_POSITIVEY = 0x1000; //Required when these surfaces are stored in a cube map. + private const int DDSCAPS2_CUBEMAP_NEGATIVEY = 0x2000; //Required when these surfaces are stored in a cube map. + private const int DDSCAPS2_CUBEMAP_POSITIVEZ = 0x4000; //Required when these surfaces are stored in a cube map. + private const int DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x8000; //Required when these surfaces are stored in a cube map. + private const int DDSCAPS2_VOLUME = 0x200000; //Required for a volume texture. + + private const uint DDS_MAGIC = 0x20534444; // "DDS " #endregion [StructLayout(LayoutKind.Sequential)] @@ -254,35 +577,6 @@ public PixelData(byte[] buffer, int index) } } - // - // Get "metadata" bytes from ST file - // - static public byte[] STmetadata(byte[] fileBytes) - { - byte[] metaBytes = new byte[0x22]; - - string textureName = ""; - for (int i = 0x40; fileBytes[i] != 0; i++) - { - textureName += (char)fileBytes[i]; - } - - byte[] extraBytes = { - fileBytes[0x08], - fileBytes[0x1C], - fileBytes[0x3C] }; - - using (MemoryStream ms = new MemoryStream()) - { - ms.Write(Encoding.ASCII.GetBytes(textureName), 0, Encoding.ASCII.GetBytes(textureName).Length); - ms.Write(new byte[32 - Encoding.ASCII.GetBytes(textureName).Length], 0, 32 - Encoding.ASCII.GetBytes(textureName).Length); - ms.Write(extraBytes, 0, extraBytes.Length); - metaBytes = ms.ToArray(); - } - - return metaBytes; - } - // // Convert DDS to ST // @@ -411,7 +705,22 @@ static public byte[] STtoDDS(byte[] fileBytes, bool header=true) int width = fileBytes[0xC] | fileBytes[0xD] << 8 | fileBytes[0xE] << 16 | fileBytes[0xF] << 24; int height = fileBytes[0x10] | fileBytes[0x11] << 8 | fileBytes[0x12] << 16 | fileBytes[0x13] << 24; - int dxt_version = fileBytes[0x1C] > 0 ? 5 : 1; + int bitCount = fileBytes[0x88]; + int alphaMask = fileBytes[0x1C]; + + int dxt_version = 0; // fileBytes[0x1C] > 0 ? 5 : 1; + switch (fileBytes[0x08]) + { + case 3: + dxt_version = 1; + break; + case 4: + dxt_version = 5; + break; + default: + // throw new FormatException($"Unknown texture compression {fileBytes[0x08]:X2}"); + break; + } PixelData[] pixels = new PixelData[(fileBytes.Length - 0x184) / 16]; int p = 0; @@ -434,44 +743,58 @@ static public byte[] STtoDDS(byte[] fileBytes, bool header=true) // DDS_HEADER ms.Write(Encoding.ASCII.GetBytes("DDS "), 0, 4); - ms.Write(BitConverter.GetBytes(124), 0, 4); // dwSize - ms.Write(BitConverter.GetBytes(0x081007), 0, 4); // dwFlags + ms.Write(BitConverter.GetBytes(124), 0, 4); // 0004 dwSize + ms.Write(BitConverter.GetBytes(0x081007), 0, 4); // 0008 dwFlags - ms.Write(BitConverter.GetBytes(height), 0, 4); // dwHeight - ms.Write(BitConverter.GetBytes(width), 0, 4); // dwWidth + ms.Write(BitConverter.GetBytes(height), 0, 4); // 000C dwHeight + ms.Write(BitConverter.GetBytes(width), 0, 4); // 0010 dwWidth - ms.Write(BitConverter.GetBytes(width == height ? 0x4000 : 0x2000), 0, 4); // dwPitchOrLinearSize + ms.Write(BitConverter.GetBytes(width == height ? 0x4000 : 0x2000), 0, 4); // 0014 dwPitchOrLinearSize - ms.Write(BitConverter.GetBytes(0), 0, 4); // dwDepth - ms.Write(BitConverter.GetBytes(0), 0, 4); // dwMipMapCount + ms.Write(BitConverter.GetBytes(0), 0, 4); // 0018 dwDepth + ms.Write(BitConverter.GetBytes(0), 0, 4); // 001C dwMipMapCount - // dwReserved1[11] - ms.Write(nullBytes, 0, 11); + ms.Write(nullBytes, 0, 44); // 0020 dwReserved1[11] // DDS_PIXELFORMAT - ms.Write(BitConverter.GetBytes(0), 0, 4); // dwSize - ms.Write(BitConverter.GetBytes(0), 0, 4); // dwFlags - ms.Write(BitConverter.GetBytes(0), 0, 4); // dwFourCC - ms.Write(BitConverter.GetBytes(0), 0, 4); // dwRGBBitCount - ms.Write(BitConverter.GetBytes(0), 0, 4); // dwRBitMask - ms.Write(BitConverter.GetBytes(0), 0, 4); // dwGBitMask - ms.Write(BitConverter.GetBytes(0), 0, 4); // dwBBitMask - ms.Write(BitConverter.GetBytes(0), 0, 4); // dwABitMask - - ms.WriteByte(0); // ? - ms.Write(BitConverter.GetBytes(0x20), 0, 4); // ? - ms.Write(BitConverter.GetBytes(0x04), 0, 4); // ? - - ms.Write(Encoding.ASCII.GetBytes("DXT" + dxt_version), 0, 4); - ms.Write(nullBytes, 0, 20); - - ms.Write(BitConverter.GetBytes(0x1000), 0, 4); // dwCaps - ms.Write(BitConverter.GetBytes(0), 0, 4); // dwCaps2 - ms.Write(BitConverter.GetBytes(0), 0, 4); // dwCaps3 - ms.Write(BitConverter.GetBytes(0), 0, 4); // dwCaps4 - ms.Write(BitConverter.GetBytes(0), 0, 4); // dwReserved2 + ms.Write(BitConverter.GetBytes(32), 0, 4); // 004C dwSize + + if (dxt_version != 0) + { + ms.Write(BitConverter.GetBytes(DDPF_FOURCC), 0, 4); // 0050 dwFlags + ms.Write(Encoding.ASCII.GetBytes("DXT" + dxt_version), 0, 4); // 0054 dwFourCC + } + else + { + ms.Write(BitConverter.GetBytes(DDPF_RGB), 0, 4); // 0050 dwFlags + ms.Write(BitConverter.GetBytes(0), 0, 4); // 0054 dwFourCC + } + + if (dxt_version != 0) + { + ms.Write(BitConverter.GetBytes(0), 0, 4); // 0058 dwRGBBitCount + ms.Write(BitConverter.GetBytes(0), 0, 4); // 005C dwRBitMask + ms.Write(BitConverter.GetBytes(0), 0, 4); // 0060 dwGBitMask + ms.Write(BitConverter.GetBytes(0), 0, 4); // 0064 dwBBitMask + ms.Write(BitConverter.GetBytes(0), 0, 4); // 0068 dwABitMask + } + else + { + ms.Write(BitConverter.GetBytes(bitCount), 0, 4); // 0058 dwRGBBitCount + ms.Write(BitConverter.GetBytes(0x00ff0000), 0, 4); // 005C dwRBitMask + ms.Write(BitConverter.GetBytes(0x0000ff00), 0, 4); // 0060 dwGBitMask + ms.Write(BitConverter.GetBytes(0x000000ff), 0, 4); // 0064 dwBBitMask + ms.Write(BitConverter.GetBytes(0xff000000), 0, 4); // 0068 dwABitMask + } + + ms.Write(BitConverter.GetBytes(0x1000), 0, 4); // 006C dwCaps + ms.Write(BitConverter.GetBytes(0), 0, 4); // 0070 dwCaps2 + ms.Write(BitConverter.GetBytes(0), 0, 4); // 0074 dwCaps3 + ms.Write(BitConverter.GetBytes(0), 0, 4); // 0078 dwCaps4 + ms.Write(BitConverter.GetBytes(0), 0, 4); // 007C dwReserved2 } + // Texture data foreach (PixelData pixel in pixels) { ms.WriteByte(pixel.alpha); diff --git a/Utils/FileAnalysis.cs b/Utils/FileAnalysis.cs index 6330d9b..17c14bd 100644 --- a/Utils/FileAnalysis.cs +++ b/Utils/FileAnalysis.cs @@ -1,5 +1,6 @@ using System; using System.Text; +using static GettingUpTool.Texture; namespace GettingUpTool { @@ -10,224 +11,103 @@ private static string StringFromByteArray(byte[] array, int index, int length) return Encoding.ASCII.GetString(array, index, length).Replace('\0', ' ').Replace('\t', '?').Replace('\r', '?').Replace('\n', '?'); } + private static string HexLine(ref Int32 offset, ArraySegment bytes, Type type, string comment="", bool show_bytes=true) + { + string str = $"{offset:X4}"; + + if (show_bytes == true) + str += $"\t{bytes.Array[bytes.Offset + 0]:X2} {bytes.Array[bytes.Offset + 1]:X2} {bytes.Array[bytes.Offset + 2]:X2} {bytes.Array[bytes.Offset + 3]:X2}"; + + if (type.FullName == "System.String") + str += $"\t{StringFromByteArray(bytes.Array, bytes.Offset, bytes.Count)}"; + else if (type.FullName == "System.Int32") + str += $"\t{BitConverter.ToInt32(bytes.Array, bytes.Offset)}"; + else + str += "\t\t"; + + if (comment != "") + str += $"\t{comment}"; + + str += Environment.NewLine; + + offset += bytes.Count; + + return str; + } + public static string AnalyzeST(byte[] fileBytes) { string debugLog = string.Empty; int i = 0; - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{StringFromByteArray(fileBytes, i, 4)}"; - // debugLog += $"\t{Convert.ToChar(fileBytes[0])}"; - // debugLog += $"{Convert.ToChar(fileBytes[1])}"; - // debugLog += $"{Convert.ToChar(fileBytes[2])}"; - // debugLog += $"{Convert.ToChar(fileBytes[3])}"; - debugLog += $"\tST header"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\tWidth"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\tHeight"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\tWidth"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\tHeight"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\tAlpha?"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\t0"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\t1"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\t1"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\t{Encoding.ASCII.GetString(fileBytes, i, 4).Replace('\0', ' ').Replace('\t', '?').Replace('\r', '?').Replace('\n', '?')}"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\t1"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\tDDS size"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\tTexture data offset?"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\tCompression?"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}"; - debugLog += $"\t{Encoding.ASCII.GetString(fileBytes, i, 32).Replace('\0', ' ').Replace('\t', '?').Replace('\r', '?').Replace('\n', '?')}"; - // debugLog += $"\tFilename"; - debugLog += Environment.NewLine; - i += 32; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\t{Encoding.ASCII.GetString(fileBytes, i, 4).Replace('\0', ' ').Replace('\t', '?').Replace('\r', '?').Replace('\n', '?')}"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\t{Encoding.ASCII.GetString(fileBytes, i, 4).Replace('\0', ' ').Replace('\t', '?').Replace('\r', '?').Replace('\n', '?')}"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\t2"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\t0x0A"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\t{Encoding.ASCII.GetString(fileBytes, i, 4).Replace('\0', ' ').Replace('\t', '?').Replace('\r', '?').Replace('\n', '?')}"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\t{Encoding.ASCII.GetString(fileBytes, i, 4).Replace('\0', ' ').Replace('\t', '?').Replace('\r', '?').Replace('\n', '?')}"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\t{Encoding.ASCII.GetString(fileBytes, i, 4).Replace('\0', ' ').Replace('\t', '?').Replace('\r', '?').Replace('\n', '?')}"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\t{Encoding.ASCII.GetString(fileBytes, i, 4).Replace('\0', ' ').Replace('\t', '?').Replace('\r', '?').Replace('\n', '?')}"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\t{Encoding.ASCII.GetString(fileBytes, i, 4).Replace('\0', ' ').Replace('\t', '?').Replace('\r', '?').Replace('\n', '?')}"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\tDDS size"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\tBit output?"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\t"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\tDDS size 2"; - debugLog += Environment.NewLine; - i += 4; - - for (int n = 0; n < 0x70; n += 4) - { - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\t{Encoding.ASCII.GetString(fileBytes, i, 4).Replace('\0', ' ').Replace('\t', '?').Replace('\r', '?').Replace('\n', '?')}"; - // debugLog += $"\t{Convert.ToChar(fileBytes[i + 0])}{Convert.ToChar(fileBytes[i + 1])}{Convert.ToChar(fileBytes[i + 2])}{Convert.ToChar(fileBytes[i + 3])}"; - debugLog += Environment.NewLine; - i += 4; // 0x70; - } - - // 0104 - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{Encoding.ASCII.GetString(fileBytes, i, 4).Replace('\0', ' ').Replace('\t', '?').Replace('\r', '?').Replace('\n', '?')}"; - // debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\tBIR header"; - debugLog += Environment.NewLine; - i += 4; - - for (int n = 0; n < 0x7C; n += 4) - { - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += Environment.NewLine; - i += 4; - } - - // 0184 - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\tTexture data {fileBytes.Length - i} bytes"; - debugLog += Environment.NewLine; - i += 4; + // var fileStruct = BytesToStructure(fileBytes); + + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(string), "header ----------"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "Compression"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "Width"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "Height"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "Width2"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "Height2"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "Alpha bit depth"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "0"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "1 / 8"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "1 / 4"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "??"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "1"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "DDS size"); + int birOffset = 0x84 + fileBytes[i]; + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "Texture data offset?"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "Tiling?"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 32), typeof(string), "", false); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "2"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "10"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "DDS size 2"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "Bit output?"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "DDS size 3"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "DDS size 4"); + while (i < birOffset) + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(string), "header ----------"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += $". Texture data {fileBytes.Length - i} bytes"; return debugLog; } @@ -237,227 +117,46 @@ public static string AnalyzeST2(byte[] fileBytes) string debugLog = string.Empty; int i = 0; - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{StringFromByteArray(fileBytes, i, 4)}"; - // debugLog += $"\t{Convert.ToChar(fileBytes[0])}"; - // debugLog += $"{Convert.ToChar(fileBytes[1])}"; - // debugLog += $"{Convert.ToChar(fileBytes[2])}"; - // debugLog += $"{Convert.ToChar(fileBytes[3])}"; - debugLog += $"\tHeader"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\tWidth"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\tHeight"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\tWidth"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\tHeight"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\tAlpha?"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\t0"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\t1"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\t1"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\t0"; - debugLog += Environment.NewLine; - i += 4; - - // 0030 - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\t1"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\tDDS size"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\tTexture data offset?"; - debugLog += Environment.NewLine; - i += 4; - - // 003C - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += Environment.NewLine; - i += 4; - - // 0040 Filename - debugLog += $"{i:X4}"; - debugLog += $"\t{Encoding.ASCII.GetString(fileBytes, i, 32).Replace('\0', ' ').Replace('\t', '?').Replace('\r', '?').Replace('\n', '?')}"; - debugLog += Environment.NewLine; - i += 32; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\t2"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\t10"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\tDDS size"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\tBit output?"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\tBIR size"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\tDDS size 2"; - debugLog += Environment.NewLine; - i += 4; - - // 0094 - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += Environment.NewLine; - i += 4; - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += Environment.NewLine; - i += 4; - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += Environment.NewLine; - i += 4; - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += Environment.NewLine; - i += 4; - - // 00A4 BIR header - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{Encoding.ASCII.GetString(fileBytes, i, 4).Replace('\0', ' ').Replace('\t', '?').Replace('\r', '?').Replace('\n', '?')}"; - debugLog += $"\tBIR/DDS header"; - debugLog += Environment.NewLine; - i += 4; - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\t{Encoding.ASCII.GetString(fileBytes, i, 4).Replace('\0', ' ').Replace('\t', '?').Replace('\r', '?').Replace('\n', '?')}"; - debugLog += Environment.NewLine; - i += 4; - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\t{Encoding.ASCII.GetString(fileBytes, i, 4).Replace('\0', ' ').Replace('\t', '?').Replace('\r', '?').Replace('\n', '?')}"; - debugLog += Environment.NewLine; - i += 4; - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\t{Encoding.ASCII.GetString(fileBytes, i, 4).Replace('\0', ' ').Replace('\t', '?').Replace('\r', '?').Replace('\n', '?')}"; - debugLog += Environment.NewLine; - i += 4; - - // 00B4 - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\tTexture data {fileBytes.Length - i} bytes"; - debugLog += Environment.NewLine; - i += 4; + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(string), "header ----------"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "Compression"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "Width"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "Height"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "Width2"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "Height2"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "Alpha bit depth"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "0"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "1"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "1"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "??"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "1"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "DDS size"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "Texture data offset?"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "Tiling?"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 32), typeof(string), "", false); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "2"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "10"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "DDS size 2"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "Bit output?"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "DDS size 3"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "DDS size 4"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(string), "header ----------"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32)); + debugLog += $". Texture data {fileBytes.Length - i} bytes"; return debugLog; } @@ -467,145 +166,34 @@ public static string AnalyzeDDS(byte[] fileBytes) string debugLog = string.Empty; int i = 0; - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{StringFromByteArray(fileBytes, i, 4)}"; - debugLog += $"\tHeader"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\tdwSize"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\tdwFlags"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\tdwHeight"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\tdwWidth"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\tdwPitchOrLinearSize"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\tdwDepth"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\tdwMipMapCount"; - debugLog += Environment.NewLine; - i += 4; + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(string), "Header"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "dwSize"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "dwFlags"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "dwHeight"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "dwWidth"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "dwPitchOrLinearSize"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "dwDepth"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "dwMipMapCount"); - // 0020 for (int n = 0; n < 0x2C; n += 4) { - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\tdwReserved1[{n / 4}]"; - debugLog += Environment.NewLine; - i += 4; + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), $"dwReserved[{n / 4}]"); } - // 004C debugLog += $". DDS_PIXELFORMAT" + Environment.NewLine; - - debugLog += $"| {i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\tdwSize"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"| {i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\tdwFlags"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"| {i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - // debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\t{StringFromByteArray(fileBytes, i, 4)}"; - debugLog += $"\tdwFourCC"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"| {i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\tdwRGBBitCount"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"| {i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\tdwRBitMask"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"| {i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\tdwGBitMask"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"| {i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\tdwBBitMask"; - debugLog += Environment.NewLine; - i += 4; - - debugLog += $"' {i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\tdwABitMask"; - debugLog += Environment.NewLine; - i += 4; - - // 006C - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\tdwCaps"; - debugLog += Environment.NewLine; - i += 4; - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\tdwCaps2"; - debugLog += Environment.NewLine; - i += 4; - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\tdwCaps3"; - debugLog += Environment.NewLine; - i += 4; - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\tdwCaps4"; - debugLog += Environment.NewLine; - i += 4; - - // 007C - debugLog += $"{i:X4}\t{fileBytes[i + 0]:X2} {fileBytes[i + 1]:X2} {fileBytes[i + 2]:X2} {fileBytes[i + 3]:X2}"; - debugLog += $"\t{BitConverter.ToInt32(fileBytes, i)}"; - debugLog += $"\tdwReserved2"; - debugLog += Environment.NewLine; - i += 4; - + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "dwSize"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "dwFlags"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(string), "dwFourCC"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "dwRGBBitCount"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "dwRBitMask"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "dwGBitMask"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "dwBBitMask"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "dwABitMask"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "dwCaps"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "dwCaps2"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "dwCaps3"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "dwCaps4"); + debugLog += HexLine(ref i, new ArraySegment(fileBytes, i, 4), typeof(Int32), "dwReserved2"); debugLog += $". Texture data {fileBytes.Length - i} bytes"; return debugLog; diff --git a/Utils/GameFinder.cs b/Utils/GameFinder.cs index 74fe8c9..06933d0 100644 --- a/Utils/GameFinder.cs +++ b/Utils/GameFinder.cs @@ -1,5 +1,6 @@ using Microsoft.Win32; using System; +using System.Diagnostics; using System.IO; using System.Text.RegularExpressions; @@ -7,6 +8,11 @@ namespace GettingUpTool { public static class GameFinder { + public static bool IsGameRunning() + { + return Process.GetProcessesByName("GettingUp").Length != 0; + } + public static bool ValidateGamePath(DirectoryInfo path) { bool isValid = false; @@ -126,7 +132,7 @@ public static DirectoryInfo LocateGamePath() if (!dirSteamLib.Exists) continue; // Check if this library folder contains MEGU - path = new DirectoryInfo(Path.Combine(pathSteam, @"steamapps\common\Marc Ecko's Getting Up 2")); + path = new DirectoryInfo(Path.Combine(dirSteamLib.FullName, @"steamapps\common\Marc Ecko's Getting Up 2")); if (ValidateGamePath(path)) return path; } } diff --git a/Utils/UiHelpers.cs b/Utils/UiHelpers.cs new file mode 100644 index 0000000..d38a49d --- /dev/null +++ b/Utils/UiHelpers.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace GettingUpTool +{ + static class UI + { + public const string GithubUrl = "https://github.com/Asbra/GettingUpTool"; + public const string HelpUrl = "https://github.com/Asbra/GettingUpTool/wiki/Replacing-textures-graffiti-in-Marc-Ecko%27s-Getting-Up"; + + public static void BuildTree(DirectoryInfo directoryInfo, TreeNodeCollection nodes, string[] fileExtensions, bool flat = false) + { + TreeNode curNode = null; + if (flat && nodes.Count > 0) + { + curNode = nodes[0]; + } + else + { + curNode = nodes.Add(directoryInfo.Name); + } + + foreach (FileInfo file in directoryInfo.GetFiles()) + { + string filext = file.Extension.ToLower(); + // if (filext == ".st" || filext == ".bir" || filext == ".dds" || filext == ".st2") + // if (filext == ".st" || filext == ".dds") + if (Array.IndexOf(fileExtensions, filext) > -1) + { + curNode.Nodes.Add(file.FullName, file.Name); + } + } + + foreach (DirectoryInfo subdir in directoryInfo.GetDirectories()) + { + BuildTree(subdir, flat ? nodes : curNode.Nodes, fileExtensions, flat); + } + } + + private static void ClearEmptyNodes(TreeNodeCollection tv, TreeNode tn) + { + if (tn.Nodes.Count > 0) + { + for (int iNode = 0; iNode < tn.Nodes.Count; iNode++) + { + ClearEmptyNodes(tv, tn.Nodes[iNode]); + } + } + else if (string.IsNullOrWhiteSpace(tn.Name)) + { + tv.Remove(tn); + } + } + + public static void RebuildFileTree(DirectoryInfo directoryInfo, TreeNodeCollection nodes, string[] fileExtensions, bool flat = false) + { + nodes.Clear(); + + BuildTree(directoryInfo, nodes, fileExtensions, flat); + + if (nodes.Count > 0) + { + for (int i = 0; i < 30; i++) + ClearEmptyNodes(nodes, nodes[0]); + + // Recursively delete empty nodes + for (int i = 0; i < nodes.Count; i++) + { + if (nodes[i].Nodes.Count == 0) + { + nodes.Remove(nodes[i]); + + if (string.IsNullOrWhiteSpace(nodes[i].Name) || Directory.Exists(nodes[i].Name)) + { + nodes.Remove(nodes[i]); + } + } + } + + // Open the first node by default + nodes[0].Expand(); + if (nodes[0].Nodes.Count > 0) + nodes[0].Nodes[0].Expand(); + } + } + } +}