Add design migration for inverted gloss and specular, and a backup before doing that.

This commit is contained in:
Ottermandias 2024-08-09 16:01:44 +02:00
parent d7074c5791
commit 5cd224b164
5 changed files with 91 additions and 14 deletions

View file

@ -143,10 +143,10 @@ public class Configuration : IPluginConfiguration, ISavable
public static class Constants
{
public const int CurrentVersion = 6;
public const int CurrentVersion = 7;
public static readonly ISortMode<Design>[] ValidSortModes =
{
[
ISortMode<Design>.FoldersFirst,
ISortMode<Design>.Lexicographical,
new DesignFileSystem.CreationDate(),
@ -159,7 +159,7 @@ public class Configuration : IPluginConfiguration, ISavable
ISortMode<Design>.InverseFoldersLast,
ISortMode<Design>.InternalOrder,
ISortMode<Design>.InverseInternalOrder,
};
];
}
/// <summary> Convert SortMode Types to their name. </summary>

View file

@ -9,6 +9,7 @@ using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using OtterGui.Classes;
using Penumbra.GameData.Structs;
using Notification = OtterGui.Classes.Notification;
namespace Glamourer.Designs;
@ -34,7 +35,7 @@ public sealed class Design : DesignBase, ISavable, IDesignStandIn
}
// Metadata
public new const int FileVersion = 1;
public new const int FileVersion = 2;
public Guid Identifier { get; internal init; }
public DateTimeOffset CreationDate { get; internal init; }
@ -143,17 +144,81 @@ public sealed class Design : DesignBase, ISavable, IDesignStandIn
#region Deserialization
public static Design LoadDesign(CustomizeService customizations, ItemManager items, DesignLinkLoader linkLoader, JObject json)
public static Design LoadDesign(SaveService saveService, CustomizeService customizations, ItemManager items, DesignLinkLoader linkLoader, JObject json)
{
var version = json["FileVersion"]?.ToObject<int>() ?? 0;
return version switch
{
FileVersion => LoadDesignV1(customizations, items, linkLoader, json),
1 => LoadDesignV1(saveService, customizations, items, linkLoader, json),
FileVersion => LoadDesignV2(customizations, items, linkLoader, json),
_ => throw new Exception("The design to be loaded has no valid Version."),
};
}
private static Design LoadDesignV1(CustomizeService customizations, ItemManager items, DesignLinkLoader linkLoader, JObject json)
/// <summary> The values for gloss and specular strength were switched. Swap them for all appropriate designs. </summary>
private static Design LoadDesignV1(SaveService saveService, CustomizeService customizations, ItemManager items, DesignLinkLoader linkLoader, JObject json)
{
var design = LoadDesignV2(customizations, items, linkLoader, json);
var materialDesignData = design.GetMaterialDataRef();
if (materialDesignData.Values.Count == 0)
return design;
var materialData = materialDesignData.Clone();
// Guesstimate whether to migrate material rows:
// Update 1.3.0.10 released at that time, so any design last updated before that can be migrated.
if (design.LastEdit <= new DateTime(2024, 8, 7, 16, 0, 0, DateTimeKind.Utc))
{
Migrate("because it was saved the wrong way around before 1.3.0.10, and this design was not changed since that release.");
}
else
{
var hasNegativeGloss = false;
var hasNonPositiveGloss = false;
var specularLarger = 0;
foreach (var (key, value) in materialData.GetValues(MaterialValueIndex.Min(), MaterialValueIndex.Max()))
{
hasNegativeGloss |= value.Value.GlossStrength < 0;
hasNonPositiveGloss |= value.Value.GlossStrength <= 0;
if (value.Value.SpecularStrength > value.Value.GlossStrength)
++specularLarger;
}
// If there is any negative gloss, this is wrong and can be migrated.
if (hasNegativeGloss)
Migrate("because it had a negative Gloss value, which is not supported and thus probably outdated.");
// If there is any non-positive Gloss and some specular values that are larger, it is probably wrong and can be migrated.
else if (hasNonPositiveGloss && specularLarger > 0)
Migrate("because it had a zero Gloss value, and at least one Specular Strength larger than the Gloss, which is unusual.");
// If most of the specular strengths are larger, it is probably wrong and can be migrated.
else if (specularLarger > materialData.Values.Count / 2)
Migrate("because most of its Specular Strength values were larger than the Gloss values, which is unusual.");
}
return design;
void Migrate(string reason)
{
materialDesignData.Clear();
foreach (var (key, value) in materialData.GetValues(MaterialValueIndex.Min(), MaterialValueIndex.Max()))
{
var gloss = Math.Clamp(value.Value.SpecularStrength, 0, (float)Half.MaxValue);
var specularStrength = Math.Clamp(value.Value.GlossStrength, 0, (float)Half.MaxValue);
var colorRow = value.Value with
{
GlossStrength = gloss,
SpecularStrength = specularStrength,
};
materialDesignData.AddOrUpdateValue(MaterialValueIndex.FromKey(key), value with { Value = colorRow });
}
Glamourer.Messager.AddMessage(new Notification(
$"Swapped Gloss and Specular Strength in {materialDesignData.Values.Count} Rows in design {design.Incognito} {reason}",
NotificationType.Info));
saveService.Save(SaveType.ImmediateSync,design);
}
}
private static Design LoadDesignV2(CustomizeService customizations, ItemManager items, DesignLinkLoader linkLoader, JObject json)
{
var creationDate = json["CreationDate"]?.ToObject<DateTimeOffset>() ?? throw new ArgumentNullException("CreationDate");
@ -183,7 +248,7 @@ public sealed class Design : DesignBase, ISavable, IDesignStandIn
static string[] ParseTags(JObject json)
{
var tags = json["Tags"]?.ToObject<string[]>() ?? Array.Empty<string>();
var tags = json["Tags"]?.ToObject<string[]>() ?? [];
return tags.OrderBy(t => t).Distinct().ToArray();
}
}

View file

@ -13,6 +13,7 @@ using Penumbra.GameData.Structs;
namespace Glamourer.Designs;
public class DesignConverter(
SaveService saveService,
ItemManager _items,
DesignManager _designs,
CustomizeService _customize,
@ -69,7 +70,7 @@ public class DesignConverter(
try
{
var ret = jObject["Identifier"] != null
? Design.LoadDesign(_customize, _items, _linkLoader, jObject)
? Design.LoadDesign(saveService, _customize, _items, _linkLoader, jObject)
: DesignBase.LoadDesignBase(_customize, _items, jObject);
if (!customize)
@ -100,7 +101,7 @@ public class DesignConverter(
case (byte)'{':
var jObj1 = JObject.Parse(Encoding.UTF8.GetString(bytes));
ret = jObj1["Identifier"] != null
? Design.LoadDesign(_customize, _items, _linkLoader, jObj1)
? Design.LoadDesign(saveService, _customize, _items, _linkLoader, jObj1)
: DesignBase.LoadDesignBase(_customize, _items, jObj1);
break;
case 1:
@ -115,7 +116,7 @@ public class DesignConverter(
var jObj2 = JObject.Parse(decompressed);
Debug.Assert(version == 3);
ret = jObj2["Identifier"] != null
? Design.LoadDesign(_customize, _items, _linkLoader, jObj2)
? Design.LoadDesign(saveService, _customize, _items, _linkLoader, jObj2)
: DesignBase.LoadDesignBase(_customize, _items, jObj2);
break;
}
@ -126,7 +127,7 @@ public class DesignConverter(
var jObj2 = JObject.Parse(decompressed);
Debug.Assert(version == 5);
ret = jObj2["Identifier"] != null
? Design.LoadDesign(_customize, _items, _linkLoader, jObj2)
? Design.LoadDesign(saveService, _customize, _items, _linkLoader, jObj2)
: DesignBase.LoadDesignBase(_customize, _items, jObj2);
break;
}
@ -136,7 +137,7 @@ public class DesignConverter(
var jObj2 = JObject.Parse(decompressed);
Debug.Assert(version == 6);
ret = jObj2["Identifier"] != null
? Design.LoadDesign(_customize, _items, _linkLoader, jObj2)
? Design.LoadDesign(saveService, _customize, _items, _linkLoader, jObj2)
: DesignBase.LoadDesignBase(_customize, _items, jObj2);
break;
}

View file

@ -53,7 +53,7 @@ public sealed class DesignManager : DesignEditor
{
var text = File.ReadAllText(f.FullName);
var data = JObject.Parse(text);
var design = Design.LoadDesign(Customizations, Items, linkLoader, data);
var design = Design.LoadDesign(SaveService, Customizations, Items, linkLoader, data);
designs.Value!.Add((design, f.FullName));
}
catch (Exception ex)

View file

@ -23,9 +23,20 @@ public class ConfigMigrationService(SaveService saveService, FixedDesignMigrator
MigrateV2To4();
MigrateV4To5();
MigrateV5To6();
MigrateV6To7();
AddColors(config, true);
}
private void MigrateV6To7()
{
if (_config.Version > 6)
return;
// Do not actually change anything in the config, just create a backup before designs are migrated.
backupService.CreateMigrationBackup("pre_gloss_specular_migration");
_config.Version = 7;
}
private void MigrateV5To6()
{
if (_config.Version > 5)