diff --git a/src/TEdit.Terraria/World.cs b/src/TEdit.Terraria/World.cs index 1e437580..980673a8 100644 --- a/src/TEdit.Terraria/World.cs +++ b/src/TEdit.Terraria/World.cs @@ -48,8 +48,85 @@ public World(int height, int width, string title, int seed = -1) CharacterNames.Clear(); } - public static Task SaveAsync(World world, string filename, bool resetTime = false, int versionOverride = 0, bool incrementRevision = true, IProgress? progress = null) - => Task.Run(() => Save(world, filename, resetTime, versionOverride, incrementRevision, progress)); + public static async Task SaveAsync(World world, string filename, bool resetTime = false, int versionOverride = 0, bool incrementRevision = true, IProgress? progress = null) + { + await Task.Run(() => + { + lock (_fileLock) + { + uint currentWorldVersion = world.Version; + try + { + // Set the world version for this save + if (versionOverride > 0) + { + world.Version = (uint)(versionOverride); + } + + if (resetTime) + { + progress?.Report(new ProgressChangedEventArgs(0, "Resetting Time...")); + // world.ResetTime(); + } + + if (filename == null) + return; + string temp = filename + ".tmp"; + using (var fs = new FileStream(temp, FileMode.Create)) + { + using (var bw = new BinaryWriter(fs)) + { + if (versionOverride < 0 || world.IsV0 || world.Version == 38) + { + bool addLight = (currentWorldVersion > world.Version); // Check if world is being downgraded. + world.Version = (uint)Math.Abs(versionOverride); + SaveV0(world, bw, addLight, progress); + } + else if (world.Version > 87 && world.Version != 38) + { + SaveV2(world, bw, incrementRevision, progress); + } + else + { + bool addLight = (currentWorldVersion >= 87); // Check if world is being downgraded. + SaveV1(world, bw, addLight, progress); + } + + if (world.IsConsole) + { + ConsoleCompressor.CompressStream(fs); + } + + bw.Close(); + fs.Close(); + // Make a backup of the current file if it exists + if (File.Exists(filename)) + { + string backup = filename + "." + DateTime.Now.ToString("yyyyMMddHHmmss") + ".TEdit"; + File.Copy(filename, backup, true); + } + + // Replace the actual file with temp save file + File.Copy(temp, filename, true); + // Delete temp save file + File.Delete(temp); + progress?.Report(new ProgressChangedEventArgs(100, "World Save Complete.")); + } + } + + world.LastSave = File.GetLastWriteTimeUtc(filename); + } + finally + { + // Restore the version + if (versionOverride > 0) + { + world.Version = currentWorldVersion; + } + } + } + }); + } public static void Save( World world, diff --git a/src/TEdit/ViewModel/WorldViewModel.cs b/src/TEdit/ViewModel/WorldViewModel.cs index 21a031df..3243f3cd 100644 --- a/src/TEdit/ViewModel/WorldViewModel.cs +++ b/src/TEdit/ViewModel/WorldViewModel.cs @@ -1140,7 +1140,6 @@ private void SaveWorldThreaded(string filename, uint version = 0) Task.Factory.StartNew(async () => { ErrorLogging.TelemetryClient?.TrackEvent(nameof(SaveWorldThreaded)); - try { OnProgressChanged(CurrentWorld, new ProgressChangedEventArgs(0, "Validating World...")); @@ -1148,29 +1147,22 @@ private void SaveWorldThreaded(string filename, uint version = 0) } catch (ArgumentOutOfRangeException err) { - string msg = "There is a problem in your world.\r\n" + - $"{err.ParamName}\r\n" + - $"This world may not open in Terraria\r\n" + - "Would you like to save anyways??\r\n"; - if (MessageBox.Show(msg, "World Error", MessageBoxButton.YesNo, MessageBoxImage.Error) != - MessageBoxResult.Yes) + string msg = "There is a problem in your world.\r\n" + $"{err.ParamName}\r\n" + $"This world may not open in Terraria\r\n" + "Would you like to save anyways??\r\n"; + if (MessageBox.Show(msg, "World Error", MessageBoxButton.YesNo, MessageBoxImage.Error) != MessageBoxResult.Yes) return; } catch (Exception ex) { - string msg = "There is a problem in your world.\r\n" + - $"{ex.Message}\r\n" + - "This world may not open in Terraria\r\n" + - "Would you like to save anyways??\r\n"; - - if (MessageBox.Show(msg, "World Error", MessageBoxButton.YesNo, MessageBoxImage.Error) != - MessageBoxResult.Yes) + string msg = "There is a problem in your world.\r\n" + $"{ex.Message}\r\n" + "This world may not open in Terraria\r\n" + "Would you like to save anyways??\r\n"; + if (MessageBox.Show(msg, "World Error", MessageBoxButton.YesNo, MessageBoxImage.Error) != MessageBoxResult.Yes) return; } - World.Save(CurrentWorld, filename, versionOverride: (int)version); - }) - .ContinueWith(t => CommandManager.InvalidateRequerySuggested(), TaskFactoryHelper.UiTaskScheduler); + await World.SaveAsync(CurrentWorld, filename, versionOverride: (int)version, progress: new Progress(e => + { + DispatcherHelper.CheckBeginInvokeOnUI(() => OnProgressChanged(CurrentWorld, e)); + })); + }).ContinueWith(t => CommandManager.InvalidateRequerySuggested(), TaskFactoryHelper.UiTaskScheduler); } public void LoadWorld(string filename)