mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 18:27:24 +01:00
Start group rework.
This commit is contained in:
parent
75cfffeba7
commit
8fc7de64d9
9 changed files with 106 additions and 45 deletions
|
|
@ -2,12 +2,10 @@ using OtterGui;
|
|||
using OtterGui.Classes;
|
||||
using Penumbra.Meta.Manipulations;
|
||||
using Penumbra.Mods;
|
||||
using Penumbra.Api.Enums;
|
||||
using Penumbra.Communication;
|
||||
using Penumbra.Mods.Editor;
|
||||
using Penumbra.String.Classes;
|
||||
using Penumbra.Mods.Manager;
|
||||
using Penumbra.Mods.Subclasses;
|
||||
|
||||
namespace Penumbra.Collections.Cache;
|
||||
|
||||
|
|
@ -231,37 +229,12 @@ public sealed class CollectionCache : IDisposable
|
|||
/// <summary> Add all files and possibly manipulations of a given mod according to its settings in this collection. </summary>
|
||||
internal void AddModSync(IMod mod, bool addMetaChanges)
|
||||
{
|
||||
if (mod.Index >= 0)
|
||||
{
|
||||
var settings = _collection[mod.Index].Settings;
|
||||
if (settings is not { Enabled: true })
|
||||
return;
|
||||
var files = GetFiles(mod);
|
||||
foreach (var (path, file) in files.FileRedirections)
|
||||
AddFile(path, file, mod);
|
||||
|
||||
foreach (var (group, groupIndex) in mod.Groups.WithIndex().OrderByDescending(g => g.Value.Priority))
|
||||
{
|
||||
if (group.Count == 0)
|
||||
continue;
|
||||
|
||||
var config = settings.Settings[groupIndex];
|
||||
switch (group)
|
||||
{
|
||||
case SingleModGroup single:
|
||||
AddSubMod(single[config.AsIndex], mod);
|
||||
break;
|
||||
case MultiModGroup multi:
|
||||
{
|
||||
foreach (var (option, _) in multi.WithIndex()
|
||||
.Where(p => config.HasFlag(p.Index))
|
||||
.OrderByDescending(p => group.OptionPriority(p.Index)))
|
||||
AddSubMod(option, mod);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AddSubMod(mod.Default, mod);
|
||||
foreach (var manip in files.Manipulations)
|
||||
AddManipulation(manip, mod);
|
||||
|
||||
if (addMetaChanges)
|
||||
{
|
||||
|
|
@ -273,14 +246,15 @@ public sealed class CollectionCache : IDisposable
|
|||
}
|
||||
}
|
||||
|
||||
// Add all files and possibly manipulations of a specific submod
|
||||
private void AddSubMod(ISubMod subMod, IMod parentMod)
|
||||
private AppliedModData GetFiles(IMod mod)
|
||||
{
|
||||
foreach (var (path, file) in subMod.Files.Concat(subMod.FileSwaps))
|
||||
AddFile(path, file, parentMod);
|
||||
if (mod.Index < 0)
|
||||
return mod.GetData();
|
||||
|
||||
foreach (var manip in subMod.Manipulations)
|
||||
AddManipulation(manip, parentMod);
|
||||
var settings = _collection[mod.Index].Settings;
|
||||
return settings is not { Enabled: true }
|
||||
? AppliedModData.Empty
|
||||
: mod.GetData(settings);
|
||||
}
|
||||
|
||||
/// <summary> Invoke only if not in a full recalculation. </summary>
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
using Penumbra.Meta.Manipulations;
|
||||
using Penumbra.Mods;
|
||||
using Penumbra.Mods.Editor;
|
||||
using Penumbra.String.Classes;
|
||||
|
||||
namespace Penumbra.Collections.Cache;
|
||||
|
||||
/// <summary>
|
||||
/// Contains associations between a mod and the paths and meta manipulations affected by that mod.
|
||||
/// </summary>
|
||||
public class CollectionModData
|
||||
{
|
||||
private readonly Dictionary<IMod, (HashSet<Utf8GamePath>, HashSet<MetaManipulation>)> _data = new();
|
||||
|
|
@ -17,7 +19,7 @@ public class CollectionModData
|
|||
if (_data.Remove(mod, out var data))
|
||||
return data;
|
||||
|
||||
return (Array.Empty<Utf8GamePath>(), Array.Empty<MetaManipulation>());
|
||||
return ([], []);
|
||||
}
|
||||
|
||||
public void AddPath(IMod mod, Utf8GamePath path)
|
||||
|
|
@ -28,7 +30,7 @@ public class CollectionModData
|
|||
}
|
||||
else
|
||||
{
|
||||
data = (new HashSet<Utf8GamePath> { path }, new HashSet<MetaManipulation>());
|
||||
data = ([path], []);
|
||||
_data.Add(mod, data);
|
||||
}
|
||||
}
|
||||
|
|
@ -41,7 +43,7 @@ public class CollectionModData
|
|||
}
|
||||
else
|
||||
{
|
||||
data = (new HashSet<Utf8GamePath>(), new HashSet<MetaManipulation> { manipulation });
|
||||
data = ([], [manipulation]);
|
||||
_data.Add(mod, data);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,27 @@
|
|||
using OtterGui.Classes;
|
||||
using Penumbra.Meta.Manipulations;
|
||||
using Penumbra.Mods.Subclasses;
|
||||
using Penumbra.String.Classes;
|
||||
|
||||
namespace Penumbra.Mods.Editor;
|
||||
|
||||
public record struct AppliedModData(
|
||||
IReadOnlyCollection<KeyValuePair<Utf8GamePath, FullPath>> FileRedirections,
|
||||
IReadOnlyCollection<MetaManipulation> Manipulations)
|
||||
{
|
||||
public static readonly AppliedModData Empty = new([], []);
|
||||
}
|
||||
|
||||
public interface IMod
|
||||
{
|
||||
LowerString Name { get; }
|
||||
|
||||
public int Index { get; }
|
||||
public int Index { get; }
|
||||
public ModPriority Priority { get; }
|
||||
|
||||
public AppliedModData GetData(ModSettings? settings = null);
|
||||
|
||||
|
||||
public ISubMod Default { get; }
|
||||
public IReadOnlyList<IModGroup> Groups { get; }
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
using OtterGui;
|
||||
using OtterGui.Classes;
|
||||
using Penumbra.Collections.Cache;
|
||||
using Penumbra.Meta.Manipulations;
|
||||
using Penumbra.Mods.Editor;
|
||||
using Penumbra.Mods.Subclasses;
|
||||
using Penumbra.String.Classes;
|
||||
|
|
@ -59,6 +61,23 @@ public sealed class Mod : IMod
|
|||
public readonly SubMod Default;
|
||||
public readonly List<IModGroup> Groups = [];
|
||||
|
||||
public AppliedModData GetData(ModSettings? settings = null)
|
||||
{
|
||||
if (settings is not { Enabled: true })
|
||||
return AppliedModData.Empty;
|
||||
|
||||
var dictRedirections = new Dictionary<Utf8GamePath, FullPath>(TotalFileCount);
|
||||
var setManips = new HashSet<MetaManipulation>(TotalManipulations);
|
||||
foreach (var (group, groupIndex) in Groups.WithIndex().OrderByDescending(g => g.Value.Priority))
|
||||
{
|
||||
var config = settings.Settings[groupIndex];
|
||||
group.AddData(config, dictRedirections, setManips);
|
||||
}
|
||||
|
||||
((ISubMod)Default).AddData(dictRedirections, setManips);
|
||||
return new AppliedModData(dictRedirections, setManips);
|
||||
}
|
||||
|
||||
ISubMod IMod.Default
|
||||
=> Default;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
using Newtonsoft.Json;
|
||||
using Penumbra.Api.Enums;
|
||||
using Penumbra.Meta.Manipulations;
|
||||
using Penumbra.Services;
|
||||
using Penumbra.String.Classes;
|
||||
|
||||
namespace Penumbra.Mods.Subclasses;
|
||||
|
||||
|
|
@ -24,6 +26,8 @@ public interface IModGroup : IReadOnlyCollection<ISubMod>
|
|||
public bool MoveOption(int optionIdxFrom, int optionIdxTo);
|
||||
public void UpdatePositions(int from = 0);
|
||||
|
||||
public void AddData(Setting setting, Dictionary<Utf8GamePath, FullPath> redirections, HashSet<MetaManipulation> manipulations);
|
||||
|
||||
/// <summary> Ensure that a value is valid for a group. </summary>
|
||||
public Setting FixSetting(Setting setting);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,16 @@ public interface ISubMod
|
|||
public IReadOnlyDictionary<Utf8GamePath, FullPath> FileSwaps { get; }
|
||||
public IReadOnlySet<MetaManipulation> Manipulations { get; }
|
||||
|
||||
public void AddData(Dictionary<Utf8GamePath, FullPath> redirections, HashSet<MetaManipulation> manipulations)
|
||||
{
|
||||
foreach (var (path, file) in Files)
|
||||
redirections.TryAdd(path, file);
|
||||
|
||||
foreach (var (path, file) in FileSwaps)
|
||||
redirections.TryAdd(path, file);
|
||||
manipulations.UnionWith(Manipulations);
|
||||
}
|
||||
|
||||
public bool IsDefault { get; }
|
||||
|
||||
public static void WriteSubMod(JsonWriter j, JsonSerializer serializer, ISubMod mod, DirectoryInfo basePath, ModPriority? priority)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ using OtterGui;
|
|||
using OtterGui.Classes;
|
||||
using OtterGui.Filesystem;
|
||||
using Penumbra.Api.Enums;
|
||||
using Penumbra.Meta.Manipulations;
|
||||
using Penumbra.String.Classes;
|
||||
|
||||
namespace Penumbra.Mods.Subclasses;
|
||||
|
||||
|
|
@ -110,6 +112,15 @@ public sealed class MultiModGroup : IModGroup
|
|||
o.SetPosition(o.GroupIdx, i);
|
||||
}
|
||||
|
||||
public void AddData(Setting setting, Dictionary<Utf8GamePath, FullPath> redirections, HashSet<MetaManipulation> manipulations)
|
||||
{
|
||||
foreach (var (option, index) in PrioritizedOptions.WithIndex().OrderByDescending(o => o.Value.Priority))
|
||||
{
|
||||
if (setting.HasFlag(index))
|
||||
((ISubMod)option.Mod).AddData(redirections, manipulations);
|
||||
}
|
||||
}
|
||||
|
||||
public Setting FixSetting(Setting setting)
|
||||
=> new(setting.Value & ((1ul << Count) - 1));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ using Newtonsoft.Json.Linq;
|
|||
using OtterGui;
|
||||
using OtterGui.Filesystem;
|
||||
using Penumbra.Api.Enums;
|
||||
using Penumbra.Meta.Manipulations;
|
||||
using Penumbra.String.Classes;
|
||||
|
||||
namespace Penumbra.Mods.Subclasses;
|
||||
|
||||
|
|
@ -114,6 +116,9 @@ public sealed class SingleModGroup : IModGroup
|
|||
o.SetPosition(o.GroupIdx, i);
|
||||
}
|
||||
|
||||
public void AddData(Setting setting, Dictionary<Utf8GamePath, FullPath> redirections, HashSet<MetaManipulation> manipulations)
|
||||
=> this[setting.AsIndex].AddData(redirections, manipulations);
|
||||
|
||||
public Setting FixSetting(Setting setting)
|
||||
=> Count == 0 ? Setting.Zero : new Setting(Math.Min(setting.Value, (ulong)(Count - 1)));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,28 @@ public class TemporaryMod : IMod
|
|||
|
||||
public readonly SubMod Default;
|
||||
|
||||
public AppliedModData GetData(ModSettings? settings = null)
|
||||
{
|
||||
Dictionary<Utf8GamePath, FullPath> dict;
|
||||
if (Default.FileSwapData.Count == 0)
|
||||
{
|
||||
dict = Default.FileData;
|
||||
}
|
||||
else if (Default.FileData.Count == 0)
|
||||
{
|
||||
dict = Default.FileSwapData;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Need to ensure uniqueness.
|
||||
dict = new Dictionary<Utf8GamePath, FullPath>(Default.FileData.Count + Default.FileSwaps.Count);
|
||||
foreach (var (gamePath, file) in Default.FileData.Concat(Default.FileSwaps))
|
||||
dict.TryAdd(gamePath, file);
|
||||
}
|
||||
|
||||
return new AppliedModData(dict, Default.Manipulations);
|
||||
}
|
||||
|
||||
ISubMod IMod.Default
|
||||
=> Default;
|
||||
|
||||
|
|
@ -53,7 +75,8 @@ public class TemporaryMod : IMod
|
|||
dir = ModCreator.CreateModFolder(modManager.BasePath, collection.Name, config.ReplaceNonAsciiOnImport, true);
|
||||
var fileDir = Directory.CreateDirectory(Path.Combine(dir.FullName, "files"));
|
||||
modManager.DataEditor.CreateMeta(dir, collection.Name, character ?? config.DefaultModAuthor,
|
||||
$"Mod generated from temporary collection {collection.Id} for {character ?? "Unknown Character"} with name {collection.Name}.", null, null);
|
||||
$"Mod generated from temporary collection {collection.Id} for {character ?? "Unknown Character"} with name {collection.Name}.",
|
||||
null, null);
|
||||
var mod = new Mod(dir);
|
||||
var defaultMod = mod.Default;
|
||||
foreach (var (gamePath, fullPath) in collection.ResolvedFiles)
|
||||
|
|
@ -86,7 +109,8 @@ public class TemporaryMod : IMod
|
|||
|
||||
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.Identifier}.");
|
||||
Penumbra.Log.Information(
|
||||
$"Successfully generated mod {mod.Name} at {mod.ModPath.FullName} for collection {collection.Identifier}.");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue