## Adds Auto Archiving Backups are archived once an hour, day, and month. Archives older than 60 days are pruned automatically. _Note: Automatic pruning is off by default_ ### Archive compression format The following formats are supported: * Zstd (The fastest with best compression ratio) * GZip * Zip * None (Tar) _Note: By default archives use [zstandard](http://facebook.github.io/zstd/) format. The archive format can be changed in modernuo.json `autoArchive.compressionFormat`_ ### Restoring world from archive Move the archive to the Saves folder (tar.zst file). On startup the server will extract the file and restore the latest save. See pictures below. ### Manually extracting an archives #### Windows * Use the latest version of [7-zip w/ ZStandard](https://github.com/mcmilk/7-Zip-zstd/releases/latest) 1. Extract the `.tar.zst` file. 2. Extract the `.tar` file. (Yes you have to do it in two steps) * On Windows 10 you can use the command line. `zstd.exe` is in the Assemblies folder after building ModernUO. 1. `tar --use-compress-program "Distribution\Assemblies\zstd.exe -d" -xvf "Archives\Hourly\archivefile.tar.zst" -C "path to where you want to extract it"` #### Mac * Install [Keka](https://www.keka.io) 1. Drop the .tar.zst onto the keka interface. #### Linux 1. Install zstd from a package manager 2. Run `tar -I zstd -xvf "Archives\Hourly\archivefile.tar.zst" -C "path to where you want to extract it"` ### Other changes * Changes Autosave to occur at the same time no matter when the server is booted. * Adds `[SaveFrequency <delay> [warning]`command to set save frequency and warning frequency in-game. * Adds support for time zones that are configurable. The system timezone can also be manually configured. Check `TimeZoneHandler.cs` for details. <img width="257" alt="Screen Shot 2021-09-22 at 11 23 18 PM" src="https://user-images.githubusercontent.com/3953314/134464929-a5bf3cd8-2ef0-4476-a9ad-71d0816a19ac.png"> <img width="241" alt="Screen Shot 2021-09-22 at 11 23 39 PM" src="https://user-images.githubusercontent.com/3953314/134464945-5f6f96dc-3d1e-434d-8256-5c6b3705e786.png"> <img width="836" alt="Screen Shot 2021-09-22 at 11 34 39 PM" src="https://user-images.githubusercontent.com/3953314/134464957-625e57f2-ef47-4ca1-a0a7-cd40c9b6539c.png"> <img width="631" alt="Screen Shot 2021-09-22 at 11 34 50 PM" src="https://user-images.githubusercontent.com/3953314/134464969-b2d65c0d-f8f5-497a-a832-5d805e8e0b22.png">
132 lines
3.6 KiB
C#
132 lines
3.6 KiB
C#
using System;
|
|
using Server.Misc;
|
|
|
|
namespace Server.Saves
|
|
{
|
|
public class AutoSave : Timer
|
|
{
|
|
private static Timer _autoSave;
|
|
private static bool _enabled;
|
|
private static DateTime _nextSave;
|
|
|
|
public static TimeSpan Delay { get; private set; }
|
|
public static TimeSpan Warning { get; private set; }
|
|
|
|
public static bool SavesEnabled
|
|
{
|
|
get => _enabled;
|
|
set
|
|
{
|
|
_enabled = value;
|
|
|
|
if (value)
|
|
{
|
|
SetNextSave(Core.Now.ToSystemLocalTime());
|
|
_autoSave ??= new AutoSave();
|
|
_autoSave.Start();
|
|
}
|
|
else
|
|
{
|
|
_autoSave?.Stop();
|
|
_autoSave = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void Configure()
|
|
{
|
|
Delay = ServerConfiguration.GetOrUpdateSetting("autosave.saveDelay", TimeSpan.FromMinutes(5.0));
|
|
Warning = ServerConfiguration.GetOrUpdateSetting("autosave.warningDelay", TimeSpan.Zero);
|
|
}
|
|
|
|
public static void Initialize()
|
|
{
|
|
SavesEnabled = true;
|
|
}
|
|
|
|
public static void ResetAutoSave(TimeSpan saveDelay, TimeSpan warningDelay)
|
|
{
|
|
if (saveDelay != Delay || warningDelay != Warning)
|
|
{
|
|
Delay = saveDelay;
|
|
Warning = warningDelay;
|
|
|
|
ServerConfiguration.SetSetting("autosave.saveDelay", Delay);
|
|
ServerConfiguration.SetSetting("autosave.warningDelay", Warning);
|
|
}
|
|
|
|
SavesEnabled = true;
|
|
}
|
|
|
|
private static void SetNextSave(DateTime now)
|
|
{
|
|
var timeOfDay = now.TimeOfDay;
|
|
var delay = Delay.Ticks;
|
|
|
|
_nextSave = (now + TimeSpan.FromTicks(delay - timeOfDay.Ticks % delay) - Warning).ToUniversalTime();
|
|
}
|
|
|
|
public AutoSave() : base(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.0))
|
|
{
|
|
}
|
|
|
|
protected override void OnTick()
|
|
{
|
|
if (_nextSave > Core.Now)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (SavesEnabled && !AutoRestart.Restarting && !Core.Closing && World.Running)
|
|
{
|
|
if (Warning > TimeSpan.Zero)
|
|
{
|
|
BroadcastWarning();
|
|
StartTimer(Warning, Save);
|
|
}
|
|
else
|
|
{
|
|
Save();
|
|
}
|
|
}
|
|
|
|
_nextSave += Delay;
|
|
}
|
|
|
|
private static void BroadcastWarning()
|
|
{
|
|
var s = (int)Warning.TotalSeconds;
|
|
var m = s / 60;
|
|
s %= 60;
|
|
|
|
if (m > 0 && s > 0)
|
|
{
|
|
World.Broadcast(
|
|
0x35,
|
|
true,
|
|
"The world will save in {0} minute{1} and {2} second{3}.",
|
|
m,
|
|
m != 1 ? "s" : "",
|
|
s,
|
|
s != 1 ? "s" : ""
|
|
);
|
|
}
|
|
else if (m > 0)
|
|
{
|
|
World.Broadcast(0x35, true, "The world will save in {0} minute{1}.", m, m != 1 ? "s" : "");
|
|
}
|
|
else
|
|
{
|
|
World.Broadcast(0x35, true, "The world will save in {0} second{1}.", s, s != 1 ? "s" : "");
|
|
}
|
|
}
|
|
|
|
public static void Save()
|
|
{
|
|
if (!AutoRestart.Restarting && World.Running)
|
|
{
|
|
World.Save();
|
|
}
|
|
}
|
|
}
|
|
}
|