Merge branch 'master' into restree-blurb

This commit is contained in:
Exter-N 2024-06-02 00:05:16 +02:00
commit 3b26e97231
17 changed files with 129 additions and 98 deletions

@ -1 +1 @@
Subproject commit 1d9365164655a7cb38172e1311e15e19b1def6db
Subproject commit 0b5afffda19d3e16aec9e8682d18c8f11f67f1c6

@ -1 +1 @@
Subproject commit 69d106b457eb0f73d4b4caf1234da5631fd6fbf0
Subproject commit f1e4e520daaa8f23e5c8b71d55e5992b8f6768e2

@ -1 +1 @@
Subproject commit f2cea65b83b2d6cb0d03339e8f76aed8102a41d5
Subproject commit 29b71cf7b3cc68995d38f0954fa38c4b9500a81d

View file

@ -106,8 +106,8 @@ public class ModsApi : IPenumbraApiMods, IApiService, IDisposable
var fullPath = leaf.FullName();
var isDefault = ModFileSystem.ModHasDefaultPath(mod, fullPath);
var isNameDefault = isDefault || ModFileSystem.ModHasDefaultPath(mod, leaf.Name);
return (PenumbraApiEc.Success, fullPath, !isDefault, !isNameDefault );
var isNameDefault = isDefault || ModFileSystem.ModHasDefaultPath(mod, leaf.Name);
return (PenumbraApiEc.Success, fullPath, !isDefault, !isNameDefault);
}
public PenumbraApiEc SetModPath(string modDirectory, string modName, string newPath)
@ -129,4 +129,9 @@ public class ModsApi : IPenumbraApiMods, IApiService, IDisposable
return PenumbraApiEc.PathRenameFailed;
}
}
public Dictionary<string, object?> GetChangedItems(string modDirectory, string modName)
=> _modManager.TryGetMod(modDirectory, modName, out var mod)
? mod.ChangedItems.ToDictionary(kvp => kvp.Key, kvp => kvp.Value)
: [];
}

View file

@ -22,7 +22,7 @@ public class PenumbraApi(
}
public (int Breaking, int Feature) ApiVersion
=> (5, 0);
=> (5, 1);
public bool Valid { get; private set; } = true;
public IPenumbraApiCollection Collection { get; } = collection;

View file

@ -49,6 +49,7 @@ public sealed class IpcProviders : IDisposable, IApiService
IpcSubscribers.ModMoved.Provider(pi, api.Mods),
IpcSubscribers.GetModPath.Provider(pi, api.Mods),
IpcSubscribers.SetModPath.Provider(pi, api.Mods),
IpcSubscribers.GetChangedItems.Provider(pi, api.Mods),
IpcSubscribers.GetAvailableModSettings.Provider(pi, api.ModSettings),
IpcSubscribers.GetCurrentModSettings.Provider(pi, api.ModSettings),

View file

