Add option to clear non-ascii symbols from paths again.

This commit is contained in:
Ottermandias 2023-12-10 15:41:26 +01:00
parent b14cd26e4e
commit 59ea1f2dd6
13 changed files with 56 additions and 62 deletions

View file

@ -877,7 +877,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi
public PenumbraApiEc CreateNamedTemporaryCollection(string name) public PenumbraApiEc CreateNamedTemporaryCollection(string name)
{ {
CheckInitialized(); CheckInitialized();
if (name.Length == 0 || ModCreator.ReplaceBadXivSymbols(name) != name || name.Contains('|')) if (name.Length == 0 || ModCreator.ReplaceBadXivSymbols(name, _config.ReplaceNonAsciiOnImport) != name || name.Contains('|'))
return PenumbraApiEc.InvalidArgument; return PenumbraApiEc.InvalidArgument;
return _tempCollections.CreateTemporaryCollection(name).Length > 0 return _tempCollections.CreateTemporaryCollection(name).Length > 0

View file

@ -46,6 +46,7 @@ public class Configuration : IPluginConfiguration, ISavable
public bool UseOwnerNameForCharacterCollection { get; set; } = true; public bool UseOwnerNameForCharacterCollection { get; set; } = true;
public bool UseNoModsInInspect { get; set; } = false; public bool UseNoModsInInspect { get; set; } = false;
public bool HideChangedItemFilters { get; set; } = false; public bool HideChangedItemFilters { get; set; } = false;
public bool ReplaceNonAsciiOnImport { get; set; } = false;
public bool HidePrioritiesInSelector { get; set; } = false; public bool HidePrioritiesInSelector { get; set; } = false;
public bool HideRedrawBar { get; set; } = false; public bool HideRedrawBar { get; set; } = false;

View file

@ -44,7 +44,7 @@ public partial class TexToolsImporter
}; };
Penumbra.Log.Information($" -> Importing {archive.Type} Archive."); Penumbra.Log.Information($" -> Importing {archive.Type} Archive.");
_currentModDirectory = ModCreator.CreateModFolder(_baseDirectory, Path.GetRandomFileName()); _currentModDirectory = ModCreator.CreateModFolder(_baseDirectory, Path.GetRandomFileName(), _config.ReplaceNonAsciiOnImport, true);
var options = new ExtractionOptions() var options = new ExtractionOptions()
{ {
ExtractFullPath = true, ExtractFullPath = true,
@ -97,13 +97,13 @@ public partial class TexToolsImporter
// Use either the top-level directory as the mods base name, or the (fixed for path) name in the json. // Use either the top-level directory as the mods base name, or the (fixed for path) name in the json.
if (leadDir) if (leadDir)
{ {
_currentModDirectory = ModCreator.CreateModFolder(_baseDirectory, baseName, false); _currentModDirectory = ModCreator.CreateModFolder(_baseDirectory, baseName, _config.ReplaceNonAsciiOnImport, false);
Directory.Move(Path.Combine(oldName, baseName), _currentModDirectory.FullName); Directory.Move(Path.Combine(oldName, baseName), _currentModDirectory.FullName);
Directory.Delete(oldName); Directory.Delete(oldName);
} }
else else
{ {
_currentModDirectory = ModCreator.CreateModFolder(_baseDirectory, name, false); _currentModDirectory = ModCreator.CreateModFolder(_baseDirectory, name, _config.ReplaceNonAsciiOnImport, false);
Directory.Move(oldName, _currentModDirectory.FullName); Directory.Move(oldName, _currentModDirectory.FullName);
} }

View file

@ -35,7 +35,7 @@ public partial class TexToolsImporter
var modList = modListRaw.Select(m => JsonConvert.DeserializeObject<SimpleMod>(m, JsonSettings)!).ToList(); var modList = modListRaw.Select(m => JsonConvert.DeserializeObject<SimpleMod>(m, JsonSettings)!).ToList();
_currentModDirectory = ModCreator.CreateModFolder(_baseDirectory, Path.GetFileNameWithoutExtension(modPackFile.Name)); _currentModDirectory = ModCreator.CreateModFolder(_baseDirectory, Path.GetFileNameWithoutExtension(modPackFile.Name), _config.ReplaceNonAsciiOnImport, true);
// Create a new ModMeta from the TTMP mod list info // Create a new ModMeta from the TTMP mod list info
_modManager.DataEditor.CreateMeta(_currentModDirectory, _currentModName, DefaultTexToolsData.Author, DefaultTexToolsData.Description, _modManager.DataEditor.CreateMeta(_currentModDirectory, _currentModName, DefaultTexToolsData.Author, DefaultTexToolsData.Description,
null, null); null, null);
@ -88,7 +88,7 @@ public partial class TexToolsImporter
_currentOptionName = DefaultTexToolsData.DefaultOption; _currentOptionName = DefaultTexToolsData.DefaultOption;
Penumbra.Log.Information(" -> Importing Simple V2 ModPack"); Penumbra.Log.Information(" -> Importing Simple V2 ModPack");
_currentModDirectory = ModCreator.CreateModFolder(_baseDirectory, _currentModName); _currentModDirectory = ModCreator.CreateModFolder(_baseDirectory, _currentModName, _config.ReplaceNonAsciiOnImport, true);
_modManager.DataEditor.CreateMeta(_currentModDirectory, _currentModName, modList.Author, string.IsNullOrEmpty(modList.Description) _modManager.DataEditor.CreateMeta(_currentModDirectory, _currentModName, modList.Author, string.IsNullOrEmpty(modList.Description)
? "Mod imported from TexTools mod pack" ? "Mod imported from TexTools mod pack"
: modList.Description, modList.Version, modList.Url); : modList.Description, modList.Version, modList.Url);
@ -131,7 +131,7 @@ public partial class TexToolsImporter
_currentNumOptions = GetOptionCount(modList); _currentNumOptions = GetOptionCount(modList);
_currentModName = modList.Name; _currentModName = modList.Name;
_currentModDirectory = ModCreator.CreateModFolder(_baseDirectory, _currentModName); _currentModDirectory = ModCreator.CreateModFolder(_baseDirectory, _currentModName, _config.ReplaceNonAsciiOnImport, true);
_modManager.DataEditor.CreateMeta(_currentModDirectory, _currentModName, modList.Author, modList.Description, modList.Version, _modManager.DataEditor.CreateMeta(_currentModDirectory, _currentModName, modList.Author, modList.Description, modList.Version,
modList.Url); modList.Url);
@ -168,7 +168,7 @@ public partial class TexToolsImporter
{ {
var name = numGroups == 1 ? _currentGroupName : $"{_currentGroupName}, Part {groupId + 1}"; var name = numGroups == 1 ? _currentGroupName : $"{_currentGroupName}, Part {groupId + 1}";
options.Clear(); options.Clear();
var groupFolder = ModCreator.NewSubFolderName(_currentModDirectory, name) var groupFolder = ModCreator.NewSubFolderName(_currentModDirectory, name, _config.ReplaceNonAsciiOnImport)
?? new DirectoryInfo(Path.Combine(_currentModDirectory.FullName, ?? new DirectoryInfo(Path.Combine(_currentModDirectory.FullName,
numGroups == 1 ? $"Group {groupPriority + 1}" : $"Group {groupPriority + 1}, Part {groupId + 1}")); numGroups == 1 ? $"Group {groupPriority + 1}" : $"Group {groupPriority + 1}, Part {groupId + 1}"));
@ -178,7 +178,7 @@ public partial class TexToolsImporter
var option = allOptions[i + optionIdx]; var option = allOptions[i + optionIdx];
_token.ThrowIfCancellationRequested(); _token.ThrowIfCancellationRequested();
_currentOptionName = option.Name; _currentOptionName = option.Name;
var optionFolder = ModCreator.NewSubFolderName(groupFolder, option.Name) var optionFolder = ModCreator.NewSubFolderName(groupFolder, option.Name, _config.ReplaceNonAsciiOnImport)
?? new DirectoryInfo(Path.Combine(groupFolder.FullName, $"Option {i + optionIdx + 1}")); ?? new DirectoryInfo(Path.Combine(groupFolder.FullName, $"Option {i + optionIdx + 1}"));
ExtractSimpleModList(optionFolder, option.ModsJsons); ExtractSimpleModList(optionFolder, option.ModsJsons);
options.Add(_modManager.Creator.CreateSubMod(_currentModDirectory, optionFolder, option)); options.Add(_modManager.Creator.CreateSubMod(_currentModDirectory, optionFolder, option));

View file

@ -49,13 +49,13 @@ public unsafe class MetaFileManager
TexToolsMeta.WriteTexToolsMeta(this, mod.Default.Manipulations, mod.ModPath); TexToolsMeta.WriteTexToolsMeta(this, mod.Default.Manipulations, mod.ModPath);
foreach (var group in mod.Groups) foreach (var group in mod.Groups)
{ {
var dir = ModCreator.NewOptionDirectory(mod.ModPath, group.Name); var dir = ModCreator.NewOptionDirectory(mod.ModPath, group.Name, Config.ReplaceNonAsciiOnImport);
if (!dir.Exists) if (!dir.Exists)
dir.Create(); dir.Create();
foreach (var option in group.OfType<SubMod>()) foreach (var option in group.OfType<SubMod>())
{ {
var optionDir = ModCreator.NewOptionDirectory(dir, option.Name); var optionDir = ModCreator.NewOptionDirectory(dir, option.Name, Config.ReplaceNonAsciiOnImport);
if (!optionDir.Exists) if (!optionDir.Exists)
optionDir.Create(); optionDir.Create();

View file

@ -4,7 +4,6 @@ using OtterGui;
using OtterGui.Classes; using OtterGui.Classes;
using Penumbra.Api.Enums; using Penumbra.Api.Enums;
using Penumbra.Communication; using Penumbra.Communication;
using Penumbra.Meta.Manipulations;
using Penumbra.Mods.Manager; using Penumbra.Mods.Manager;
using Penumbra.Mods.Subclasses; using Penumbra.Mods.Subclasses;
using Penumbra.Services; using Penumbra.Services;
@ -15,6 +14,7 @@ namespace Penumbra.Mods.Editor;
public class ModMerger : IDisposable public class ModMerger : IDisposable
{ {
private readonly Configuration _config;
private readonly CommunicatorService _communicator; private readonly CommunicatorService _communicator;
private readonly ModOptionEditor _editor; private readonly ModOptionEditor _editor;
private readonly ModFileSystemSelector _selector; private readonly ModFileSystemSelector _selector;
@ -40,13 +40,14 @@ public class ModMerger : IDisposable
public Exception? Error { get; private set; } public Exception? Error { get; private set; }
public ModMerger(ModManager mods, ModOptionEditor editor, ModFileSystemSelector selector, DuplicateManager duplicates, public ModMerger(ModManager mods, ModOptionEditor editor, ModFileSystemSelector selector, DuplicateManager duplicates,
CommunicatorService communicator, ModCreator creator) CommunicatorService communicator, ModCreator creator, Configuration config)
{ {
_editor = editor; _editor = editor;
_selector = selector; _selector = selector;
_duplicates = duplicates; _duplicates = duplicates;
_communicator = communicator; _communicator = communicator;
_creator = creator; _creator = creator;
_config = config;
_mods = mods; _mods = mods;
_selector.SelectionChanged += OnSelectionChange; _selector.SelectionChanged += OnSelectionChange;
_communicator.ModPathChanged.Subscribe(OnModPathChange, ModPathChanged.Priority.ModMerger); _communicator.ModPathChanged.Subscribe(OnModPathChange, ModPathChanged.Priority.ModMerger);
@ -82,7 +83,8 @@ public class ModMerger : IDisposable
catch (Exception ex) catch (Exception ex)
{ {
Error = ex; Error = ex;
Penumbra.Messager.NotificationMessage(ex, $"Could not merge {MergeFromMod!.Name} into {MergeToMod!.Name}, cleaning up changes.", NotificationType.Error, false); Penumbra.Messager.NotificationMessage(ex, $"Could not merge {MergeFromMod!.Name} into {MergeToMod!.Name}, cleaning up changes.",
NotificationType.Error, false);
FailureCleanup(); FailureCleanup();
DataCleanup(); DataCleanup();
} }
@ -138,10 +140,10 @@ public class ModMerger : IDisposable
var (option, optionCreated) = _editor.FindOrAddOption(MergeToMod!, groupIdx, optionName); var (option, optionCreated) = _editor.FindOrAddOption(MergeToMod!, groupIdx, optionName);
if (optionCreated) if (optionCreated)
_createdOptions.Add(option); _createdOptions.Add(option);
var dir = ModCreator.NewOptionDirectory(MergeToMod!.ModPath, groupName); var dir = ModCreator.NewOptionDirectory(MergeToMod!.ModPath, groupName, _config.ReplaceNonAsciiOnImport);
if (!dir.Exists) if (!dir.Exists)
_createdDirectories.Add(dir.FullName); _createdDirectories.Add(dir.FullName);
dir = ModCreator.NewOptionDirectory(dir, optionName); dir = ModCreator.NewOptionDirectory(dir, optionName, _config.ReplaceNonAsciiOnImport);
if (!dir.Exists) if (!dir.Exists)
_createdDirectories.Add(dir.FullName); _createdDirectories.Add(dir.FullName);
CopyFiles(dir); CopyFiles(dir);

View file

@ -6,11 +6,10 @@ using Penumbra.Mods.Manager;
using Penumbra.Mods.Subclasses; using Penumbra.Mods.Subclasses;
using Penumbra.String.Classes; using Penumbra.String.Classes;
namespace Penumbra.Mods; namespace Penumbra.Mods.Editor;
public class ModNormalizer public class ModNormalizer(ModManager _modManager, Configuration _config)
{ {
private readonly ModManager _modManager;
private readonly List<List<Dictionary<Utf8GamePath, FullPath>>> _redirections = new(); private readonly List<List<Dictionary<Utf8GamePath, FullPath>>> _redirections = new();
public Mod Mod { get; private set; } = null!; public Mod Mod { get; private set; } = null!;
@ -25,9 +24,6 @@ public class ModNormalizer
public bool Running public bool Running
=> !Worker.IsCompleted; => !Worker.IsCompleted;
public ModNormalizer(ModManager modManager)
=> _modManager = modManager;
public void Normalize(Mod mod) public void Normalize(Mod mod)
{ {
if (Step < TotalSteps) if (Step < TotalSteps)
@ -175,10 +171,10 @@ public class ModNormalizer
for (var i = _redirections[groupIdx + 1].Count; i < group.Count; ++i) for (var i = _redirections[groupIdx + 1].Count; i < group.Count; ++i)
_redirections[groupIdx + 1].Add(new Dictionary<Utf8GamePath, FullPath>()); _redirections[groupIdx + 1].Add(new Dictionary<Utf8GamePath, FullPath>());
var groupDir = ModCreator.CreateModFolder(directory, group.Name); var groupDir = ModCreator.CreateModFolder(directory, group.Name, _config.ReplaceNonAsciiOnImport, true);
foreach (var option in group.OfType<SubMod>()) foreach (var option in group.OfType<SubMod>())
{ {
var optionDir = ModCreator.CreateModFolder(groupDir, option.Name); var optionDir = ModCreator.CreateModFolder(groupDir, option.Name, _config.ReplaceNonAsciiOnImport, true);
newDict = _redirections[groupIdx + 1][option.OptionIdx]; newDict = _redirections[groupIdx + 1][option.OptionIdx];
newDict.Clear(); newDict.Clear();
@ -228,7 +224,8 @@ public class ModNormalizer
} }
catch (Exception e) catch (Exception e)
{ {
Penumbra.Messager.NotificationMessage(e, $"Could not move old files out of the way while normalizing mod {Mod.Name}.", NotificationType.Error, false); Penumbra.Messager.NotificationMessage(e, $"Could not move old files out of the way while normalizing mod {Mod.Name}.",
NotificationType.Error, false);
} }
return false; return false;
@ -251,7 +248,8 @@ public class ModNormalizer
} }
catch (Exception e) catch (Exception e)
{ {
Penumbra.Messager.NotificationMessage(e, $"Could not move new files into the mod while normalizing mod {Mod.Name}.", NotificationType.Error, false); Penumbra.Messager.NotificationMessage(e, $"Could not move new files into the mod while normalizing mod {Mod.Name}.",
NotificationType.Error, false);
foreach (var dir in Mod.ModPath.EnumerateDirectories()) foreach (var dir in Mod.ModPath.EnumerateDirectories())
{ {
if (dir.FullName.Equals(_oldDirName, StringComparison.OrdinalIgnoreCase) if (dir.FullName.Equals(_oldDirName, StringComparison.OrdinalIgnoreCase)

View file

@ -217,7 +217,7 @@ public sealed class ModManager : ModStorage, IDisposable
if (oldName == newName) if (oldName == newName)
return NewDirectoryState.Identical; return NewDirectoryState.Identical;
var fixedNewName = ModCreator.ReplaceBadXivSymbols(newName); var fixedNewName = ModCreator.ReplaceBadXivSymbols(newName, _config.ReplaceNonAsciiOnImport);
if (fixedNewName != newName) if (fixedNewName != newName)
return NewDirectoryState.ContainsInvalidSymbols; return NewDirectoryState.ContainsInvalidSymbols;

View file

@ -16,30 +16,15 @@ using Penumbra.String.Classes;
namespace Penumbra.Mods; namespace Penumbra.Mods;
public partial class ModCreator public partial class ModCreator(SaveService _saveService, Configuration _config, ModDataEditor _dataEditor, MetaFileManager _metaFileManager,
IGamePathParser _gamePathParser)
{ {
private readonly Configuration _config;
private readonly SaveService _saveService;
private readonly ModDataEditor _dataEditor;
private readonly MetaFileManager _metaFileManager;
private readonly IGamePathParser _gamePathParser;
public ModCreator(SaveService saveService, Configuration config, ModDataEditor dataEditor, MetaFileManager metaFileManager,
IGamePathParser gamePathParser)
{
_saveService = saveService;
_config = config;
_dataEditor = dataEditor;
_metaFileManager = metaFileManager;
_gamePathParser = gamePathParser;
}
/// <summary> Creates directory and files necessary for a new mod without adding it to the manager. </summary> /// <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 = "") public DirectoryInfo? CreateEmptyMod(DirectoryInfo basePath, string newName, string description = "")
{ {
try try
{ {
var newDir = CreateModFolder(basePath, newName); var newDir = CreateModFolder(basePath, newName, _config.ReplaceNonAsciiOnImport, true);
_dataEditor.CreateMeta(newDir, newName, _config.DefaultModAuthor, description, "1.0", string.Empty); _dataEditor.CreateMeta(newDir, newName, _config.DefaultModAuthor, description, "1.0", string.Empty);
CreateDefaultFiles(newDir); CreateDefaultFiles(newDir);
return newDir; return newDir;
@ -138,13 +123,13 @@ public partial class ModCreator
/// - Unique, by appending (digit) for duplicates.<br/> /// - Unique, by appending (digit) for duplicates.<br/>
/// - Containing no symbols invalid for FFXIV or windows paths.<br/> /// - Containing no symbols invalid for FFXIV or windows paths.<br/>
/// </summary> /// </summary>
public static DirectoryInfo CreateModFolder(DirectoryInfo outDirectory, string modListName, bool create = true) public static DirectoryInfo CreateModFolder(DirectoryInfo outDirectory, string modListName, bool onlyAscii, bool create)
{ {
var name = modListName; var name = modListName;
if (name.Length == 0) if (name.Length == 0)
name = "_"; name = "_";
var newModFolderBase = NewOptionDirectory(outDirectory, name); var newModFolderBase = NewOptionDirectory(outDirectory, name, onlyAscii);
var newModFolder = newModFolderBase.FullName.ObtainUniqueFile(); var newModFolder = newModFolderBase.FullName.ObtainUniqueFile();
if (newModFolder.Length == 0) if (newModFolder.Length == 0)
throw new IOException("Could not create mod folder: too many folders of the same name exist."); throw new IOException("Could not create mod folder: too many folders of the same name exist.");
@ -238,9 +223,9 @@ public partial class ModCreator
/// Create the name for a group or option subfolder based on its parent folder and given name. /// Create the name for a group or option subfolder based on its parent folder and given name.
/// subFolderName should never be empty, and the result is unique and contains no invalid symbols. /// subFolderName should never be empty, and the result is unique and contains no invalid symbols.
/// </summary> /// </summary>
public static DirectoryInfo? NewSubFolderName(DirectoryInfo parentFolder, string subFolderName) public static DirectoryInfo? NewSubFolderName(DirectoryInfo parentFolder, string subFolderName, bool onlyAscii)
{ {
var newModFolderBase = NewOptionDirectory(parentFolder, subFolderName); var newModFolderBase = NewOptionDirectory(parentFolder, subFolderName, onlyAscii);
var newModFolder = newModFolderBase.FullName.ObtainUniqueFile(); var newModFolder = newModFolderBase.FullName.ObtainUniqueFile();
return newModFolder.Length == 0 ? null : new DirectoryInfo(newModFolder); return newModFolder.Length == 0 ? null : new DirectoryInfo(newModFolder);
} }
@ -325,14 +310,14 @@ public partial class ModCreator
} }
/// <summary> Return the name of a new valid directory based on the base directory and the given name. </summary> /// <summary> Return the name of a new valid directory based on the base directory and the given name. </summary>
public static DirectoryInfo NewOptionDirectory(DirectoryInfo baseDir, string optionName) public static DirectoryInfo NewOptionDirectory(DirectoryInfo baseDir, string optionName, bool onlyAscii)
{ {
var option = ReplaceBadXivSymbols(optionName); var option = ReplaceBadXivSymbols(optionName, onlyAscii);
return new DirectoryInfo(Path.Combine(baseDir.FullName, option.Length > 0 ? option : "_")); return new DirectoryInfo(Path.Combine(baseDir.FullName, option.Length > 0 ? option : "_"));
} }
/// <summary> Normalize for nicer names, and remove invalid symbols or invalid paths. </summary> /// <summary> Normalize for nicer names, and remove invalid symbols or invalid paths. </summary>
public static string ReplaceBadXivSymbols(string s, string replacement = "_") public static string ReplaceBadXivSymbols(string s, bool onlyAscii, string replacement = "_")
{ {
switch (s) switch (s)
{ {
@ -345,6 +330,8 @@ public partial class ModCreator
{ {
if (c.IsInvalidInPath()) if (c.IsInvalidInPath())
sb.Append(replacement); sb.Append(replacement);
else if (onlyAscii && c.IsInvalidAscii())
sb.Append(replacement);
else else
sb.Append(c); sb.Append(c);
} }

View file

@ -52,7 +52,7 @@ public class TemporaryMod : IMod
DirectoryInfo? dir = null; DirectoryInfo? dir = null;
try try
{ {
dir = ModCreator.CreateModFolder(modManager.BasePath, collection.Name); dir = ModCreator.CreateModFolder(modManager.BasePath, collection.Name, config.ReplaceNonAsciiOnImport, true);
var fileDir = Directory.CreateDirectory(Path.Combine(dir.FullName, "files")); var fileDir = Directory.CreateDirectory(Path.Combine(dir.FullName, "files"));
modManager.DataEditor.CreateMeta(dir, collection.Name, character ?? config.DefaultModAuthor, modManager.DataEditor.CreateMeta(dir, collection.Name, character ?? config.DefaultModAuthor,
$"Mod generated from temporary collection {collection.Name} for {character ?? "Unknown Character"}.", null, null); $"Mod generated from temporary collection {collection.Name} for {character ?? "Unknown Character"}.", null, null);

View file

@ -25,6 +25,7 @@ namespace Penumbra.UI.AdvancedWindow;
public class ItemSwapTab : IDisposable, ITab public class ItemSwapTab : IDisposable, ITab
{ {
private readonly Configuration _config;
private readonly CommunicatorService _communicator; private readonly CommunicatorService _communicator;
private readonly ItemService _itemService; private readonly ItemService _itemService;
private readonly CollectionManager _collectionManager; private readonly CollectionManager _collectionManager;
@ -32,13 +33,14 @@ public class ItemSwapTab : IDisposable, ITab
private readonly MetaFileManager _metaFileManager; private readonly MetaFileManager _metaFileManager;
public ItemSwapTab(CommunicatorService communicator, ItemService itemService, CollectionManager collectionManager, public ItemSwapTab(CommunicatorService communicator, ItemService itemService, CollectionManager collectionManager,
ModManager modManager, IdentifierService identifier, MetaFileManager metaFileManager) ModManager modManager, IdentifierService identifier, MetaFileManager metaFileManager, Configuration config)
{ {
_communicator = communicator; _communicator = communicator;
_itemService = itemService; _itemService = itemService;
_collectionManager = collectionManager; _collectionManager = collectionManager;
_modManager = modManager; _modManager = modManager;
_metaFileManager = metaFileManager; _metaFileManager = metaFileManager;
_config = config;
_swapData = new ItemSwapContainer(metaFileManager, identifier); _swapData = new ItemSwapContainer(metaFileManager, identifier);
_selectors = new Dictionary<SwapType, (ItemSelector Source, ItemSelector Target, string TextFrom, string TextTo)> _selectors = new Dictionary<SwapType, (ItemSelector Source, ItemSelector Target, string TextFrom, string TextTo)>
@ -296,7 +298,7 @@ public class ItemSwapTab : IDisposable, ITab
{ {
optionFolderName = optionFolderName =
ModCreator.NewSubFolderName(new DirectoryInfo(Path.Combine(_mod.ModPath.FullName, _selectedGroup?.Name ?? _newGroupName)), ModCreator.NewSubFolderName(new DirectoryInfo(Path.Combine(_mod.ModPath.FullName, _selectedGroup?.Name ?? _newGroupName)),
_newOptionName); _newOptionName, _config.ReplaceNonAsciiOnImport);
if (optionFolderName?.Exists == true) if (optionFolderName?.Exists == true)
throw new Exception($"The folder {optionFolderName.FullName} for the option already exists."); throw new Exception($"The folder {optionFolderName.FullName} for the option already exists.");

View file

@ -22,12 +22,13 @@ public partial class ModEditWindow
private HashSet<string> GetPlayerResourcesOfType(ResourceType type) private HashSet<string> GetPlayerResourcesOfType(ResourceType type)
{ {
var resources = ResourceTreeApiHelper.GetResourcesOfType(_resourceTreeFactory.FromObjectTable(ResourceTreeFactory.Flags.LocalPlayerRelatedOnly), type) var resources = ResourceTreeApiHelper
.GetResourcesOfType(_resourceTreeFactory.FromObjectTable(ResourceTreeFactory.Flags.LocalPlayerRelatedOnly), type)
.Values .Values
.SelectMany(resources => resources.Values) .SelectMany(resources => resources.Values)
.Select(resource => resource.Item1); .Select(resource => resource.Item1);
return new(resources, StringComparer.OrdinalIgnoreCase); return new HashSet<string>(resources, StringComparer.OrdinalIgnoreCase);
} }
private IReadOnlyList<FileRegistry> PopulateIsOnPlayer(IReadOnlyList<FileRegistry> files, ResourceType type) private IReadOnlyList<FileRegistry> PopulateIsOnPlayer(IReadOnlyList<FileRegistry> files, ResourceType type)
@ -198,7 +199,7 @@ public partial class ModEditWindow
if (mod == null) if (mod == null)
return new QuickImportAction(editor, optionName, gamePath); return new QuickImportAction(editor, optionName, gamePath);
var (preferredPath, subDirs) = GetPreferredPath(mod, subMod); var (preferredPath, subDirs) = GetPreferredPath(mod, subMod, owner._config.ReplaceNonAsciiOnImport);
var targetPath = new FullPath(Path.Combine(preferredPath.FullName, gamePath.ToString())).FullName; var targetPath = new FullPath(Path.Combine(preferredPath.FullName, gamePath.ToString())).FullName;
if (File.Exists(targetPath)) if (File.Exists(targetPath))
return new QuickImportAction(editor, optionName, gamePath); return new QuickImportAction(editor, optionName, gamePath);
@ -226,7 +227,7 @@ public partial class ModEditWindow
return fileRegistry; return fileRegistry;
} }
private static (DirectoryInfo, int) GetPreferredPath(Mod mod, ISubMod subMod) private static (DirectoryInfo, int) GetPreferredPath(Mod mod, ISubMod subMod, bool replaceNonAscii)
{ {
var path = mod.ModPath; var path = mod.ModPath;
var subDirs = 0; var subDirs = 0;
@ -237,13 +238,13 @@ public partial class ModEditWindow
var fullName = subMod.FullName; var fullName = subMod.FullName;
if (fullName.EndsWith(": " + name)) if (fullName.EndsWith(": " + name))
{ {
path = ModCreator.NewOptionDirectory(path, fullName[..^(name.Length + 2)]); path = ModCreator.NewOptionDirectory(path, fullName[..^(name.Length + 2)], replaceNonAscii);
path = ModCreator.NewOptionDirectory(path, name); path = ModCreator.NewOptionDirectory(path, name, replaceNonAscii);
subDirs = 2; subDirs = 2;
} }
else else
{ {
path = ModCreator.NewOptionDirectory(path, fullName); path = ModCreator.NewOptionDirectory(path, fullName, replaceNonAscii);
subDirs = 1; subDirs = 1;
} }

View file

@ -535,6 +535,9 @@ public class SettingsTab : ITab
/// <summary> Draw all settings pertaining to import and export of mods. </summary> /// <summary> Draw all settings pertaining to import and export of mods. </summary>
private void DrawModHandlingSettings() private void DrawModHandlingSettings()
{ {
Checkbox("Replace Non-Standard Symbols On Import",
"Replace all non-ASCII symbols in mod and option names with underscores when importing mods.", _config.ReplaceNonAsciiOnImport,
v => _config.ReplaceNonAsciiOnImport = v);
Checkbox("Always Open Import at Default Directory", Checkbox("Always Open Import at Default Directory",
"Open the import window at the location specified here every time, forgetting your previous path.", "Open the import window at the location specified here every time, forgetting your previous path.",
_config.AlwaysOpenDefaultImport, v => _config.AlwaysOpenDefaultImport = v); _config.AlwaysOpenDefaultImport, v => _config.AlwaysOpenDefaultImport = v);