From 2d72d4fbcd863229a9e78fc95b2a40c2bc7d0c8f Mon Sep 17 00:00:00 2001 From: Lwmte <3331699+Lwmte@users.noreply.github.com> Date: Sun, 17 Aug 2025 16:51:27 +0200 Subject: [PATCH 1/4] Fixed bug with incorrect bone weight writing if tint was changed --- TombLib/TombLib/LevelData/Compilers/TombEngine/Wad.cs | 4 ++-- TombLib/TombLib/Wad/WadMesh.cs | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/TombLib/TombLib/LevelData/Compilers/TombEngine/Wad.cs b/TombLib/TombLib/LevelData/Compilers/TombEngine/Wad.cs index 907726dbba..979ece592d 100644 --- a/TombLib/TombLib/LevelData/Compilers/TombEngine/Wad.cs +++ b/TombLib/TombLib/LevelData/Compilers/TombEngine/Wad.cs @@ -48,8 +48,8 @@ private TombEngineMesh ConvertWadMesh(WadMesh oldMesh, bool isStatic, string obj Position = new Vector3(pos.X, -pos.Y, pos.Z), Normal = Vector3.Normalize(new Vector3(normal.X, -normal.Y, normal.Z)), Color = color, - BoneIndex = oldMesh.HasWeights ? oldMesh.VertexWeights[i].Index : new int[4] { meshIndex, 0, 0, 0 }, - BoneWeight = oldMesh.HasWeights ? oldMesh.VertexWeights[i].Weight : new float[4] { 1, 0, 0, 0 }, + BoneIndex = oldMesh.HasWeights && oldMesh.VertexWeights[i].Valid() ? oldMesh.VertexWeights[i].Index : new int[4] { meshIndex, 0, 0, 0 }, + BoneWeight = oldMesh.HasWeights && oldMesh.VertexWeights[i].Valid() ? oldMesh.VertexWeights[i].Weight : new float[4] { 1, 0, 0, 0 }, Glow = oldMesh.HasAttributes ? (float)oldMesh.VertexAttributes[i].Glow / 64.0f : 0.0f, Move = oldMesh.HasAttributes ? (float)oldMesh.VertexAttributes[i].Move / 64.0f : 0.0f }; diff --git a/TombLib/TombLib/Wad/WadMesh.cs b/TombLib/TombLib/Wad/WadMesh.cs index fe301fe61b..02d554648f 100644 --- a/TombLib/TombLib/Wad/WadMesh.cs +++ b/TombLib/TombLib/Wad/WadMesh.cs @@ -29,6 +29,12 @@ public VertexWeight() Weight = new float[4]; } + public bool Valid() + { + return Weight[0] > 0.0f || Weight[1] > 0.0f || + Weight[2] > 0.0f || Weight[3] > 0.0f; + } + public static bool operator ==(VertexWeight a, VertexWeight b) { for (int i = 0; i < 4; i++) From bf6001e7ccbf467c4a89b86ddfc65276304ae585 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Feb 2026 19:35:23 +0000 Subject: [PATCH 2/4] Initial plan From 4bba5e814d29534e20a784d340293dfd35a8cd44 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Feb 2026 19:43:38 +0000 Subject: [PATCH 3/4] Use project name for .trproj files and add rename checkbox - Add TrprojFileName property to GameProjectBase to track actual .trproj file name - New projects now get {projectName}.trproj instead of {engineName}.trproj - Existing projects preserve their current .trproj file name when loaded - GetTrprojFilePath() now uses the stored TrprojFileName - Rename() supports optional renameTrprojFile parameter to rename the .trproj file - FormRenameProject gets a "Rename .trproj file as well" checkbox (checked by default) - Update IProject.Rename interface to include renameTrprojFile parameter Co-authored-by: Nickelony <20436882+Nickelony@users.noreply.github.com> --- .../NewStructure/Bases/GameProjectBase.cs | 23 +++++++++++++++++-- .../NewStructure/IGameProject.cs | 2 +- .../TombIDE.Shared/NewStructure/IProject.cs | 2 +- .../Implementations/LevelProject.cs | 2 +- .../Forms/FormRenameProject.Designer.cs | 22 ++++++++++++++---- TombIDE/TombIDE/Forms/FormRenameProject.cs | 10 ++++++-- 6 files changed, 50 insertions(+), 11 deletions(-) diff --git a/TombIDE/TombIDE.Shared/NewStructure/Bases/GameProjectBase.cs b/TombIDE/TombIDE.Shared/NewStructure/Bases/GameProjectBase.cs index aa65ace7eb..645c06e882 100644 --- a/TombIDE/TombIDE.Shared/NewStructure/Bases/GameProjectBase.cs +++ b/TombIDE/TombIDE.Shared/NewStructure/Bases/GameProjectBase.cs @@ -35,6 +35,11 @@ public abstract class GameProjectBase : IGameProject public string Name { get; protected set; } public string DirectoryPath { get; protected set; } + /// + /// The file name (not path) of the .trproj file. (e.g. "MyProject.trproj") + /// + public string TrprojFileName { get; set; } + protected string CustomScriptDirectoryPath { get; set; } public string LevelsDirectoryPath { get; set; } @@ -51,6 +56,7 @@ public GameProjectBase(TrprojFile trproj, Version targetTrprojVersion) Name = trproj.ProjectName; DirectoryPath = Path.GetDirectoryName(trproj.FilePath); + TrprojFileName = Path.GetFileName(trproj.FilePath); LevelsDirectoryPath = trproj.LevelSourcingDirectory; @@ -70,6 +76,7 @@ public GameProjectBase(string name, string directoryPath, string levelsDirectory { Name = name; DirectoryPath = directoryPath; + TrprojFileName = name + ".trproj"; LevelsDirectoryPath = levelsDirectoryPath; if (SupportsCustomScriptPaths) @@ -80,7 +87,7 @@ public GameProjectBase(string name, string directoryPath, string levelsDirectory } public virtual string GetTrprojFilePath() - => Path.Combine(DirectoryPath, Path.GetFileNameWithoutExtension(GetEngineExecutableFilePath()) + ".trproj"); + => Path.Combine(DirectoryPath, TrprojFileName); public virtual string GetLauncherFilePath() { @@ -154,8 +161,10 @@ public virtual LevelProject[] GetAllValidLevelProjects() return result.ToArray(); } - public virtual void Rename(string newName, bool renameDirectory) + public virtual void Rename(string newName, bool renameDirectory, bool renameTrprojFile = false) { + string oldTrprojFileName = TrprojFileName; + if (renameDirectory) { string newProjectPath = Path.Combine(Path.GetDirectoryName(DirectoryPath), newName); @@ -179,6 +188,16 @@ public virtual void Rename(string newName, bool renameDirectory) } Name = newName; + + if (renameTrprojFile) + { + TrprojFileName = newName + ".trproj"; + + string oldTrprojPath = Path.Combine(DirectoryPath, oldTrprojFileName); + + if (File.Exists(oldTrprojPath) && !oldTrprojPath.Equals(GetTrprojFilePath(), StringComparison.OrdinalIgnoreCase)) + File.Delete(oldTrprojPath); + } } public virtual bool IsValid(out string errorMessage) diff --git a/TombIDE/TombIDE.Shared/NewStructure/IGameProject.cs b/TombIDE/TombIDE.Shared/NewStructure/IGameProject.cs index e671f74ff4..3a5dcee3fb 100644 --- a/TombIDE/TombIDE.Shared/NewStructure/IGameProject.cs +++ b/TombIDE/TombIDE.Shared/NewStructure/IGameProject.cs @@ -56,7 +56,7 @@ public interface IGameProject : IProject List GameLanguageNames { get; } /// - /// .trproj file name = game's .exe file name (tomb4, PCTomb5, ...) + ".trproj" + /// Returns the full path to the project's .trproj file. /// string GetTrprojFilePath(); diff --git a/TombIDE/TombIDE.Shared/NewStructure/IProject.cs b/TombIDE/TombIDE.Shared/NewStructure/IProject.cs index 64a0dfa420..febd4e9c47 100644 --- a/TombIDE/TombIDE.Shared/NewStructure/IProject.cs +++ b/TombIDE/TombIDE.Shared/NewStructure/IProject.cs @@ -20,7 +20,7 @@ public interface IProject /// /// Renames the project and its directory if specified. /// - void Rename(string newName, bool renameDirectory = false); + void Rename(string newName, bool renameDirectory = false, bool renameTrprojFile = false); /// /// Saves the project's settings. diff --git a/TombIDE/TombIDE.Shared/NewStructure/Implementations/LevelProject.cs b/TombIDE/TombIDE.Shared/NewStructure/Implementations/LevelProject.cs index 832f08a8b5..715e0d34ac 100644 --- a/TombIDE/TombIDE.Shared/NewStructure/Implementations/LevelProject.cs +++ b/TombIDE/TombIDE.Shared/NewStructure/Implementations/LevelProject.cs @@ -80,7 +80,7 @@ public bool IsValid(out string errorMessage) public bool IsExternal(string relativeToLevelsDirectoryPath) => !DirectoryPath.StartsWith(relativeToLevelsDirectoryPath, StringComparison.OrdinalIgnoreCase); - public void Rename(string newName, bool renameDirectory = false) + public void Rename(string newName, bool renameDirectory = false, bool renameTrprojFile = false) { if (renameDirectory) { diff --git a/TombIDE/TombIDE/Forms/FormRenameProject.Designer.cs b/TombIDE/TombIDE/Forms/FormRenameProject.Designer.cs index 6bc7a3def9..ea09bdc548 100644 --- a/TombIDE/TombIDE/Forms/FormRenameProject.Designer.cs +++ b/TombIDE/TombIDE/Forms/FormRenameProject.Designer.cs @@ -20,6 +20,7 @@ private void InitializeComponent() this.button_Apply = new DarkUI.Controls.DarkButton(); this.button_Cancel = new DarkUI.Controls.DarkButton(); this.checkBox_RenameDirectory = new DarkUI.Controls.DarkCheckBox(); + this.checkBox_RenameTrproj = new DarkUI.Controls.DarkCheckBox(); this.panel_02 = new System.Windows.Forms.Panel(); this.label = new DarkUI.Controls.DarkLabel(); this.textBox_NewName = new DarkUI.Controls.DarkTextBox(); @@ -36,7 +37,7 @@ private void InitializeComponent() this.button_Apply.Margin = new System.Windows.Forms.Padding(3, 9, 0, 0); this.button_Apply.Name = "button_Apply"; this.button_Apply.Size = new System.Drawing.Size(75, 23); - this.button_Apply.TabIndex = 1; + this.button_Apply.TabIndex = 2; this.button_Apply.Text = "Apply"; this.button_Apply.Click += new System.EventHandler(this.button_Apply_Click); // @@ -48,7 +49,7 @@ private void InitializeComponent() this.button_Cancel.Margin = new System.Windows.Forms.Padding(3, 9, 0, 0); this.button_Cancel.Name = "button_Cancel"; this.button_Cancel.Size = new System.Drawing.Size(75, 23); - this.button_Cancel.TabIndex = 2; + this.button_Cancel.TabIndex = 3; this.button_Cancel.Text = "Cancel"; // // checkBox_RenameDirectory @@ -60,15 +61,27 @@ private void InitializeComponent() this.checkBox_RenameDirectory.TabIndex = 0; this.checkBox_RenameDirectory.Text = "Rename project directory as well"; // + // checkBox_RenameTrproj + // + this.checkBox_RenameTrproj.Checked = true; + this.checkBox_RenameTrproj.CheckState = System.Windows.Forms.CheckState.Checked; + this.checkBox_RenameTrproj.Location = new System.Drawing.Point(6, 34); + this.checkBox_RenameTrproj.Margin = new System.Windows.Forms.Padding(3, 0, 3, 0); + this.checkBox_RenameTrproj.Name = "checkBox_RenameTrproj"; + this.checkBox_RenameTrproj.Size = new System.Drawing.Size(185, 23); + this.checkBox_RenameTrproj.TabIndex = 1; + this.checkBox_RenameTrproj.Text = "Rename .trproj file as well"; + // // panel_02 // this.panel_02.Controls.Add(this.checkBox_RenameDirectory); + this.panel_02.Controls.Add(this.checkBox_RenameTrproj); this.panel_02.Controls.Add(this.button_Cancel); this.panel_02.Controls.Add(this.button_Apply); this.panel_02.Dock = System.Windows.Forms.DockStyle.Bottom; this.panel_02.Location = new System.Drawing.Point(0, 55); this.panel_02.Name = "panel_02"; - this.panel_02.Size = new System.Drawing.Size(464, 42); + this.panel_02.Size = new System.Drawing.Size(464, 62); this.panel_02.TabIndex = 2; // // label @@ -108,7 +121,7 @@ private void InitializeComponent() this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.CancelButton = this.button_Cancel; - this.ClientSize = new System.Drawing.Size(464, 97); + this.ClientSize = new System.Drawing.Size(464, 117); this.Controls.Add(this.panel_01); this.Controls.Add(this.panel_02); this.FlatBorder = true; @@ -132,6 +145,7 @@ private void InitializeComponent() private DarkUI.Controls.DarkButton button_Apply; private DarkUI.Controls.DarkButton button_Cancel; private DarkUI.Controls.DarkCheckBox checkBox_RenameDirectory; + private DarkUI.Controls.DarkCheckBox checkBox_RenameTrproj; private System.Windows.Forms.Panel panel_02; private DarkUI.Controls.DarkLabel label; private DarkUI.Controls.DarkTextBox textBox_NewName; diff --git a/TombIDE/TombIDE/Forms/FormRenameProject.cs b/TombIDE/TombIDE/Forms/FormRenameProject.cs index b933549ce4..e71c18ae96 100644 --- a/TombIDE/TombIDE/Forms/FormRenameProject.cs +++ b/TombIDE/TombIDE/Forms/FormRenameProject.cs @@ -42,6 +42,7 @@ private void button_Apply_Click(object sender, EventArgs e) throw new ArgumentException("Invalid name."); bool renameDirectory = checkBox_RenameDirectory.Checked; + bool renameTrprojFile = checkBox_RenameTrproj.Checked; if (newName == _targetProject.Name) { @@ -56,7 +57,12 @@ private void button_Apply_Click(object sender, EventArgs e) throw new ArgumentException("A directory with the same name already exists in the parent directory."); } - _targetProject.Rename(newName, true); + _targetProject.Rename(newName, true, renameTrprojFile); + _targetProject.Save(); + } + else if (renameTrprojFile) + { + _targetProject.Rename(newName, false, true); _targetProject.Save(); } else @@ -69,7 +75,7 @@ private void button_Apply_Click(object sender, EventArgs e) if (renameDirectory && Directory.Exists(newDirectory) && !newDirectory.Equals(_targetProject.DirectoryPath, StringComparison.OrdinalIgnoreCase)) throw new ArgumentException("A directory with the same name already exists in the parent directory."); - _targetProject.Rename(newName, renameDirectory); + _targetProject.Rename(newName, renameDirectory, renameTrprojFile); _targetProject.Save(); } } From 3a83fc71f692aee326a7bd2a6d42104d328694d4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Feb 2026 19:45:32 +0000 Subject: [PATCH 4/4] Move .trproj file cleanup after save to prevent data loss Address code review: delete old .trproj file only after successfully saving the new one, preventing data loss if save fails. Co-authored-by: Nickelony <20436882+Nickelony@users.noreply.github.com> --- .../NewStructure/Bases/GameProjectBase.cs | 9 ---- TombIDE/TombIDE/Forms/FormRenameProject.cs | 51 +++++++++++-------- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/TombIDE/TombIDE.Shared/NewStructure/Bases/GameProjectBase.cs b/TombIDE/TombIDE.Shared/NewStructure/Bases/GameProjectBase.cs index 645c06e882..136ad475a8 100644 --- a/TombIDE/TombIDE.Shared/NewStructure/Bases/GameProjectBase.cs +++ b/TombIDE/TombIDE.Shared/NewStructure/Bases/GameProjectBase.cs @@ -163,8 +163,6 @@ public virtual LevelProject[] GetAllValidLevelProjects() public virtual void Rename(string newName, bool renameDirectory, bool renameTrprojFile = false) { - string oldTrprojFileName = TrprojFileName; - if (renameDirectory) { string newProjectPath = Path.Combine(Path.GetDirectoryName(DirectoryPath), newName); @@ -190,14 +188,7 @@ public virtual void Rename(string newName, bool renameDirectory, bool renameTrpr Name = newName; if (renameTrprojFile) - { TrprojFileName = newName + ".trproj"; - - string oldTrprojPath = Path.Combine(DirectoryPath, oldTrprojFileName); - - if (File.Exists(oldTrprojPath) && !oldTrprojPath.Equals(GetTrprojFilePath(), StringComparison.OrdinalIgnoreCase)) - File.Delete(oldTrprojPath); - } } public virtual bool IsValid(out string errorMessage) diff --git a/TombIDE/TombIDE/Forms/FormRenameProject.cs b/TombIDE/TombIDE/Forms/FormRenameProject.cs index e71c18ae96..e3397efcbc 100644 --- a/TombIDE/TombIDE/Forms/FormRenameProject.cs +++ b/TombIDE/TombIDE/Forms/FormRenameProject.cs @@ -44,29 +44,25 @@ private void button_Apply_Click(object sender, EventArgs e) bool renameDirectory = checkBox_RenameDirectory.Checked; bool renameTrprojFile = checkBox_RenameTrproj.Checked; - if (newName == _targetProject.Name) + if (newName == _targetProject.Name && !renameDirectory && !renameTrprojFile) { - // If the name hasn't changed, but the directory name is different and the user wants to rename it - if (Path.GetFileName(_targetProject.DirectoryPath) != newName && renameDirectory) - { - if (!Path.GetFileName(_targetProject.DirectoryPath).Equals(newName, StringComparison.OrdinalIgnoreCase)) - { - string newDirectory = Path.Combine(Path.GetDirectoryName(_targetProject.DirectoryPath), newName); - - if (Directory.Exists(newDirectory)) - throw new ArgumentException("A directory with the same name already exists in the parent directory."); - } + DialogResult = DialogResult.Cancel; + return; + } - _targetProject.Rename(newName, true, renameTrprojFile); - _targetProject.Save(); - } - else if (renameTrprojFile) + if (newName == _targetProject.Name && !renameDirectory) + { + // Only renaming the .trproj file + } + else if (newName == _targetProject.Name && renameDirectory) + { + if (!Path.GetFileName(_targetProject.DirectoryPath).Equals(newName, StringComparison.OrdinalIgnoreCase)) { - _targetProject.Rename(newName, false, true); - _targetProject.Save(); + string newDirectory = Path.Combine(Path.GetDirectoryName(_targetProject.DirectoryPath), newName); + + if (Directory.Exists(newDirectory)) + throw new ArgumentException("A directory with the same name already exists in the parent directory."); } - else - DialogResult = DialogResult.Cancel; } else { @@ -74,9 +70,22 @@ private void button_Apply_Click(object sender, EventArgs e) if (renameDirectory && Directory.Exists(newDirectory) && !newDirectory.Equals(_targetProject.DirectoryPath, StringComparison.OrdinalIgnoreCase)) throw new ArgumentException("A directory with the same name already exists in the parent directory."); + } + + string oldTrprojFilePath = _targetProject.GetTrprojFilePath(); + + _targetProject.Rename(newName, renameDirectory, renameTrprojFile); + _targetProject.Save(); + + // Clean up old .trproj file after successful save + if (renameTrprojFile) + { + // After a directory rename, the old file is now inside the new directory + string oldTrprojFileName = Path.GetFileName(oldTrprojFilePath); + string oldTrprojPathAfterRename = Path.Combine(_targetProject.DirectoryPath, oldTrprojFileName); - _targetProject.Rename(newName, renameDirectory, renameTrprojFile); - _targetProject.Save(); + if (File.Exists(oldTrprojPathAfterRename) && !oldTrprojPathAfterRename.Equals(_targetProject.GetTrprojFilePath(), StringComparison.OrdinalIgnoreCase)) + File.Delete(oldTrprojPathAfterRename); } } catch (Exception ex)