mirror of
https://github.com/xivdev/Penumbra.git
synced 2026-01-03 06:13:45 +01:00
Merge branch 'dev'
# Conflicts: # Penumbra/UI/AdvancedWindow/ModEditWindow.cs
This commit is contained in:
commit
b5c69b2946
85 changed files with 901 additions and 887 deletions
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ public static class CustomizationSwap
|
|||
{
|
||||
/// The .mdl file for customizations is unique per racecode, slot and id, thus the .mdl redirection itself is independent of the mode.
|
||||
public static FileSwap CreateMdl(MetaFileManager manager, Func<Utf8GamePath, FullPath> redirections, BodySlot slot, GenderRace race,
|
||||
SetId idFrom, SetId idTo)
|
||||
PrimaryId idFrom, PrimaryId idTo)
|
||||
{
|
||||
if (idFrom.Id > byte.MaxValue)
|
||||
throw new Exception($"The Customization ID {idFrom} is too large for {slot}.");
|
||||
|
|
@ -43,10 +43,10 @@ public static class CustomizationSwap
|
|||
}
|
||||
|
||||
public static FileSwap CreateMtrl(MetaFileManager manager, Func<Utf8GamePath, FullPath> redirections, BodySlot slot, GenderRace race,
|
||||
SetId idFrom, SetId idTo, byte variant,
|
||||
PrimaryId idFrom, PrimaryId idTo, byte variant,
|
||||
ref string fileName, ref bool dataWasChanged)
|
||||
{
|
||||
variant = slot is BodySlot.Face or BodySlot.Zear ? byte.MaxValue : variant;
|
||||
variant = slot is BodySlot.Face or BodySlot.Ear ? byte.MaxValue : variant;
|
||||
var mtrlFromPath = GamePaths.Character.Mtrl.Path(race, slot, idFrom, fileName, out var gameRaceFrom, out var gameSetIdFrom, variant);
|
||||
var mtrlToPath = GamePaths.Character.Mtrl.Path(race, slot, idTo, fileName, out var gameRaceTo, out var gameSetIdTo, variant);
|
||||
|
||||
|
|
@ -79,7 +79,7 @@ public static class CustomizationSwap
|
|||
}
|
||||
|
||||
public static FileSwap CreateTex(MetaFileManager manager, Func<Utf8GamePath, FullPath> redirections, BodySlot slot, GenderRace race,
|
||||
SetId idFrom, ref MtrlFile.Texture texture,
|
||||
PrimaryId idFrom, ref MtrlFile.Texture texture,
|
||||
ref bool dataWasChanged)
|
||||
{
|
||||
var path = texture.Path;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using Penumbra.Api.Enums;
|
||||
using Penumbra.GameData;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Files;
|
||||
|
|
@ -41,7 +40,7 @@ public static class EquipmentSwap
|
|||
: Array.Empty<EquipSlot>();
|
||||
}
|
||||
|
||||
public static EquipItem[] CreateTypeSwap(MetaFileManager manager, IObjectIdentifier identifier, List<Swap> swaps,
|
||||
public static EquipItem[] CreateTypeSwap(MetaFileManager manager, ObjectIdentification identifier, List<Swap> swaps,
|
||||
Func<Utf8GamePath, FullPath> redirections, Func<MetaManipulation, MetaManipulation> manips,
|
||||
EquipSlot slotFrom, EquipItem itemFrom, EquipSlot slotTo, EquipItem itemTo)
|
||||
{
|
||||
|
|
@ -99,7 +98,7 @@ public static class EquipmentSwap
|
|||
return affectedItems;
|
||||
}
|
||||
|
||||
public static EquipItem[] CreateItemSwap(MetaFileManager manager, IObjectIdentifier identifier, List<Swap> swaps,
|
||||
public static EquipItem[] CreateItemSwap(MetaFileManager manager, ObjectIdentification identifier, List<Swap> swaps,
|
||||
Func<Utf8GamePath, FullPath> redirections, Func<MetaManipulation, MetaManipulation> manips, EquipItem itemFrom,
|
||||
EquipItem itemTo, bool rFinger = true, bool lFinger = true)
|
||||
{
|
||||
|
|
@ -186,13 +185,13 @@ public static class EquipmentSwap
|
|||
}
|
||||
|
||||
public static MetaSwap? CreateEqdp(MetaFileManager manager, Func<Utf8GamePath, FullPath> redirections,
|
||||
Func<MetaManipulation, MetaManipulation> manips, EquipSlot slot, GenderRace gr, SetId idFrom,
|
||||
SetId idTo, byte mtrlTo)
|
||||
Func<MetaManipulation, MetaManipulation> manips, EquipSlot slot, GenderRace gr, PrimaryId idFrom,
|
||||
PrimaryId idTo, byte mtrlTo)
|
||||
=> CreateEqdp(manager, redirections, manips, slot, slot, gr, idFrom, idTo, mtrlTo);
|
||||
|
||||
public static MetaSwap? CreateEqdp(MetaFileManager manager, Func<Utf8GamePath, FullPath> redirections,
|
||||
Func<MetaManipulation, MetaManipulation> manips, EquipSlot slotFrom, EquipSlot slotTo, GenderRace gr, SetId idFrom,
|
||||
SetId idTo, byte mtrlTo)
|
||||
Func<MetaManipulation, MetaManipulation> manips, EquipSlot slotFrom, EquipSlot slotTo, GenderRace gr, PrimaryId idFrom,
|
||||
PrimaryId idTo, byte mtrlTo)
|
||||
{
|
||||
var (gender, race) = gr.Split();
|
||||
var eqdpFrom = new EqdpManipulation(ExpandedEqdpFile.GetDefault(manager, gr, slotFrom.IsAccessory(), idFrom), slotFrom, gender,
|
||||
|
|
@ -215,11 +214,11 @@ public static class EquipmentSwap
|
|||
}
|
||||
|
||||
public static FileSwap CreateMdl(MetaFileManager manager, Func<Utf8GamePath, FullPath> redirections, EquipSlot slot, GenderRace gr,
|
||||
SetId idFrom, SetId idTo, byte mtrlTo)
|
||||
PrimaryId idFrom, PrimaryId idTo, byte mtrlTo)
|
||||
=> CreateMdl(manager, redirections, slot, slot, gr, idFrom, idTo, mtrlTo);
|
||||
|
||||
public static FileSwap CreateMdl(MetaFileManager manager, Func<Utf8GamePath, FullPath> redirections, EquipSlot slotFrom, EquipSlot slotTo,
|
||||
GenderRace gr, SetId idFrom, SetId idTo, byte mtrlTo)
|
||||
GenderRace gr, PrimaryId idFrom, PrimaryId idTo, byte mtrlTo)
|
||||
{
|
||||
var mdlPathFrom = slotFrom.IsAccessory()
|
||||
? GamePaths.Accessory.Mdl.Path(idFrom, gr, slotFrom)
|
||||
|
|
@ -237,18 +236,18 @@ public static class EquipmentSwap
|
|||
return mdl;
|
||||
}
|
||||
|
||||
private static void LookupItem(EquipItem i, out EquipSlot slot, out SetId modelId, out Variant variant)
|
||||
private static void LookupItem(EquipItem i, out EquipSlot slot, out PrimaryId modelId, out Variant variant)
|
||||
{
|
||||
slot = i.Type.ToSlot();
|
||||
if (!slot.IsEquipmentPiece())
|
||||
throw new ItemSwap.InvalidItemTypeException();
|
||||
|
||||
modelId = i.ModelId;
|
||||
modelId = i.PrimaryId;
|
||||
variant = i.Variant;
|
||||
}
|
||||
|
||||
private static (ImcFile, Variant[], EquipItem[]) GetVariants(MetaFileManager manager, IObjectIdentifier identifier, EquipSlot slotFrom,
|
||||
SetId idFrom, SetId idTo, Variant variantFrom)
|
||||
private static (ImcFile, Variant[], EquipItem[]) GetVariants(MetaFileManager manager, ObjectIdentification identifier, EquipSlot slotFrom,
|
||||
PrimaryId idFrom, PrimaryId idTo, Variant variantFrom)
|
||||
{
|
||||
var entry = new ImcManipulation(slotFrom, variantFrom.Id, idFrom, default);
|
||||
var imc = new ImcFile(manager, entry);
|
||||
|
|
@ -256,11 +255,8 @@ public static class EquipmentSwap
|
|||
Variant[] variants;
|
||||
if (idFrom == idTo)
|
||||
{
|
||||
items = identifier.Identify(idFrom, variantFrom, slotFrom).ToArray();
|
||||
variants = new[]
|
||||
{
|
||||
variantFrom,
|
||||
};
|
||||
items = identifier.Identify(idFrom, 0, variantFrom, slotFrom).ToArray();
|
||||
variants = [variantFrom];
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -274,8 +270,8 @@ public static class EquipmentSwap
|
|||
return (imc, variants, items);
|
||||
}
|
||||
|
||||
public static MetaSwap? CreateGmp(MetaFileManager manager, Func<MetaManipulation, MetaManipulation> manips, EquipSlot slot, SetId idFrom,
|
||||
SetId idTo)
|
||||
public static MetaSwap? CreateGmp(MetaFileManager manager, Func<MetaManipulation, MetaManipulation> manips, EquipSlot slot, PrimaryId idFrom,
|
||||
PrimaryId idTo)
|
||||
{
|
||||
if (slot is not EquipSlot.Head)
|
||||
return null;
|
||||
|
|
@ -287,12 +283,12 @@ public static class EquipmentSwap
|
|||
|
||||
public static MetaSwap CreateImc(MetaFileManager manager, Func<Utf8GamePath, FullPath> redirections,
|
||||
Func<MetaManipulation, MetaManipulation> manips, EquipSlot slot,
|
||||
SetId idFrom, SetId idTo, Variant variantFrom, Variant variantTo, ImcFile imcFileFrom, ImcFile imcFileTo)
|
||||
PrimaryId idFrom, PrimaryId idTo, Variant variantFrom, Variant variantTo, ImcFile imcFileFrom, ImcFile imcFileTo)
|
||||
=> CreateImc(manager, redirections, manips, slot, slot, idFrom, idTo, variantFrom, variantTo, imcFileFrom, imcFileTo);
|
||||
|
||||
public static MetaSwap CreateImc(MetaFileManager manager, Func<Utf8GamePath, FullPath> redirections,
|
||||
Func<MetaManipulation, MetaManipulation> manips,
|
||||
EquipSlot slotFrom, EquipSlot slotTo, SetId idFrom, SetId idTo,
|
||||
EquipSlot slotFrom, EquipSlot slotTo, PrimaryId idFrom, PrimaryId idTo,
|
||||
Variant variantFrom, Variant variantTo, ImcFile imcFileFrom, ImcFile imcFileTo)
|
||||
{
|
||||
var entryFrom = imcFileFrom.GetEntry(ImcFile.PartIndex(slotFrom), variantFrom);
|
||||
|
|
@ -326,7 +322,7 @@ public static class EquipmentSwap
|
|||
|
||||
|
||||
// Example: Abyssos Helm / Body
|
||||
public static FileSwap? CreateAvfx(MetaFileManager manager, Func<Utf8GamePath, FullPath> redirections, SetId idFrom, SetId idTo, byte vfxId)
|
||||
public static FileSwap? CreateAvfx(MetaFileManager manager, Func<Utf8GamePath, FullPath> redirections, PrimaryId idFrom, PrimaryId idTo, byte vfxId)
|
||||
{
|
||||
if (vfxId == 0)
|
||||
return null;
|
||||
|
|
@ -344,8 +340,8 @@ public static class EquipmentSwap
|
|||
return avfx;
|
||||
}
|
||||
|
||||
public static MetaSwap? CreateEqp(MetaFileManager manager, Func<MetaManipulation, MetaManipulation> manips, EquipSlot slot, SetId idFrom,
|
||||
SetId idTo)
|
||||
public static MetaSwap? CreateEqp(MetaFileManager manager, Func<MetaManipulation, MetaManipulation> manips, EquipSlot slot, PrimaryId idFrom,
|
||||
PrimaryId idTo)
|
||||
{
|
||||
if (slot.IsAccessory())
|
||||
return null;
|
||||
|
|
@ -357,13 +353,13 @@ public static class EquipmentSwap
|
|||
return new MetaSwap(manips, eqpFrom, eqpTo);
|
||||
}
|
||||
|
||||
public static FileSwap? CreateMtrl(MetaFileManager manager, Func<Utf8GamePath, FullPath> redirections, EquipSlot slot, SetId idFrom,
|
||||
SetId idTo, byte variantTo, ref string fileName,
|
||||
public static FileSwap? CreateMtrl(MetaFileManager manager, Func<Utf8GamePath, FullPath> redirections, EquipSlot slot, PrimaryId idFrom,
|
||||
PrimaryId idTo, byte variantTo, ref string fileName,
|
||||
ref bool dataWasChanged)
|
||||
=> CreateMtrl(manager, redirections, slot, slot, idFrom, idTo, variantTo, ref fileName, ref dataWasChanged);
|
||||
|
||||
public static FileSwap? CreateMtrl(MetaFileManager manager, Func<Utf8GamePath, FullPath> redirections, EquipSlot slotFrom, EquipSlot slotTo,
|
||||
SetId idFrom, SetId idTo, byte variantTo, ref string fileName,
|
||||
PrimaryId idFrom, PrimaryId idTo, byte variantTo, ref string fileName,
|
||||
ref bool dataWasChanged)
|
||||
{
|
||||
var prefix = slotTo.IsAccessory() ? 'a' : 'e';
|
||||
|
|
@ -401,13 +397,13 @@ public static class EquipmentSwap
|
|||
return mtrl;
|
||||
}
|
||||
|
||||
public static FileSwap CreateTex(MetaFileManager manager, Func<Utf8GamePath, FullPath> redirections, char prefix, SetId idFrom, SetId idTo,
|
||||
public static FileSwap CreateTex(MetaFileManager manager, Func<Utf8GamePath, FullPath> redirections, char prefix, PrimaryId idFrom, PrimaryId idTo,
|
||||
ref MtrlFile.Texture texture, ref bool dataWasChanged)
|
||||
=> CreateTex(manager, redirections, prefix, EquipSlot.Unknown, EquipSlot.Unknown, idFrom, idTo, ref texture, ref dataWasChanged);
|
||||
|
||||
public static FileSwap CreateTex(MetaFileManager manager, Func<Utf8GamePath, FullPath> redirections, char prefix, EquipSlot slotFrom,
|
||||
EquipSlot slotTo, SetId idFrom,
|
||||
SetId idTo, ref MtrlFile.Texture texture, ref bool dataWasChanged)
|
||||
EquipSlot slotTo, PrimaryId idFrom,
|
||||
PrimaryId idTo, ref MtrlFile.Texture texture, ref bool dataWasChanged)
|
||||
{
|
||||
var path = texture.Path;
|
||||
var addedDashes = false;
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ public static class ItemSwap
|
|||
/// <remarks> metaChanges is not manipulated, but IReadOnlySet does not support TryGetValue. </remarks>
|
||||
public static MetaSwap? CreateEst(MetaFileManager manager, Func<Utf8GamePath, FullPath> redirections,
|
||||
Func<MetaManipulation, MetaManipulation> manips, EstManipulation.EstType type,
|
||||
GenderRace genderRace, SetId idFrom, SetId idTo, bool ownMdl)
|
||||
GenderRace genderRace, PrimaryId idFrom, PrimaryId idTo, bool ownMdl)
|
||||
{
|
||||
if (type == 0)
|
||||
return null;
|
||||
|
|
@ -195,7 +195,7 @@ public static class ItemSwap
|
|||
}
|
||||
}
|
||||
|
||||
public static string ReplaceAnyId(string path, char idType, SetId id, bool condition = true)
|
||||
public static string ReplaceAnyId(string path, char idType, PrimaryId id, bool condition = true)
|
||||
=> condition
|
||||
? Regex.Replace(path, $"{idType}\\d{{4}}", $"{idType}{id.Id:D4}")
|
||||
: path;
|
||||
|
|
@ -203,10 +203,10 @@ public static class ItemSwap
|
|||
public static string ReplaceAnyRace(string path, GenderRace to, bool condition = true)
|
||||
=> ReplaceAnyId(path, 'c', (ushort)to, condition);
|
||||
|
||||
public static string ReplaceAnyBody(string path, BodySlot slot, SetId to, bool condition = true)
|
||||
public static string ReplaceAnyBody(string path, BodySlot slot, PrimaryId to, bool condition = true)
|
||||
=> ReplaceAnyId(path, slot.ToAbbreviation(), to, condition);
|
||||
|
||||
public static string ReplaceId(string path, char type, SetId idFrom, SetId idTo, bool condition = true)
|
||||
public static string ReplaceId(string path, char type, PrimaryId idFrom, PrimaryId idTo, bool condition = true)
|
||||
=> condition
|
||||
? path.Replace($"{type}{idFrom.Id:D4}", $"{type}{idTo.Id:D4}")
|
||||
: path;
|
||||
|
|
@ -219,7 +219,7 @@ public static class ItemSwap
|
|||
public static string ReplaceRace(string path, GenderRace from, GenderRace to, bool condition = true)
|
||||
=> ReplaceId(path, 'c', (ushort)from, (ushort)to, condition);
|
||||
|
||||
public static string ReplaceBody(string path, BodySlot slot, SetId idFrom, SetId idTo, bool condition = true)
|
||||
public static string ReplaceBody(string path, BodySlot slot, PrimaryId idFrom, PrimaryId idTo, bool condition = true)
|
||||
=> ReplaceId(path, slot.ToAbbreviation(), idFrom, idTo, condition);
|
||||
|
||||
public static string AddSuffix(string path, string ext, string suffix, bool condition = true)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
using Lumina.Excel.GeneratedSheets;
|
||||
using Penumbra.Collections;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
using Penumbra.Meta.Manipulations;
|
||||
|
|
@ -7,17 +7,16 @@ using Penumbra.String.Classes;
|
|||
using Penumbra.Meta;
|
||||
using Penumbra.Mods.Manager;
|
||||
using Penumbra.Mods.Subclasses;
|
||||
using Penumbra.Services;
|
||||
|
||||
namespace Penumbra.Mods.ItemSwap;
|
||||
|
||||
public class ItemSwapContainer
|
||||
{
|
||||
private readonly MetaFileManager _manager;
|
||||
private readonly IdentifierService _identifier;
|
||||
private readonly MetaFileManager _manager;
|
||||
private readonly ObjectIdentification _identifier;
|
||||
|
||||
private Dictionary<Utf8GamePath, FullPath> _modRedirections = new();
|
||||
private HashSet<MetaManipulation> _modManipulations = new();
|
||||
private Dictionary<Utf8GamePath, FullPath> _modRedirections = [];
|
||||
private HashSet<MetaManipulation> _modManipulations = [];
|
||||
|
||||
public IReadOnlyDictionary<Utf8GamePath, FullPath> ModRedirections
|
||||
=> _modRedirections;
|
||||
|
|
@ -25,7 +24,7 @@ public class ItemSwapContainer
|
|||
public IReadOnlySet<MetaManipulation> ModManipulations
|
||||
=> _modManipulations;
|
||||
|
||||
public readonly List<Swap> Swaps = new();
|
||||
public readonly List<Swap> Swaps = [];
|
||||
|
||||
public bool Loaded { get; private set; }
|
||||
|
||||
|
|
@ -107,7 +106,7 @@ public class ItemSwapContainer
|
|||
}
|
||||
}
|
||||
|
||||
public ItemSwapContainer(MetaFileManager manager, IdentifierService identifier)
|
||||
public ItemSwapContainer(MetaFileManager manager, ObjectIdentification identifier)
|
||||
{
|
||||
_manager = manager;
|
||||
_identifier = identifier;
|
||||
|
|
@ -130,7 +129,7 @@ public class ItemSwapContainer
|
|||
{
|
||||
Swaps.Clear();
|
||||
Loaded = false;
|
||||
var ret = EquipmentSwap.CreateItemSwap(_manager, _identifier.AwaitedService, Swaps, PathResolver(collection), MetaResolver(collection),
|
||||
var ret = EquipmentSwap.CreateItemSwap(_manager, _identifier, Swaps, PathResolver(collection), MetaResolver(collection),
|
||||
from, to, useRightRing, useLeftRing);
|
||||
Loaded = true;
|
||||
return ret;
|
||||
|
|
@ -140,13 +139,13 @@ public class ItemSwapContainer
|
|||
{
|
||||
Swaps.Clear();
|
||||
Loaded = false;
|
||||
var ret = EquipmentSwap.CreateTypeSwap(_manager, _identifier.AwaitedService, Swaps, PathResolver(collection), MetaResolver(collection),
|
||||
var ret = EquipmentSwap.CreateTypeSwap(_manager, _identifier, Swaps, PathResolver(collection), MetaResolver(collection),
|
||||
slotFrom, from, slotTo, to);
|
||||
Loaded = true;
|
||||
return ret;
|
||||
}
|
||||
|
||||
public bool LoadCustomization(MetaFileManager manager, BodySlot slot, GenderRace race, SetId from, SetId to,
|
||||
public bool LoadCustomization(MetaFileManager manager, BodySlot slot, GenderRace race, PrimaryId from, PrimaryId to,
|
||||
ModCollection? collection = null)
|
||||
{
|
||||
var pathResolver = PathResolver(collection);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using Penumbra.Communication;
|
||||
using Penumbra.GameData;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.Meta.Manipulations;
|
||||
|
|
@ -9,11 +8,12 @@ namespace Penumbra.Mods.Manager;
|
|||
|
||||
public class ModCacheManager : IDisposable
|
||||
{
|
||||
private readonly CommunicatorService _communicator;
|
||||
private readonly IdentifierService _identifier;
|
||||
private readonly ModStorage _modManager;
|
||||
private readonly CommunicatorService _communicator;
|
||||
private readonly ObjectIdentification _identifier;
|
||||
private readonly ModStorage _modManager;
|
||||
private bool _updatingItems = false;
|
||||
|
||||
public ModCacheManager(CommunicatorService communicator, IdentifierService identifier, ModStorage modStorage)
|
||||
public ModCacheManager(CommunicatorService communicator, ObjectIdentification identifier, ModStorage modStorage)
|
||||
{
|
||||
_communicator = communicator;
|
||||
_identifier = identifier;
|
||||
|
|
@ -23,8 +23,7 @@ public class ModCacheManager : IDisposable
|
|||
_communicator.ModPathChanged.Subscribe(OnModPathChange, ModPathChanged.Priority.ModCacheManager);
|
||||
_communicator.ModDataChanged.Subscribe(OnModDataChange, ModDataChanged.Priority.ModCacheManager);
|
||||
_communicator.ModDiscoveryFinished.Subscribe(OnModDiscoveryFinished, ModDiscoveryFinished.Priority.ModCacheManager);
|
||||
if (!identifier.Valid)
|
||||
identifier.FinishedCreation += OnIdentifierCreation;
|
||||
identifier.Awaiter.ContinueWith(_ => OnIdentifierCreation());
|
||||
OnModDiscoveryFinished();
|
||||
}
|
||||
|
||||
|
|
@ -37,7 +36,7 @@ public class ModCacheManager : IDisposable
|
|||
}
|
||||
|
||||
/// <summary> Compute the items changed by a given meta manipulation and put them into the changedItems dictionary. </summary>
|
||||
public static void ComputeChangedItems(IObjectIdentifier identifier, IDictionary<string, object?> changedItems, MetaManipulation manip)
|
||||
public static void ComputeChangedItems(ObjectIdentification identifier, IDictionary<string, object?> changedItems, MetaManipulation manip)
|
||||
{
|
||||
switch (manip.ManipulationType)
|
||||
{
|
||||
|
|
@ -140,7 +139,7 @@ public class ModCacheManager : IDisposable
|
|||
{
|
||||
case ModPathChangeType.Added:
|
||||
case ModPathChangeType.Reloaded:
|
||||
Refresh(mod);
|
||||
RefreshWithChangedItems(mod);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -152,12 +151,27 @@ public class ModCacheManager : IDisposable
|
|||
}
|
||||
|
||||
private void OnModDiscoveryFinished()
|
||||
=> Parallel.ForEach(_modManager, Refresh);
|
||||
{
|
||||
if (!_identifier.Awaiter.IsCompletedSuccessfully || _updatingItems)
|
||||
{
|
||||
Parallel.ForEach(_modManager, RefreshWithoutChangedItems);
|
||||
}
|
||||
else
|
||||
{
|
||||
_updatingItems = true;
|
||||
Parallel.ForEach(_modManager, RefreshWithChangedItems);
|
||||
_updatingItems = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnIdentifierCreation()
|
||||
{
|
||||
if (_updatingItems)
|
||||
return;
|
||||
|
||||
_updatingItems = true;
|
||||
Parallel.ForEach(_modManager, UpdateChangedItems);
|
||||
_identifier.FinishedCreation -= OnIdentifierCreation;
|
||||
_updatingItems = false;
|
||||
}
|
||||
|
||||
private static void UpdateFileCount(Mod mod)
|
||||
|
|
@ -179,14 +193,11 @@ public class ModCacheManager : IDisposable
|
|||
{
|
||||
var changedItems = (SortedList<string, object?>)mod.ChangedItems;
|
||||
changedItems.Clear();
|
||||
if (!_identifier.Valid)
|
||||
return;
|
||||
|
||||
foreach (var gamePath in mod.AllSubMods.SelectMany(m => m.Files.Keys.Concat(m.FileSwaps.Keys)))
|
||||
_identifier.AwaitedService.Identify(changedItems, gamePath.ToString());
|
||||
_identifier.Identify(changedItems, gamePath.ToString());
|
||||
|
||||
foreach (var manip in mod.AllSubMods.SelectMany(m => m.Manipulations))
|
||||
ComputeChangedItems(_identifier.AwaitedService, changedItems, manip);
|
||||
ComputeChangedItems(_identifier, changedItems, manip);
|
||||
|
||||
mod.LowerChangedItemsString = string.Join("\0", mod.ChangedItems.Keys.Select(k => k.ToLowerInvariant()));
|
||||
}
|
||||
|
|
@ -209,10 +220,16 @@ public class ModCacheManager : IDisposable
|
|||
}
|
||||
}
|
||||
|
||||
private void Refresh(Mod mod)
|
||||
private void RefreshWithChangedItems(Mod mod)
|
||||
{
|
||||
UpdateTags(mod);
|
||||
UpdateCounts(mod);
|
||||
UpdateChangedItems(mod);
|
||||
}
|
||||
|
||||
private void RefreshWithoutChangedItems(Mod mod)
|
||||
{
|
||||
UpdateTags(mod);
|
||||
UpdateCounts(mod);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ using OtterGui;
|
|||
using OtterGui.Classes;
|
||||
using OtterGui.Filesystem;
|
||||
using Penumbra.Api.Enums;
|
||||
using Penumbra.GameData;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.Import;
|
||||
using Penumbra.Import.Structs;
|
||||
using Penumbra.Meta;
|
||||
|
|
@ -16,16 +16,18 @@ using Penumbra.String.Classes;
|
|||
|
||||
namespace Penumbra.Mods;
|
||||
|
||||
public partial class ModCreator(SaveService _saveService, Configuration _config, ModDataEditor _dataEditor, MetaFileManager _metaFileManager,
|
||||
IGamePathParser _gamePathParser)
|
||||
public partial class ModCreator(SaveService _saveService, Configuration config, ModDataEditor _dataEditor, MetaFileManager _metaFileManager,
|
||||
GamePathParser _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>
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -30,9 +30,9 @@ public sealed class SubMod : ISubMod
|
|||
public bool IsDefault
|
||||
=> GroupIdx < 0;
|
||||
|
||||
public Dictionary<Utf8GamePath, FullPath> FileData = new();
|
||||
public Dictionary<Utf8GamePath, FullPath> FileSwapData = new();
|
||||
public HashSet<MetaManipulation> ManipulationData = new();
|
||||
public Dictionary<Utf8GamePath, FullPath> FileData = [];
|
||||
public Dictionary<Utf8GamePath, FullPath> FileSwapData = [];
|
||||
public HashSet<MetaManipulation> ManipulationData = [];
|
||||
|
||||
public SubMod(IMod parentMod)
|
||||
=> ParentMod = parentMod;
|
||||
|
|
|
|||
|
|
@ -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}.");
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue