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)