diff --git a/Penumbra/Services/PcpService.cs b/Penumbra/Services/PcpService.cs index 32eca652..73c61cdb 100644 --- a/Penumbra/Services/PcpService.cs +++ b/Penumbra/Services/PcpService.cs @@ -38,6 +38,7 @@ public class PcpService : IApiService, IDisposable private readonly CommunicatorService _communicator; private readonly SHA1 _sha1 = SHA1.Create(); private readonly ModFileSystem _fileSystem; + private readonly ModManager _mods; public PcpService(Configuration config, SaveService files, @@ -50,7 +51,8 @@ public class PcpService : IApiService, IDisposable ModCreator modCreator, ModExportManager modExport, CommunicatorService communicator, - ModFileSystem fileSystem) + ModFileSystem fileSystem, + ModManager mods) { _config = config; _files = files; @@ -64,10 +66,27 @@ public class PcpService : IApiService, IDisposable _modExport = modExport; _communicator = communicator; _fileSystem = fileSystem; + _mods = mods; _communicator.ModPathChanged.Subscribe(OnModPathChange, ModPathChanged.Priority.PcpService); } + public void CleanPcpMods() + { + var mods = _mods.Where(m => m.ModTags.Contains("PCP")).ToList(); + Penumbra.Log.Information($"[PCPService] Deleting {mods.Count} mods containing the tag PCP."); + foreach (var mod in mods) + _mods.DeleteMod(mod); + } + + public void CleanPcpCollections() + { + var collections = _collections.Storage.Where(c => c.Identity.Name.StartsWith("PCP/")).ToList(); + Penumbra.Log.Information($"[PCPService] Deleting {collections.Count} mods containing the tag PCP."); + foreach (var collection in collections) + _collections.Storage.Delete(collection); + } + private void OnModPathChange(ModPathChangeType type, Mod mod, DirectoryInfo? oldDirectory, DirectoryInfo? newDirectory) { if (type is not ModPathChangeType.Added || _config.DisablePcpHandling || newDirectory is null) @@ -80,12 +99,14 @@ public class PcpService : IApiService, IDisposable { // First version had collection.json, changed. var oldFile = Path.Combine(newDirectory.FullName, "collection.json"); + Penumbra.Log.Information("[PCPService] Renaming old PCP file from collection.json to character.json."); if (File.Exists(oldFile)) File.Move(oldFile, file, true); else return; } + Penumbra.Log.Information($"[PCPService] Found a PCP file for {mod.Name}, applying."); var text = File.ReadAllText(file); var jObj = JObject.Parse(text); var identifier = _actors.FromJson(jObj["Actor"] as JObject); @@ -116,6 +137,7 @@ public class PcpService : IApiService, IDisposable // ignored. } } + if (_config.AllowPcpIpc) _communicator.PcpParsing.Invoke(jObj, mod.Identifier, collection.Identity.Id); } @@ -132,6 +154,7 @@ public class PcpService : IApiService, IDisposable { try { + Penumbra.Log.Information($"[PCPService] Creating PCP file for game object {objectIndex.Index}."); var (identifier, tree, collection) = await _framework.Framework.RunOnFrameworkThread(() => { var (actor, identifier) = CheckActor(objectIndex); @@ -178,6 +201,7 @@ public class PcpService : IApiService, IDisposable { ["Version"] = 1, ["Actor"] = actor.ToJson(), + ["Mod"] = directory.Name, ["Collection"] = note.Length > 0 ? $"{actor.ToName()}: {note}" : actor.ToName(), ["Time"] = time, ["Note"] = note, diff --git a/Penumbra/UI/Tabs/SettingsTab.cs b/Penumbra/UI/Tabs/SettingsTab.cs index 143709f4..a6d03593 100644 --- a/Penumbra/UI/Tabs/SettingsTab.cs +++ b/Penumbra/UI/Tabs/SettingsTab.cs @@ -52,6 +52,7 @@ public class SettingsTab : ITab, IUiService private readonly CollectionAutoSelector _autoSelector; private readonly CleanupService _cleanupService; private readonly AttributeHook _attributeHook; + private readonly PcpService _pcpService; private int _minimumX = int.MaxValue; private int _minimumY = int.MaxValue; @@ -64,7 +65,7 @@ public class SettingsTab : ITab, IUiService DalamudSubstitutionProvider dalamudSubstitutionProvider, FileCompactor compactor, DalamudConfigService dalamudConfig, IDataManager gameData, PredefinedTagManager predefinedTagConfig, CrashHandlerService crashService, MigrationSectionDrawer migrationDrawer, CollectionAutoSelector autoSelector, CleanupService cleanupService, - AttributeHook attributeHook) + AttributeHook attributeHook, PcpService pcpService) { _pluginInterface = pluginInterface; _config = config; @@ -90,6 +91,7 @@ public class SettingsTab : ITab, IUiService _autoSelector = autoSelector; _cleanupService = cleanupService; _attributeHook = attributeHook; + _pcpService = pcpService; } public void DrawHeader() @@ -601,6 +603,23 @@ public class SettingsTab : ITab, IUiService Checkbox("Handle PCP Files", "When encountering specific mods, usually but not necessarily denoted by a .pcp file ending, Penumbra will automatically try to create an associated collection and assign it to a specific character for this mod package. This can turn this behaviour off if unwanted.", !_config.DisablePcpHandling, v => _config.DisablePcpHandling = !v); + + var active = _config.DeleteModModifier.IsActive(); + ImGui.SameLine(); + if (ImUtf8.ButtonEx("Delete all PCP Mods"u8, "Deletes all mods tagged with 'PCP' from the mod list."u8, disabled: !active)) + _pcpService.CleanPcpMods(); + if (!active) + ImUtf8.HoverTooltip(ImGuiHoveredFlags.AllowWhenDisabled, $"Hold {_config.DeleteModModifier} while clicking."); + + ImGui.SameLine(); + if (ImUtf8.ButtonEx("Delete all PCP Collections"u8, "Deletes all collections whose name starts with 'PCP/' from the collection list."u8, disabled: !active)) + _pcpService.CleanPcpCollections(); + if (!active) + ImUtf8.HoverTooltip(ImGuiHoveredFlags.AllowWhenDisabled, $"Hold {_config.DeleteModModifier} while clicking."); + + Checkbox("Allow Other Plugins Access to PCP Handling", + "When creating or importing PCP files, other plugins can add and interpret their own data to the character.json file.", + _config.AllowPcpIpc, v => _config.AllowPcpIpc = v); DrawDefaultModImportPath(); DrawDefaultModAuthor(); DrawDefaultModImportFolder();