Respect ascii setting for group names.

This commit is contained in:
Ottermandias 2023-12-12 21:05:08 +01:00
parent 76cb09b3b5
commit 173b4d7306
10 changed files with 70 additions and 58 deletions

View file

@ -7,15 +7,17 @@ namespace Penumbra.Mods.Editor;
public class DuplicateManager
{
private readonly Configuration _config;
private readonly SaveService _saveService;
private readonly ModManager _modManager;
private readonly SHA256 _hasher = SHA256.Create();
private readonly List<(FullPath[] Paths, long Size, byte[] Hash)> _duplicates = new();
public DuplicateManager(ModManager modManager, SaveService saveService)
public DuplicateManager(ModManager modManager, SaveService saveService, Configuration config)
{
_modManager = modManager;
_saveService = saveService;
_config = config;
}
public IReadOnlyList<(FullPath[] Paths, long Size, byte[] Hash)> Duplicates
@ -82,7 +84,7 @@ public class DuplicateManager
{
var sub = (SubMod)subMod;
sub.FileData = dict;
_saveService.ImmediateSaveSync(new ModSaveGroup(mod, groupIdx));
_saveService.ImmediateSaveSync(new ModSaveGroup(mod, groupIdx, _config.ReplaceNonAsciiOnImport));
}
}

View file

@ -83,7 +83,7 @@ public static partial class ModMigration
creator.IncorporateMetaChanges(mod.Default, mod.ModPath, true);
foreach (var (_, index) in mod.Groups.WithIndex())
saveService.ImmediateSave(new ModSaveGroup(mod, index));
saveService.ImmediateSave(new ModSaveGroup(mod, index, creator.Config.ReplaceNonAsciiOnImport));
// Delete meta files.
foreach (var file in seenMetaFiles.Where(f => f.Exists))
@ -111,7 +111,7 @@ public static partial class ModMigration
}
fileVersion = 1;
saveService.ImmediateSave(new ModSaveGroup(mod, -1));
saveService.ImmediateSave(new ModSaveGroup(mod, -1, creator.Config.ReplaceNonAsciiOnImport));
return true;
}

View file

@ -33,13 +33,15 @@ public enum ModOptionChangeType
public class ModOptionEditor
{
private readonly Configuration _config;
private readonly CommunicatorService _communicator;
private readonly SaveService _saveService;
public ModOptionEditor(CommunicatorService communicator, SaveService saveService)
public ModOptionEditor(CommunicatorService communicator, SaveService saveService, Configuration config)
{
_communicator = communicator;
_saveService = saveService;
_config = config;
}
/// <summary> Change the type of a group given by mod and index to type, if possible. </summary>
@ -50,7 +52,7 @@ public class ModOptionEditor
return;
mod.Groups[groupIdx] = group.Convert(type);
_saveService.QueueSave(new ModSaveGroup(mod, groupIdx));
_saveService.QueueSave(new ModSaveGroup(mod, groupIdx, _config.ReplaceNonAsciiOnImport));
_communicator.ModOptionChanged.Invoke(ModOptionChangeType.GroupTypeChanged, mod, groupIdx, -1, -1);
}
@ -62,7 +64,7 @@ public class ModOptionEditor
return;
group.DefaultSettings = defaultOption;
_saveService.QueueSave(new ModSaveGroup(mod, groupIdx));
_saveService.QueueSave(new ModSaveGroup(mod, groupIdx, _config.ReplaceNonAsciiOnImport));
_communicator.ModOptionChanged.Invoke(ModOptionChangeType.DefaultOptionChanged, mod, groupIdx, -1, -1);
}
@ -74,7 +76,7 @@ public class ModOptionEditor
if (oldName == newName || !VerifyFileName(mod, group, newName, true))
return;
_saveService.ImmediateDelete(new ModSaveGroup(mod, groupIdx));
_saveService.ImmediateDelete(new ModSaveGroup(mod, groupIdx, _config.ReplaceNonAsciiOnImport));
var _ = group switch
{
SingleModGroup s => s.Name = newName,
@ -82,7 +84,7 @@ public class ModOptionEditor
_ => newName,
};
_saveService.ImmediateSave(new ModSaveGroup(mod, groupIdx));
_saveService.ImmediateSave(new ModSaveGroup(mod, groupIdx, _config.ReplaceNonAsciiOnImport));
_communicator.ModOptionChanged.Invoke(ModOptionChangeType.GroupRenamed, mod, groupIdx, -1, -1);
}
@ -105,7 +107,7 @@ public class ModOptionEditor
Name = newName,
Priority = maxPriority,
});
_saveService.ImmediateSave(new ModSaveGroup(mod, mod.Groups.Count - 1));
_saveService.ImmediateSave(new ModSaveGroup(mod, mod.Groups.Count - 1, _config.ReplaceNonAsciiOnImport));
_communicator.ModOptionChanged.Invoke(ModOptionChangeType.GroupAdded, mod, mod.Groups.Count - 1, -1, -1);
}
@ -129,7 +131,7 @@ public class ModOptionEditor
_communicator.ModOptionChanged.Invoke(ModOptionChangeType.PrepareChange, mod, groupIdx, -1, -1);
mod.Groups.RemoveAt(groupIdx);
UpdateSubModPositions(mod, groupIdx);
_saveService.SaveAllOptionGroups(mod, false);
_saveService.SaveAllOptionGroups(mod, false, _config.ReplaceNonAsciiOnImport);
_communicator.ModOptionChanged.Invoke(ModOptionChangeType.GroupDeleted, mod, groupIdx, -1, -1);
}
@ -140,7 +142,7 @@ public class ModOptionEditor
return;
UpdateSubModPositions(mod, Math.Min(groupIdxFrom, groupIdxTo));
_saveService.SaveAllOptionGroups(mod, false);
_saveService.SaveAllOptionGroups(mod, false, _config.ReplaceNonAsciiOnImport);
_communicator.ModOptionChanged.Invoke(ModOptionChangeType.GroupMoved, mod, groupIdxFrom, -1, groupIdxTo);
}
@ -157,7 +159,7 @@ public class ModOptionEditor
MultiModGroup m => m.Description = newDescription,
_ => newDescription,
};
_saveService.QueueSave(new ModSaveGroup(mod, groupIdx));
_saveService.QueueSave(new ModSaveGroup(mod, groupIdx, _config.ReplaceNonAsciiOnImport));
_communicator.ModOptionChanged.Invoke(ModOptionChangeType.DisplayChange, mod, groupIdx, -1, -1);
}
@ -170,7 +172,7 @@ public class ModOptionEditor
return;
s.Description = newDescription;
_saveService.QueueSave(new ModSaveGroup(mod, groupIdx));
_saveService.QueueSave(new ModSaveGroup(mod, groupIdx, _config.ReplaceNonAsciiOnImport));
_communicator.ModOptionChanged.Invoke(ModOptionChangeType.DisplayChange, mod, groupIdx, optionIdx, -1);
}
@ -187,7 +189,7 @@ public class ModOptionEditor
MultiModGroup m => m.Priority = newPriority,
_ => newPriority,
};
_saveService.QueueSave(new ModSaveGroup(mod, groupIdx));
_saveService.QueueSave(new ModSaveGroup(mod, groupIdx, _config.ReplaceNonAsciiOnImport));
_communicator.ModOptionChanged.Invoke(ModOptionChangeType.PriorityChanged, mod, groupIdx, -1, -1);
}
@ -204,7 +206,7 @@ public class ModOptionEditor
return;
m.PrioritizedOptions[optionIdx] = (m.PrioritizedOptions[optionIdx].Mod, newPriority);
_saveService.QueueSave(new ModSaveGroup(mod, groupIdx));
_saveService.QueueSave(new ModSaveGroup(mod, groupIdx, _config.ReplaceNonAsciiOnImport));
_communicator.ModOptionChanged.Invoke(ModOptionChangeType.PriorityChanged, mod, groupIdx, optionIdx, -1);
return;
}
@ -230,7 +232,7 @@ public class ModOptionEditor
break;
}
_saveService.QueueSave(new ModSaveGroup(mod, groupIdx));
_saveService.QueueSave(new ModSaveGroup(mod, groupIdx, _config.ReplaceNonAsciiOnImport));
_communicator.ModOptionChanged.Invoke(ModOptionChangeType.DisplayChange, mod, groupIdx, optionIdx, -1);
}
@ -250,7 +252,7 @@ public class ModOptionEditor
break;
}
_saveService.QueueSave(new ModSaveGroup(mod, groupIdx));
_saveService.QueueSave(new ModSaveGroup(mod, groupIdx, _config.ReplaceNonAsciiOnImport));
_communicator.ModOptionChanged.Invoke(ModOptionChangeType.OptionAdded, mod, groupIdx, group.Count - 1, -1);
}
@ -296,7 +298,7 @@ public class ModOptionEditor
break;
}
_saveService.QueueSave(new ModSaveGroup(mod, groupIdx));
_saveService.QueueSave(new ModSaveGroup(mod, groupIdx, _config.ReplaceNonAsciiOnImport));
_communicator.ModOptionChanged.Invoke(ModOptionChangeType.OptionAdded, mod, groupIdx, group.Count - 1, -1);
}
@ -317,7 +319,7 @@ public class ModOptionEditor
}
group.UpdatePositions(optionIdx);
_saveService.QueueSave(new ModSaveGroup(mod, groupIdx));
_saveService.QueueSave(new ModSaveGroup(mod, groupIdx, _config.ReplaceNonAsciiOnImport));
_communicator.ModOptionChanged.Invoke(ModOptionChangeType.OptionDeleted, mod, groupIdx, optionIdx, -1);
}
@ -328,7 +330,7 @@ public class ModOptionEditor
if (!group.MoveOption(optionIdxFrom, optionIdxTo))
return;
_saveService.QueueSave(new ModSaveGroup(mod, groupIdx));
_saveService.QueueSave(new ModSaveGroup(mod, groupIdx, _config.ReplaceNonAsciiOnImport));
_communicator.ModOptionChanged.Invoke(ModOptionChangeType.OptionMoved, mod, groupIdx, optionIdxFrom, optionIdxTo);
}
@ -342,7 +344,7 @@ public class ModOptionEditor
_communicator.ModOptionChanged.Invoke(ModOptionChangeType.PrepareChange, mod, groupIdx, optionIdx, -1);
subMod.ManipulationData.SetTo(manipulations);
_saveService.QueueSave(new ModSaveGroup(mod, groupIdx));
_saveService.QueueSave(new ModSaveGroup(mod, groupIdx, _config.ReplaceNonAsciiOnImport));
_communicator.ModOptionChanged.Invoke(ModOptionChangeType.OptionMetaChanged, mod, groupIdx, optionIdx, -1);
}
@ -355,7 +357,7 @@ public class ModOptionEditor
_communicator.ModOptionChanged.Invoke(ModOptionChangeType.PrepareChange, mod, groupIdx, optionIdx, -1);
subMod.FileData.SetTo(replacements);
_saveService.QueueSave(new ModSaveGroup(mod, groupIdx));
_saveService.QueueSave(new ModSaveGroup(mod, groupIdx, _config.ReplaceNonAsciiOnImport));
_communicator.ModOptionChanged.Invoke(ModOptionChangeType.OptionFilesChanged, mod, groupIdx, optionIdx, -1);
}
@ -367,7 +369,7 @@ public class ModOptionEditor
subMod.FileData.AddFrom(additions);
if (oldCount != subMod.FileData.Count)
{
_saveService.QueueSave(new ModSaveGroup(mod, groupIdx));
_saveService.QueueSave(new ModSaveGroup(mod, groupIdx, _config.ReplaceNonAsciiOnImport));
_communicator.ModOptionChanged.Invoke(ModOptionChangeType.OptionFilesAdded, mod, groupIdx, optionIdx, -1);
}
}
@ -381,7 +383,7 @@ public class ModOptionEditor
_communicator.ModOptionChanged.Invoke(ModOptionChangeType.PrepareChange, mod, groupIdx, optionIdx, -1);
subMod.FileSwapData.SetTo(swaps);
_saveService.QueueSave(new ModSaveGroup(mod, groupIdx));
_saveService.QueueSave(new ModSaveGroup(mod, groupIdx, _config.ReplaceNonAsciiOnImport));
_communicator.ModOptionChanged.Invoke(ModOptionChangeType.OptionSwapsChanged, mod, groupIdx, optionIdx, -1);
}