@ -3,6 +3,7 @@ using Dalamud.Plugin;
using ImGuiNET;
using OtterGui.Raii;
using OtterGui.Services;
using OtterGui.Text;
using Penumbra.Api.Enums;
using Penumbra.Api.Helpers;
using Penumbra.Api.IpcSubscribers;
@ -13,16 +14,17 @@ public class ModsIpcTester : IUiService, IDisposable
{
private readonly DalamudPluginInterface _pi;
private string _modDirectory = string.Empty;
private string _modName = string.Empty;
private string _pathInput = string.Empty;
private string _newInstallPath = string.Empty;
private PenumbraApiEc _lastReloadEc;
private PenumbraApiEc _lastAddEc;
private PenumbraApiEc _lastDeleteEc;
private PenumbraApiEc _lastSetPathEc;
private PenumbraApiEc _lastInstallEc;
private Dictionary<string, string> _mods = [];
private string _modDirectory = string.Empty;
private string _modName = string.Empty;
private string _pathInput = string.Empty;
private string _newInstallPath = string.Empty;
private PenumbraApiEc _lastReloadEc;
private PenumbraApiEc _lastAddEc;
private PenumbraApiEc _lastDeleteEc;
private PenumbraApiEc _lastSetPathEc;
private PenumbraApiEc _lastInstallEc;
private Dictionary<string, string> _mods = [];
private Dictionary<string, object?> _changedItems = [];
public readonly EventSubscriber<string> DeleteSubscriber;
public readonly EventSubscriber<string> AddSubscriber;
@ -120,6 +122,14 @@ public class ModsIpcTester : IUiService, IDisposable
ImGui.SameLine();
ImGui.TextUnformatted(_lastDeleteEc.ToString());
IpcTester.DrawIntro(GetChangedItems.Label, "Get Changed Items");
DrawChangedItemsPopup();
if (ImUtf8.Button("Get##ChangedItems"u8))
{
_changedItems = new GetChangedItems(_pi).Invoke(_modDirectory, _modName);
ImUtf8.OpenPopup("ChangedItems"u8);
}
IpcTester.DrawIntro(GetModPath.Label, "Current Path");
var (ec, path, def, nameDef) = new GetModPath(_pi).Invoke(_modDirectory, _modName);
ImGui.TextUnformatted($"{path} ({(def ? "Custom" : "Default")} Path, {(nameDef ? "Custom" : "Default")} Name) [{ec}]");
@ -157,4 +167,18 @@ public class ModsIpcTester : IUiService, IDisposable
if (ImGui.Button("Close", -Vector2.UnitX) || !ImGui.IsWindowFocused())
ImGui.CloseCurrentPopup();
}
private void DrawChangedItemsPopup()
{
ImGui.SetNextWindowSize(ImGuiHelpers.ScaledVector2(500, 500));
using var p = ImUtf8.Popup("ChangedItems"u8);
if (!p)
return;
foreach (var (name, data) in _changedItems)
ImUtf8.Text($"{name}: {data}");
if (ImUtf8.Button("Close"u8, -Vector2.UnitX) || !ImGui.IsWindowFocused())
ImGui.CloseCurrentPopup();
}
}

View file

@ -153,7 +153,11 @@ public class CollectionStorage : IReadOnlyList<ModCollection>, IDisposable
/// </summary>
public bool AddCollection(string name, ModCollection? duplicate)
{
if (name.Length == 0)
return false;
var newCollection = Create(name, _collections.Count, duplicate);
_collections.Add(newCollection);
_saveService.ImmediateSave(new ModCollectionSave(_modStorage, newCollection));
Penumbra.Messager.NotificationMessage($"Created new collection {newCollection.AnonymizedName}.", NotificationType.Success, false);
_communicator.CollectionChange.Invoke(CollectionType.Inactive, null, newCollection, string.Empty);

View file

@ -44,10 +44,10 @@ public struct GlobalEqpCache : IService
if (_doNotHideBracelets.Contains(armor[7].Set))
original |= EqpEntry.BodyShowBracelet | EqpEntry.HandShowBracelet;
if (_doNotHideBracelets.Contains(armor[8].Set))
if (_doNotHideRingR.Contains(armor[8].Set))
original |= EqpEntry.HandShowRingR;
if (_doNotHideBracelets.Contains(armor[9].Set))
if (_doNotHideRingL.Contains(armor[9].Set))
original |= EqpEntry.HandShowRingL;
return original;
}

View file

@ -1,5 +1,9 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
namespace Penumbra.Meta.Manipulations;
[JsonConverter(typeof(StringEnumConverter))]
public enum GlobalEqpType
{
DoNotHideEarrings,

View file

@ -37,7 +37,7 @@ public class ModMerger : IDisposable
public readonly HashSet<IModDataContainer> SelectedOptions = [];
public readonly IReadOnlyList<string> Warnings = [];
public readonly IReadOnlyList<string> Warnings = new List<string>();
public Exception? Error { get; private set; }
public ModMerger(ModManager mods, ModGroupEditor editor, ModFileSystemSelector selector, DuplicateManager duplicates,

View file

@ -1,3 +1,4 @@
using System.Collections.Frozen;
using Penumbra.Meta.Manipulations;
using Penumbra.Mods.Manager;
using Penumbra.Mods.SubMods;
@ -14,13 +15,19 @@ public class ModMetaEditor(ModManager modManager)
private readonly HashSet<RspManipulation> _rsp = [];
private readonly HashSet<GlobalEqpManipulation> _globalEqp = [];
public int OtherImcCount { get; private set; }
public int OtherEqpCount { get; private set; }
public int OtherEqdpCount { get; private set; }
public int OtherGmpCount { get; private set; }
public int OtherEstCount { get; private set; }
public int OtherRspCount { get; private set; }
public int OtherGlobalEqpCount { get; private set; }
public sealed class OtherOptionData : HashSet<string>
{
public int TotalCount;
public new void Clear()
{
TotalCount = 0;
base.Clear();
}
}
public readonly FrozenDictionary<MetaManipulation.Type, OtherOptionData> OtherData =
Enum.GetValues<MetaManipulation.Type>().ToFrozenDictionary(t => t, _ => new OtherOptionData());
public bool Changes { get; private set; }
@ -114,13 +121,9 @@ public class ModMetaEditor(ModManager modManager)
public void Load(Mod mod, IModDataContainer currentOption)
{
OtherImcCount = 0;
OtherEqpCount = 0;
OtherEqdpCount = 0;
OtherGmpCount = 0;
OtherEstCount = 0;
OtherRspCount = 0;
OtherGlobalEqpCount = 0;
foreach (var type in Enum.GetValues<MetaManipulation.Type>())
OtherData[type].Clear();
foreach (var option in mod.AllDataContainers)
{
if (option == currentOption)
@ -128,30 +131,9 @@ public class ModMetaEditor(ModManager modManager)
foreach (var manip in option.Manipulations)
{
switch (manip.ManipulationType)
{
case MetaManipulation.Type.Imc:
++OtherImcCount;
break;
case MetaManipulation.Type.Eqdp:
++OtherEqdpCount;
break;
case MetaManipulation.Type.Eqp:
++OtherEqpCount;
break;
case MetaManipulation.Type.Est:
++OtherEstCount;
break;
case MetaManipulation.Type.Gmp:
++OtherGmpCount;
break;
case MetaManipulation.Type.Rsp:
++OtherRspCount;
break;
case MetaManipulation.Type.GlobalEqp:
++OtherGlobalEqpCount;
break;
}
var data = OtherData[manip.ManipulationType];
++data.TotalCount;
data.Add(option.GetFullName());
}
}

View file

@ -66,37 +66,45 @@ public partial class ModEditWindow
return;
DrawEditHeader(_editor.MetaEditor.Eqp, "Equipment Parameter Edits (EQP)###EQP", 5, EqpRow.Draw, EqpRow.DrawNew,
_editor.MetaEditor.OtherEqpCount);
_editor.MetaEditor.OtherData[MetaManipulation.Type.Eqp]);
DrawEditHeader(_editor.MetaEditor.Eqdp, "Racial Model Edits (EQDP)###EQDP", 7, EqdpRow.Draw, EqdpRow.DrawNew,
_editor.MetaEditor.OtherEqdpCount);
DrawEditHeader(_editor.MetaEditor.Imc, "Variant Edits (IMC)###IMC", 10, ImcRow.Draw, ImcRow.DrawNew, _editor.MetaEditor.OtherImcCount);
_editor.MetaEditor.OtherData[MetaManipulation.Type.Eqdp]);
DrawEditHeader(_editor.MetaEditor.Imc, "Variant Edits (IMC)###IMC", 10, ImcRow.Draw, ImcRow.DrawNew,
_editor.MetaEditor.OtherData[MetaManipulation.Type.Imc]);
DrawEditHeader(_editor.MetaEditor.Est, "Extra Skeleton Parameters (EST)###EST", 7, EstRow.Draw, EstRow.DrawNew,
_editor.MetaEditor.OtherEstCount);
_editor.MetaEditor.OtherData[MetaManipulation.Type.Est]);
DrawEditHeader(_editor.MetaEditor.Gmp, "Visor/Gimmick Edits (GMP)###GMP", 7, GmpRow.Draw, GmpRow.DrawNew,
_editor.MetaEditor.OtherGmpCount);
_editor.MetaEditor.OtherData[MetaManipulation.Type.Gmp]);
DrawEditHeader(_editor.MetaEditor.Rsp, "Racial Scaling Edits (RSP)###RSP", 5, RspRow.Draw, RspRow.DrawNew,
_editor.MetaEditor.OtherRspCount);
_editor.MetaEditor.OtherData[MetaManipulation.Type.Rsp]);
DrawEditHeader(_editor.MetaEditor.GlobalEqp, "Global Equipment Parameter Edits (Global EQP)###GEQP", 4, GlobalEqpRow.Draw,
GlobalEqpRow.DrawNew, _editor.MetaEditor.OtherGlobalEqpCount);
GlobalEqpRow.DrawNew, _editor.MetaEditor.OtherData[MetaManipulation.Type.GlobalEqp]);
}
/// <summary> The headers for the different meta changes all have basically the same structure for different types.</summary>
private void DrawEditHeader<T>(IReadOnlyCollection<T> items, string label, int numColumns,
Action<MetaFileManager, T, ModEditor, Vector2> draw,
Action<MetaFileManager, ModEditor, Vector2> drawNew, int otherCount)
Action<MetaFileManager, T, ModEditor, Vector2> draw, Action<MetaFileManager, ModEditor, Vector2> drawNew,
ModMetaEditor.OtherOptionData otherOptionData)
{
const ImGuiTableFlags flags = ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.BordersInnerV;
var oldPos = ImGui.GetCursorPosY();
var header = ImGui.CollapsingHeader($"{items.Count} {label}");
var newPos = ImGui.GetCursorPos();
if (otherCount > 0)
if (otherOptionData.TotalCount > 0)
{
var text = $"{otherCount} Edits in other Options";
var text = $"{otherOptionData.TotalCount} Edits in other Options";
var size = ImGui.CalcTextSize(text).X;
ImGui.SetCursorPos(new Vector2(ImGui.GetContentRegionAvail().X - size, oldPos + ImGui.GetStyle().FramePadding.Y));
ImGuiUtil.TextColored(ColorId.RedundantAssignment.Value() | 0xFF000000, text);
if (ImGui.IsItemHovered())
{
using var tt = ImUtf8.Tooltip();
foreach (var name in otherOptionData)
ImUtf8.Text(name);
}
ImGui.SetCursorPos(newPos);
}

View file

@ -47,19 +47,26 @@ public class PenumbraChangelog
Add8_2_0(Changelog);
Add8_3_0(Changelog);
Add1_0_0_0(Changelog);
Add1_0_2_0(Changelog);
Add1_0_3_0(Changelog);
AddDummy(Changelog);
AddDummy(Changelog);
Add1_1_0_0(Changelog);
}
#region Changelogs
private static void Add1_0_3_0(Changelog log)
=> log.NextVersion("Version 1.0.3.0")
private static void Add1_1_0_0(Changelog log)
=> log.NextVersion("Version 1.1.0.0")
.RegisterImportant(
"This update comes, again, with a lot of very heavy backend changes (collections and groups) and thus may introduce new issues.")
.RegisterEntry("Updated to .net8 and XIV 6.58, using some new framework facilities to improve performance and stability.")
.RegisterHighlight(
"Added an experimental crash handler that is supposed to write a Penumbra.log file when the game crashes, containing Penumbra-specific information.")
.RegisterEntry("This is disabled by default. It can be enabled in Advanced Settings.", 1)
.RegisterHighlight("Collections now have associated GUIDs as identifiers instead of their names, so they can now be renamed.")
.RegisterEntry("Migrating those collections may introduce issues, please let me know as soon as possible if you encounter any.", 1)
.RegisterEntry("A permanent (non-rolling) backup should be created before the migration in case of any issues.", 1)
.RegisterHighlight(
"Added predefined tags that can be setup in the Settings tab and can be more easily applied or removed from mods. (by DZD)")
.RegisterHighlight(
"A total rework of how options and groups are handled internally, and introduction of the first new group type, the IMC Group.")
.RegisterEntry(
@ -75,9 +82,14 @@ public class PenumbraChangelog
.RegisterEntry(
"This can be used if something like a jacket or a stole is put onto an accessory to prevent it from being hidden in general.",
1)
.RegisterEntry(
"The first empty option in a single-select option group imported from a TTMP will now keep its location instead of being moved to the first option.")
.RegisterEntry("Further empty options are still removed.", 1)
.RegisterHighlight(
"Added a field to rename mods directly from the mod selector context menu, instead of moving them in the filesystem.")
.RegisterEntry("You can choose which rename field (none, either one or both) to display in the settings.", 1)
.RegisterEntry("Added the characterglass.shpk shader file to special shader treatment to fix issues when replacing it. (By Ny)")
.RegisterEntry("Made it more obvious if a user has not set their root directory yet.")
.RegisterEntry(
"You can now paste your current clipboard text into the mod selector filter with a simple right-click as long as it is not focused.")
.RegisterHighlight(
@ -88,29 +100,17 @@ public class PenumbraChangelog
.RegisterEntry("Removed the auto-generated descriptions for newly created groups in Penumbra.")
.RegisterEntry(
"Made some improvements to the Advanced Editing window, for example a much better and more performant Hex Viewer for unstructured data was added.")
.RegisterEntry("Made a lot of further improvements on Model import/export (by ackwell).")
.RegisterEntry("Various improvements to model import/export by ackwell (throughout all patches).")
.RegisterEntry("Hovering over meta manipulations in other options in the advanced editing window now shows a list of those options.")
.RegisterEntry("Reworked the API and IPC structure heavily.")
.RegisterImportant("This means some plugins interacting with Penumbra may not work correctly until they update.", 1)
.RegisterEntry("Worked around the UI IPC possibly displacing all settings when the drawn additions became too big.")
.RegisterEntry("Fixed an issue where reloading a mod did not ensure settings for that mod being correct afterwards.")
.RegisterEntry("Fixed some issues with the file sizes of compressed files.")
.RegisterEntry("Fixed an issue with merging and deduplicating mods.")
.RegisterEntry("Fixed a crash when scanning for mods without access rights to the folder.")
.RegisterEntry(
"Made plugin conform to Dalamud requirements by adding a punchline and another button to open the menu from the installer.");
private static void Add1_0_2_0(Changelog log)
=> log.NextVersion("Version 1.0.2.0")
.RegisterEntry("Updated to .net8 and XIV 6.58, using some new framework facilities to improve performance and stability.")
.RegisterHighlight(
"Added an experimental crash handler that is supposed to write a Penumbra.log file when the game crashes, containing Penumbra-specific information.")
.RegisterEntry("Various improvements to model import/export by ackwell (throughout all patches).")
.RegisterHighlight(
"Added predefined tags that can be setup in the Settings tab and can be more easily applied or removed from mods. (by DZD)")
.RegisterEntry(
"The first empty option in a single-select option group imported from a TTMP will now keep its location instead of being moved to the first option.")
.RegisterEntry("Further empty options are still removed.", 1)
.RegisterEntry("Made it more obvious if a user has not set their root directory yet.")
.RegisterEntry("Added the characterglass.shpk shader file to special shader treatment to fix issues when replacing it. (By Ny)")
.RegisterEntry("Fixed some issues with the file sizes of compressed files.")
.RegisterEntry("Fixed an issue where reloading a mod did not ensure settings for that mod being correct afterwards.")
"Made plugin conform to Dalamud requirements by adding a punchline and another button to open the menu from the installer.")
.RegisterEntry("Added an option to automatically redraw the player character when saving files. (1.0.0.8)")
.RegisterEntry("Fixed issue with manipulating mods not triggering some events. (1.0.0.7)")
.RegisterEntry("Fixed issue with temporary mods not triggering some events. (1.0.0.6)")
@ -762,6 +762,9 @@ public class PenumbraChangelog
#endregion
private static void AddDummy(Changelog log)
=> log.NextVersion(string.Empty);
private (int, ChangeLogDisplayType) ConfigData()
=> (_config.Ephemeral.LastSeenVersion, _config.ChangeLogDisplayType);

View file

@ -109,7 +109,7 @@ public sealed class CollectionSelector : ItemSelector<ModCollection>, IDisposabl
}
private string Name(ModCollection collection)
=> _incognito.IncognitoMode ? collection.AnonymizedName : collection.Name;
=> _incognito.IncognitoMode || collection.Name.Length == 0 ? collection.AnonymizedName : collection.Name;
private void OnCollectionChange(CollectionType type, ModCollection? old, ModCollection? @new, string _3)
{

View file

@ -321,8 +321,8 @@ public sealed class ModGroupEditDrawer(
&& (!_draggingAcross || (_dragDropGroup != null && group is MultiModGroup { Options.Count: >= IModGroup.MaxMultiOptions })))
return;
using var target = ImRaii.DragDropTarget();
if (!target.Success || !DragDropTarget.CheckPayload(_draggingAcross ? AcrossGroupsLabel : InsideGroupLabel))
using var target = ImUtf8.DragDropTarget();
if (!target.IsDropping(_draggingAcross ? AcrossGroupsLabel : InsideGroupLabel))
return;
if (_dragDropGroup != null && _dragDropOption != null)

View file

@ -5,8 +5,8 @@
"Punchline": "Runtime mod loader and manager.",
"Description": "Runtime mod loader and manager.",
"InternalName": "Penumbra",
"AssemblyVersion": "1.0.1.0",
"TestingAssemblyVersion": "1.0.3.2",
"AssemblyVersion": "1.1.0.2",
"TestingAssemblyVersion": "1.1.0.2",
"RepoUrl": "https://github.com/xivdev/Penumbra",
"ApplicableVersion": "any",
"DalamudApiLevel": 9,
@ -17,9 +17,9 @@
"LoadPriority": 69420,
"LoadRequiredState": 2,
"LoadSync": true,
"DownloadLinkInstall": "https://github.com/xivdev/Penumbra/releases/download/1.0.1.0/Penumbra.zip",
"DownloadLinkTesting": "https://github.com/xivdev/Penumbra/releases/download/testing_1.0.3.2/Penumbra.zip",
"DownloadLinkUpdate": "https://github.com/xivdev/Penumbra/releases/download/1.0.1.0/Penumbra.zip",
"DownloadLinkInstall": "https://github.com/xivdev/Penumbra/releases/download/1.1.0.2/Penumbra.zip",
"DownloadLinkTesting": "https://github.com/xivdev/Penumbra/releases/download/1.1.0.2/Penumbra.zip",
"DownloadLinkUpdate": "https://github.com/xivdev/Penumbra/releases/download/1.1.0.2/Penumbra.zip",
"IconUrl": "https://raw.githubusercontent.com/xivdev/Penumbra/master/images/icon.png"
}
]