diff --git a/CHANGELOG.md b/CHANGELOG.md
index 24ee8ef13..1264ef870 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,5 @@
## [Unreleased](https://github.com/LostArtefacts/TR-Rando/compare/V1.9.1...master) - xxxx-xx-xx
+- improved data integrity checks when opening a folder and prior to randomization (#719)
## [V1.9.1](https://github.com/LostArtefacts/TR-Rando/compare/V1.9.0...V1.9.1) - 2024-06-23
- fixed a missing reference related to Willard, which would cause enemy randomization to fail if he was selected (#712)
diff --git a/Deps/TRGE.Coord.dll b/Deps/TRGE.Coord.dll
index 15df017f9..4e4e8d50b 100644
Binary files a/Deps/TRGE.Coord.dll and b/Deps/TRGE.Coord.dll differ
diff --git a/Deps/TRGE.Core.dll b/Deps/TRGE.Core.dll
index 89e7c6486..0ecb673df 100644
Binary files a/Deps/TRGE.Core.dll and b/Deps/TRGE.Core.dll differ
diff --git a/TRRandomizerCore/Helpers/ChecksumTester.cs b/TRRandomizerCore/Helpers/ChecksumTester.cs
index aa51039a4..6a5259f25 100644
--- a/TRRandomizerCore/Helpers/ChecksumTester.cs
+++ b/TRRandomizerCore/Helpers/ChecksumTester.cs
@@ -111,6 +111,7 @@ public bool Test(string file)
"1e7d0d88ff9d569e22982af761bb006b", // FLOATING.TR2 (Multipatch/EPC)
"fd8c45efc3f5e690edd0796d350a28ba", // XIAN.TR2
"b56c04ea52227eb7fdebd0665b45357a", // HOUSE.TR2
+ "2241125203a4af81fc4889ed844d5b22", // HOUSE.TR2 (rando-generated for texture optimisation)
"04ad2f33e48081a6b27a7f0ebf90968d", // LEVEL1.TR2
"d9b53b88dd70eec1e4b31182f3286bf5", // LEVEL2.TR2
"ca4294e3bd8835ebf06e114b479a22c2", // LEVEL3.TR2
diff --git a/TRRandomizerCore/TRRandomizerController.cs b/TRRandomizerCore/TRRandomizerController.cs
index deb7cac5a..a26874913 100644
--- a/TRRandomizerCore/TRRandomizerController.cs
+++ b/TRRandomizerCore/TRRandomizerController.cs
@@ -20,10 +20,11 @@ public class TRRandomizerController
internal AbstractTRScriptEditor ScriptEditor => _editor.ScriptEditor;
internal RandomizerSettings LevelRandomizer => (_editor.LevelEditor as ISettingsProvider).Settings;
- internal TRRandomizerController(string directoryPath, bool performChecksumTest)
+ internal TRRandomizerController(string directoryPath)
{
- // If there is a checksum mismatch, we will just ignore the previous backup and open the folder afresh
- _editor = TRCoord.Instance.Open(directoryPath, TRScriptOpenOption.DiscardBackup, performChecksumTest ? TRBackupChecksumOption.PerformCheck : TRBackupChecksumOption.IgnoreIssues);
+ // If there is a script checksum mismatch, we will just ignore the previous backup and open the folder afresh. If the
+ // data files fail the checksum test, the folder cannot be opened.
+ _editor = TRCoord.Instance.Open(directoryPath, TRScriptOpenOption.DiscardBackup, TRBackupChecksumOption.PerformCheck);
_editor.SaveProgressChanged += Editor_SaveProgressChanged;
_editor.RestoreProgressChanged += Editor_RestoreProgressChanged;
StoreExternalOrganisations();
diff --git a/TRRandomizerCore/TRRandomizerCoord.cs b/TRRandomizerCore/TRRandomizerCoord.cs
index 813a7b563..f6e5bc428 100644
--- a/TRRandomizerCore/TRRandomizerCoord.cs
+++ b/TRRandomizerCore/TRRandomizerCoord.cs
@@ -68,10 +68,10 @@ public void Initialise(string applicationID, string version, string taggedVersio
TRCoord.Instance.BackupProgressChanged += TRCoord_BackupProgressChanged;
}
- public TRRandomizerController Open(string directoryPath, bool performChecksumTest)
+ public TRRandomizerController Open(string directoryPath)
{
_openEventArgs = new();
- return new(directoryPath, performChecksumTest);
+ return new(directoryPath);
}
public static void ClearHistory()
@@ -79,6 +79,11 @@ public static void ClearHistory()
TRCoord.Instance.ClearHistory();
}
+ public static void CheckBackupIntegrity()
+ {
+ TRCoord.Instance.CheckBackupIntegrity();
+ }
+
public static void ClearCurrentBackup()
{
TRCoord.Instance.ClearCurrentBackup();
diff --git a/TRRandomizerView/Controls/EditorControl.xaml.cs b/TRRandomizerView/Controls/EditorControl.xaml.cs
index 4ae1b273f..1bf938091 100644
--- a/TRRandomizerView/Controls/EditorControl.xaml.cs
+++ b/TRRandomizerView/Controls/EditorControl.xaml.cs
@@ -7,6 +7,7 @@
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;
+using TRGE.Core;
using TRRandomizerCore;
using TRRandomizerView.Events;
using TRRandomizerView.Model;
@@ -88,6 +89,7 @@ private void FireEditorStateChanged()
{
EditorStateChanged?.Invoke(this, new EditorEventArgs
{
+ IsLoaded = Controller != null,
IsDirty = _dirty,
CanExport = Controller != null && Controller.IsExportPossible,
ReloadRequested = _reloadRequested
@@ -158,6 +160,23 @@ public bool Randomize()
return false;
}
+ try
+ {
+ TRRandomizerCoord.CheckBackupIntegrity();
+ }
+ catch (ChecksumMismatchException)
+ {
+ MessageWindow.ShowError("Game backup data integrity check failed. Randomization cannot be performed as the game data files in the backup directory are not original." +
+ "\n\nPlease uninstall the game and remove any external mods you may have applied.\n\nOnce complete, reinstall the game afresh, and open the data folder again in the randomizer to proceed.",
+ "https://github.com/LostArtefacts/TR-Rando/blob/master/USING.md#troubleshooting");
+
+ if (DeleteBackupImpl())
+ {
+ Unload();
+ }
+ return false;
+ }
+
if (_options.DevelopmentMode)
{
if (!MessageWindow.ShowConfirm("Development mode is switched on and so the generated level files will not be playable.\n\nDo you wish to continue?"))
@@ -284,23 +303,26 @@ public void RestoreDefaults()
public bool DeleteBackup()
{
- if (MessageWindow.ShowConfirm("The files that were backed up when this folder was first opened will be deleted and the editor will be closed.\n\nDo you wish to proceed?"))
+ return MessageWindow.ShowConfirm("The files that were backed up when this folder was first opened will be deleted and the editor will be closed.\n\nDo you wish to proceed?")
+ && DeleteBackupImpl();
+ }
+
+ private bool DeleteBackupImpl()
+ {
+ try
{
- try
- {
- _showExternalModPrompt = false;
- TRRandomizerCoord.ClearCurrentBackup();
- _dirty = false;
- return true;
- }
- catch (Exception e)
- {
- MessageWindow.ShowException(e);
- }
- finally
- {
- _showExternalModPrompt = true;
- }
+ _showExternalModPrompt = false;
+ TRRandomizerCoord.ClearCurrentBackup();
+ _dirty = false;
+ return true;
+ }
+ catch (Exception e)
+ {
+ MessageWindow.ShowException(e);
+ }
+ finally
+ {
+ _showExternalModPrompt = true;
}
return false;
diff --git a/TRRandomizerView/Controls/FolderLoadControl.xaml.cs b/TRRandomizerView/Controls/FolderLoadControl.xaml.cs
index e5eeb261b..4a8775c38 100644
--- a/TRRandomizerView/Controls/FolderLoadControl.xaml.cs
+++ b/TRRandomizerView/Controls/FolderLoadControl.xaml.cs
@@ -93,9 +93,9 @@ public void OpenDataFolder(RecentFolder folder)
OpenDataFolder(folder.FolderPath);
}
- public void OpenDataFolder(string folderPath, bool performChecksumTest = true)
+ public void OpenDataFolder(string folderPath)
{
- OpenProgressWindow opw = new(folderPath, performChecksumTest);
+ OpenProgressWindow opw = new(folderPath);
try
{
if (opw.ShowDialog() ?? false)
@@ -109,12 +109,9 @@ public void OpenDataFolder(string folderPath, bool performChecksumTest = true)
}
catch (ChecksumMismatchException)
{
- if (!MessageWindow.ShowConfirm(folderPath + "\n\nGame data integrity check failed. Randomization may not perform as expected as the game data files in the chosen directory are not original." +
- "\n\nThe recommended action is for you to re-install the game. Once complete, open the data folder again in the randomizer to proceed." +
- "\n\nDo you want to cancel the current operation and take the recommended action?"))
- {
- OpenDataFolder(folderPath, false);
- }
+ MessageWindow.ShowError(folderPath + "\n\nGame data integrity check failed. Randomization cannot be performed as the game data files in the chosen directory are not original." +
+ "\n\nPlease uninstall the game and remove any external mods you may have applied.\n\nOnce complete, reinstall the game afresh, and open the data folder again in the randomizer to proceed.",
+ "https://github.com/LostArtefacts/TR-Rando/blob/master/USING.md#troubleshooting");
}
catch (Exception e)
{
diff --git a/TRRandomizerView/Events/EditorEventArgs.cs b/TRRandomizerView/Events/EditorEventArgs.cs
index ee929a2c9..ff0962e47 100644
--- a/TRRandomizerView/Events/EditorEventArgs.cs
+++ b/TRRandomizerView/Events/EditorEventArgs.cs
@@ -4,6 +4,7 @@ namespace TRRandomizerView.Events;
public class EditorEventArgs : EventArgs
{
+ public bool IsLoaded { get; set; }
public bool IsDirty { get; set; }
public bool CanExport { get; set; }
public bool ReloadRequested { get; set; }
diff --git a/TRRandomizerView/Windows/MainWindow.xaml.cs b/TRRandomizerView/Windows/MainWindow.xaml.cs
index 7bd2ecd9a..d71116329 100644
--- a/TRRandomizerView/Windows/MainWindow.xaml.cs
+++ b/TRRandomizerView/Windows/MainWindow.xaml.cs
@@ -244,7 +244,11 @@ private void EditorControl_EditorStateChanged(object sender, EditorEventArgs e)
IsEditorDirty = e.IsDirty;
EditorCanExport = e.CanExport;
_developmentModeMenuItem.IsChecked = _editorControl.DevelopmentMode;
- if (e.ReloadRequested)
+ if (!e.IsLoaded)
+ {
+ IsEditorActive = false;
+ }
+ else if (e.ReloadRequested)
{
_editorControl.Unload();
IsEditorActive = false;
diff --git a/TRRandomizerView/Windows/MessageWindow.xaml b/TRRandomizerView/Windows/MessageWindow.xaml
index f628c07f6..4a400d04c 100644
--- a/TRRandomizerView/Windows/MessageWindow.xaml
+++ b/TRRandomizerView/Windows/MessageWindow.xaml
@@ -50,12 +50,20 @@
-
+
+
+
+ Help
+ SetValue(DetailsProperty, value);
}
+ public string HelpURL
+ {
+ get => (string)GetValue(HelpURLProperty);
+ set => SetValue(HelpURLProperty, value);
+ }
+
public BitmapSource ImageIcon
{
get => (BitmapSource)GetValue(ImageIconProperty);
@@ -87,6 +104,12 @@ public Visibility ErrorLinkVisibility
set => SetValue(ErrorLinkVisibilityProperty, value);
}
+ public Visibility HelpLinkVisibility
+ {
+ get => (Visibility)GetValue(HelpLinkVisibilityProperty);
+ set => SetValue(HelpLinkVisibilityProperty, value);
+ }
+
public Visibility YesNoButtonVisibility
{
get => (Visibility)GetValue(YesNoButtonVisibilityProperty);
@@ -102,7 +125,7 @@ public Visibility CancelButtonVisibility
private MessageBoxResult _result;
- private MessageWindow(string message, Icon icon, MessageBoxButton buttons, string details = null)
+ private MessageWindow(string message, Icon icon, MessageBoxButton buttons, string details = null, string helpURL = null)
{
InitializeComponent();
Owner = WindowUtils.GetActiveWindow(this);
@@ -111,11 +134,13 @@ private MessageWindow(string message, Icon icon, MessageBoxButton buttons, strin
Message = message;
Details = details;
+ HelpURL = helpURL ?? string.Empty;
ImageIcon = Imaging.CreateBitmapSourceFromHIcon(icon.Handle, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
OkButtonVisibility = (buttons == MessageBoxButton.OK || buttons == MessageBoxButton.OKCancel) ? Visibility.Visible : Visibility.Collapsed;
DetailsButtonVisibility = details == null ? Visibility.Collapsed : Visibility.Visible;
ErrorLinkVisibility = details != null && WindowCommands.ShowErrors.CanExecute(null, Application.Current.MainWindow) ? Visibility.Visible : Visibility.Collapsed;
+ HelpLinkVisibility = helpURL == null ? Visibility.Collapsed : Visibility.Visible;
YesNoButtonVisibility = (buttons == MessageBoxButton.YesNo || buttons == MessageBoxButton.YesNoCancel) ? Visibility.Visible : Visibility.Collapsed;
CancelButtonVisibility = (buttons == MessageBoxButton.OKCancel || buttons == MessageBoxButton.YesNoCancel) ? Visibility.Visible : Visibility.Collapsed;
@@ -134,29 +159,29 @@ private MessageWindow(string message, Icon icon, MessageBoxButton buttons, strin
}
}
- public static void ShowMessage(string message)
+ public static void ShowMessage(string message, string helpURL = null)
{
- Show(message, SystemIcons.Information, MessageBoxButton.OK);
+ Show(message, SystemIcons.Information, MessageBoxButton.OK, helpURL: helpURL);
}
- public static bool ShowMessageWithCancel(string message)
+ public static bool ShowMessageWithCancel(string message, string helpURL = null)
{
- return Show(message, SystemIcons.Information, MessageBoxButton.OKCancel) == MessageBoxResult.OK;
+ return Show(message, SystemIcons.Information, MessageBoxButton.OKCancel, helpURL: helpURL) == MessageBoxResult.OK;
}
- public static void ShowWarning(string message)
+ public static void ShowWarning(string message, string helpURL = null)
{
- Show(message, SystemIcons.Warning, MessageBoxButton.OK);
+ Show(message, SystemIcons.Warning, MessageBoxButton.OK, helpURL: helpURL);
}
- public static bool ShowWarningWithCancel(string message)
+ public static bool ShowWarningWithCancel(string message, string helpURL = null)
{
- return Show(message, SystemIcons.Warning, MessageBoxButton.OKCancel) == MessageBoxResult.OK;
+ return Show(message, SystemIcons.Warning, MessageBoxButton.OKCancel, helpURL: helpURL) == MessageBoxResult.OK;
}
- public static void ShowError(string message)
+ public static void ShowError(string message, string helpURL = null)
{
- Show(message, SystemIcons.Error, MessageBoxButton.OK);
+ Show(message, SystemIcons.Error, MessageBoxButton.OK, helpURL: helpURL);
}
public static void ShowException(Exception e)
@@ -164,19 +189,19 @@ public static void ShowException(Exception e)
Show(e.Message, SystemIcons.Error, MessageBoxButton.OK, e.ToString());
}
- public static bool ShowConfirm(string message)
+ public static bool ShowConfirm(string message, string helpURL = null)
{
- return Show(message, SystemIcons.Question, MessageBoxButton.YesNo) == MessageBoxResult.Yes;
+ return Show(message, SystemIcons.Question, MessageBoxButton.YesNo, helpURL: helpURL) == MessageBoxResult.Yes;
}
- public static MessageBoxResult ShowConfirmCancel(string message)
+ public static MessageBoxResult ShowConfirmCancel(string message, string helpURL = null)
{
- return Show(message, SystemIcons.Question, MessageBoxButton.YesNoCancel);
+ return Show(message, SystemIcons.Question, MessageBoxButton.YesNoCancel, helpURL: helpURL);
}
- private static MessageBoxResult Show(string message, Icon icon, MessageBoxButton buttons, string details = null)
+ private static MessageBoxResult Show(string message, Icon icon, MessageBoxButton buttons, string details = null, string helpURL = null)
{
- MessageWindow mw = new(message, icon, buttons, details);
+ MessageWindow mw = new(message, icon, buttons, details, helpURL);
mw.ShowDialog();
return mw._result;
}
@@ -225,4 +250,9 @@ private void ErrorButton_Click(object sender, RoutedEventArgs e)
{
WindowCommands.ShowErrors.Execute(null, Application.Current.MainWindow);
}
+
+ private void HelpLink_RequestNavigate(object sender, RequestNavigateEventArgs e)
+ {
+ ProcessUtils.OpenURL(HelpURL);
+ }
}
diff --git a/TRRandomizerView/Windows/OpenProgressWindow.xaml.cs b/TRRandomizerView/Windows/OpenProgressWindow.xaml.cs
index b550f24e4..11289c3b4 100644
--- a/TRRandomizerView/Windows/OpenProgressWindow.xaml.cs
+++ b/TRRandomizerView/Windows/OpenProgressWindow.xaml.cs
@@ -47,19 +47,17 @@ public string ProgressDescription
private volatile bool _complete;
private readonly string _folderPath;
- private readonly bool _performChecksumTest;
public Exception OpenException { get; private set; }
public TRRandomizerController OpenedController { get; private set; }
- public OpenProgressWindow(string folderPath, bool performChecksumTest)
+ public OpenProgressWindow(string folderPath)
{
InitializeComponent();
Owner = WindowUtils.GetActiveWindow(this);
DataContext = this;
_complete = false;
_folderPath = folderPath;
- _performChecksumTest = performChecksumTest;
}
private void Window_Loaded(object sender, RoutedEventArgs e)
@@ -75,7 +73,7 @@ private void Open()
try
{
- OpenedController = TRRandomizerCoord.Instance.Open(_folderPath, _performChecksumTest);
+ OpenedController = TRRandomizerCoord.Instance.Open(_folderPath);
}
catch (Exception e)
{
diff --git a/USING.md b/USING.md
index 11abeeadf..0c7071d63 100644
--- a/USING.md
+++ b/USING.md
@@ -7,7 +7,7 @@ On this page:
- [TR3](#tr3)
- [TR I-III Remastered](#tr-i-iii-remastered)
- [Installing the Randomizer](#installing-the-randomizer)
- - [Game Selection](#game-selection)
+- [Game Selection](#game-selection)
- [Randomizing](#randomizing)
- [Playing](#playing)
- [Re-randomizing](#re-randomizing)
@@ -18,7 +18,7 @@ On this page:
- [General Issues](#general-issues)
- [FAQs](#faqs)
-To play the randomizer, you will need to have the relevant TR1, TR2 or TR3 game(s) installed on your PC. It is important that the data files for these games are "clean", meaning that they should not have been modified by any other custom tool. If you are in any doubt about this, the first step you should take is reinstalling the game (for example in Steam or GoG).
+To play the randomizer, you will need to have the relevant TR1, TR2 or TR3 game(s) installed on your PC. It is important that the data files for these games are "clean", meaning that they should not have been modified by any other custom tool. If you are in any doubt about this, the first step you should take is to reinstall the game (for example in Steam or GoG). Please note that the rando team cannot offer overly specific advice on game reinstallation as every system is different; you should refer to instructions specific to your system (e.g. Steam/GoG) as required, and should have a reasonable understanding of how your own PC is configured.
Following is a brief video explanation of the setup, but be sure to read each of the following points as well.
@@ -154,8 +154,9 @@ If you encounter error messages during randomization, the most likely cause is u

-3. Reinstall the TR game from scratch (e.g. in Steam or GoG).
-4. Follow this guide carefully from the [beginning](USING.md#randomizer-setup).
+3. Uninstall the TR game from your system (e.g. in Steam or GoG). You should also manually uninstall any third-party modifications you may have applied as these may not be captured by the uninstall process.
+4. Reinstall the TR game from scratch (e.g. in Steam or GoG).
+5. Follow this guide carefully from the [beginning](USING.md#randomizer-setup).
If you continue to experience issues, we have a friendly community [Discord server](https://discord.gg/f4bUqwgcCN) where you can get help or you can [raise an issue](https://github.com/LostArtefacts/TR-Rando/issues/new) for investigation.