View file

@ -16,16 +16,18 @@ using Penumbra.String.Classes;
namespace Penumbra.Mods;
public partial class ModCreator(SaveService _saveService, Configuration _config, ModDataEditor _dataEditor, MetaFileManager _metaFileManager,
public partial class ModCreator(SaveService _saveService, Configuration config, ModDataEditor _dataEditor, MetaFileManager _metaFileManager,
IGamePathParser _gamePathParser)
{
public readonly Configuration Config = config;
/// <summary> Creates directory and files necessary for a new mod without adding it to the manager. </summary>
public DirectoryInfo? CreateEmptyMod(DirectoryInfo basePath, string newName, string description = "")
{
try
{
var newDir = CreateModFolder(basePath, newName, _config.ReplaceNonAsciiOnImport, true);
_dataEditor.CreateMeta(newDir, newName, _config.DefaultModAuthor, description, "1.0", string.Empty);
var newDir = CreateModFolder(basePath, newName, Config.ReplaceNonAsciiOnImport, true);
_dataEditor.CreateMeta(newDir, newName, Config.DefaultModAuthor, description, "1.0", string.Empty);
CreateDefaultFiles(newDir);
return newDir;
}
@ -86,7 +88,8 @@ public partial class ModCreator(SaveService _saveService, Configuration _config,
if (group != null && mod.Groups.All(g => g.Name != group.Name))
{
changes = changes
|| _saveService.FileNames.OptionGroupFile(mod.ModPath.FullName, mod.Groups.Count, group.Name) != file.FullName;
|| _saveService.FileNames.OptionGroupFile(mod.ModPath.FullName, mod.Groups.Count, group.Name, true)
!= Path.Combine(file.DirectoryName!, ReplaceBadXivSymbols(file.Name, true));
mod.Groups.Add(group);
}
else
@ -96,13 +99,13 @@ public partial class ModCreator(SaveService _saveService, Configuration _config,
}
if (changes)
_saveService.SaveAllOptionGroups(mod, true);
_saveService.SaveAllOptionGroups(mod, true, Config.ReplaceNonAsciiOnImport);
}
/// <summary> Load the default option for a given mod.</summary>
public void LoadDefaultOption(Mod mod)
{
var defaultFile = _saveService.FileNames.OptionGroupFile(mod, -1);
var defaultFile = _saveService.FileNames.OptionGroupFile(mod, -1, Config.ReplaceNonAsciiOnImport);
mod.Default.SetPosition(-1, 0);
try
{
@ -161,8 +164,8 @@ public partial class ModCreator(SaveService _saveService, Configuration _config,
if (!changes)
return;
_saveService.SaveAllOptionGroups(mod, false);
_saveService.ImmediateSaveSync(new ModSaveGroup(mod.ModPath, mod.Default));
_saveService.SaveAllOptionGroups(mod, false, Config.ReplaceNonAsciiOnImport);
_saveService.ImmediateSaveSync(new ModSaveGroup(mod.ModPath, mod.Default, Config.ReplaceNonAsciiOnImport));
}
@ -188,7 +191,7 @@ public partial class ModCreator(SaveService _saveService, Configuration _config,
continue;
var meta = new TexToolsMeta(_metaFileManager, _gamePathParser, File.ReadAllBytes(file.FullName),
_config.KeepDefaultMetaChanges);
Config.KeepDefaultMetaChanges);
Penumbra.Log.Verbose(
$"Incorporating {file} as Metadata file of {meta.MetaManipulations.Count} manipulations {deleteString}");
deleteList.Add(file.FullName);
@ -201,7 +204,7 @@ public partial class ModCreator(SaveService _saveService, Configuration _config,
continue;
var rgsp = TexToolsMeta.FromRgspFile(_metaFileManager, file.FullName, File.ReadAllBytes(file.FullName),
_config.KeepDefaultMetaChanges);
Config.KeepDefaultMetaChanges);
Penumbra.Log.Verbose(
$"Incorporating {file} as racial scaling file of {rgsp.MetaManipulations.Count} manipulations {deleteString}");
deleteList.Add(file.FullName);
@ -246,7 +249,7 @@ public partial class ModCreator(SaveService _saveService, Configuration _config,
DefaultSettings = defaultSettings,
};
group.PrioritizedOptions.AddRange(subMods.OfType<SubMod>().Select((s, idx) => (s, idx)));
_saveService.ImmediateSaveSync(new ModSaveGroup(baseFolder, group, index));
_saveService.ImmediateSaveSync(new ModSaveGroup(baseFolder, group, index, Config.ReplaceNonAsciiOnImport));
break;
}
case GroupType.Single:
@ -259,7 +262,7 @@ public partial class ModCreator(SaveService _saveService, Configuration _config,
DefaultSettings = defaultSettings,
};
group.OptionData.AddRange(subMods.OfType<SubMod>());
_saveService.ImmediateSaveSync(new ModSaveGroup(baseFolder, group, index));
_saveService.ImmediateSaveSync(new ModSaveGroup(baseFolder, group, index, Config.ReplaceNonAsciiOnImport));
break;
}
}
@ -306,7 +309,7 @@ public partial class ModCreator(SaveService _saveService, Configuration _config,
}
IncorporateMetaChanges(mod.Default, directory, true);
_saveService.ImmediateSaveSync(new ModSaveGroup(mod, -1));
_saveService.ImmediateSaveSync(new ModSaveGroup(mod, -1, Config.ReplaceNonAsciiOnImport));
}
/// <summary> Return the name of a new valid directory based on the base directory and the given name. </summary>

View file

@ -39,8 +39,9 @@ public readonly struct ModSaveGroup : ISavable
private readonly IModGroup? _group;
private readonly int _groupIdx;
private readonly ISubMod? _defaultMod;
private readonly bool _onlyAscii;
public ModSaveGroup(Mod mod, int groupIdx)
public ModSaveGroup(Mod mod, int groupIdx, bool onlyAscii)
{
_basePath = mod.ModPath;
_groupIdx = groupIdx;
@ -48,24 +49,27 @@ public readonly struct ModSaveGroup : ISavable
_defaultMod = mod.Default;
else
_group = mod.Groups[_groupIdx];
_onlyAscii = onlyAscii;
}
public ModSaveGroup(DirectoryInfo basePath, IModGroup group, int groupIdx)
public ModSaveGroup(DirectoryInfo basePath, IModGroup group, int groupIdx, bool onlyAscii)
{
_basePath = basePath;
_group = group;
_groupIdx = groupIdx;
_basePath = basePath;
_group = group;
_groupIdx = groupIdx;
_onlyAscii = onlyAscii;
}
public ModSaveGroup(DirectoryInfo basePath, ISubMod @default)
public ModSaveGroup(DirectoryInfo basePath, ISubMod @default, bool onlyAscii)
{
_basePath = basePath;
_groupIdx = -1;
_defaultMod = @default;
_onlyAscii = onlyAscii;
}
public string ToFilename(FilenameService fileNames)
=> fileNames.OptionGroupFile(_basePath.FullName, _groupIdx, _group?.Name ?? string.Empty);
=> fileNames.OptionGroupFile(_basePath.FullName, _groupIdx, _group?.Name ?? string.Empty, _onlyAscii);
public void Save(StreamWriter writer)
{

View file

@ -86,7 +86,7 @@ public class TemporaryMod : IMod
foreach (var manip in collection.MetaCache?.Manipulations ?? Array.Empty<MetaManipulation>())
defaultMod.ManipulationData.Add(manip);
saveService.ImmediateSave(new ModSaveGroup(dir, defaultMod));
saveService.ImmediateSave(new ModSaveGroup(dir, defaultMod, config.ReplaceNonAsciiOnImport));
modManager.AddMod(dir);
Penumbra.Log.Information($"Successfully generated mod {mod.Name} at {mod.ModPath.FullName} for collection {collection.Name}.");
}

View file

@ -60,14 +60,14 @@ public class FilenameService(DalamudPluginInterface pi)
=> Path.Combine(modDirectory, "meta.json");
/// <summary> Obtain the path of the file describing a given option group by its index and the mod. If the index is < 0, return the path for the default mod file. </summary>
public string OptionGroupFile(Mod mod, int index)
=> OptionGroupFile(mod.ModPath.FullName, index, index >= 0 ? mod.Groups[index].Name : string.Empty);
public string OptionGroupFile(Mod mod, int index, bool onlyAscii)
=> OptionGroupFile(mod.ModPath.FullName, index, index >= 0 ? mod.Groups[index].Name : string.Empty, onlyAscii);
/// <summary> Obtain the path of the file describing a given option group by its index, name and basepath. If the index is < 0, return the path for the default mod file. </summary>
public string OptionGroupFile(string basePath, int index, string name)
public string OptionGroupFile(string basePath, int index, string name, bool onlyAscii)
{
var fileName = index >= 0
? $"group_{index + 1:D3}_{name.RemoveInvalidPathSymbols().ToLowerInvariant()}.json"
? $"group_{index + 1:D3}_{ModCreator.ReplaceBadXivSymbols(name.ToLowerInvariant(), onlyAscii)}.json"
: "default_mod.json";
return Path.Combine(basePath, fileName);
}

View file

@ -18,7 +18,7 @@ public sealed class SaveService : SaveServiceBase<FilenameService>
{ }
/// <summary> Immediately delete all existing option group files for a mod and save them anew. </summary>
public void SaveAllOptionGroups(Mod mod, bool backup)
public void SaveAllOptionGroups(Mod mod, bool backup, bool onlyAscii)
{
foreach (var file in FileNames.GetOptionGroupFiles(mod))
{
@ -37,7 +37,7 @@ public sealed class SaveService : SaveServiceBase<FilenameService>
}
for (var i = 0; i < mod.Groups.Count - 1; ++i)
ImmediateSave(new ModSaveGroup(mod, i));
ImmediateSaveSync(new ModSaveGroup(mod, mod.Groups.Count - 1));
ImmediateSave(new ModSaveGroup(mod, i, onlyAscii));
ImmediateSaveSync(new ModSaveGroup(mod, mod.Groups.Count - 1, onlyAscii));
}
}

View file

@ -53,7 +53,8 @@ public class PenumbraChangelog
private static void Add8_3_0(Changelog log)
=> log.NextVersion("Version 0.8.3.0")
.RegisterHighlight("Improved the UI for the On-Screen tabs with highlighting of used paths, filtering and more selections. (by Ny)")
.RegisterEntry("Added an option to replace non-ASCII symbols with underscores for folder paths on mod import since this causes problems on some WINE systems. This option is off by default.")
.RegisterEntry(
"Added an option to replace non-ASCII symbols with underscores for folder paths on mod import since this causes problems on some WINE systems. This option is off by default.")
.RegisterEntry(
"Added support for the Changed Item Icons to load modded icons, but this depends on a not-yet-released Dalamud update.")
.RegisterEntry(

View file

@ -86,7 +86,7 @@ public class ModPanelEditTab : ITab
_modManager.DataEditor.ChangeModTag(_mod, tagIdx, editedTag);
UiHelpers.DefaultLineSpace();
AddOptionGroup.Draw(_filenames, _modManager, _mod);
AddOptionGroup.Draw(_filenames, _modManager, _mod, _config.ReplaceNonAsciiOnImport);
UiHelpers.DefaultLineSpace();
for (var groupIdx = 0; groupIdx < _mod.Groups.Count; ++groupIdx)
@ -235,13 +235,13 @@ public class ModPanelEditTab : ITab
public static void Reset()
=> _newGroupName = string.Empty;
public static void Draw(FilenameService filenames, ModManager modManager, Mod mod)
public static void Draw(FilenameService filenames, ModManager modManager, Mod mod, bool onlyAscii)
{
using var spacing = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, new Vector2(UiHelpers.ScaleX3));
ImGui.SetNextItemWidth(UiHelpers.InputTextMinusButton3);
ImGui.InputTextWithHint("##newGroup", "Add new option group...", ref _newGroupName, 256);
ImGui.SameLine();
var defaultFile = filenames.OptionGroupFile(mod, -1);
var defaultFile = filenames.OptionGroupFile(mod, -1, onlyAscii);
var fileExists = File.Exists(defaultFile);
var tt = fileExists
? "Open the default option json file in the text editor of your choice."
@ -438,7 +438,7 @@ public class ModPanelEditTab : ITab
_delayedActions.Enqueue(() => DescriptionEdit.OpenPopup(_mod, groupIdx));
ImGui.SameLine();
var fileName = _filenames.OptionGroupFile(_mod, groupIdx);
var fileName = _filenames.OptionGroupFile(_mod, groupIdx, _config.ReplaceNonAsciiOnImport);
var fileExists = File.Exists(fileName);
tt = fileExists
? $"Open the {group.Name} json file in the text editor of your choice."