mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-13 12:14:17 +01:00
This commit is contained in:
parent
d302a17f1f
commit
6079103505
6 changed files with 61 additions and 35 deletions
|
|
@ -1 +1 @@
|
||||||
Subproject commit 0a970295b2398683b1e49c46fd613541e2486210
|
Subproject commit 297941bc22300f4a8368f4d0177f62943eb69727
|
||||||
|
|
@ -108,7 +108,7 @@ public class ModsApi : IPenumbraApiMods, IApiService, IDisposable
|
||||||
public event Action<string>? ModAdded;
|
public event Action<string>? ModAdded;
|
||||||
public event Action<string, string>? ModMoved;
|
public event Action<string, string>? ModMoved;
|
||||||
|
|
||||||
public event Action<JObject, ushort>? CreatingPcp
|
public event Action<JObject, ushort, string>? CreatingPcp
|
||||||
{
|
{
|
||||||
add => _communicator.PcpCreation.Subscribe(value!, PcpCreation.Priority.ModsApi);
|
add => _communicator.PcpCreation.Subscribe(value!, PcpCreation.Priority.ModsApi);
|
||||||
remove => _communicator.PcpCreation.Unsubscribe(value!);
|
remove => _communicator.PcpCreation.Unsubscribe(value!);
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,10 @@ namespace Penumbra.Communication;
|
||||||
/// <list type="number">
|
/// <list type="number">
|
||||||
/// <item>Parameter is the JObject that gets written to file. </item>
|
/// <item>Parameter is the JObject that gets written to file. </item>
|
||||||
/// <item>Parameter is the object index of the game object this is written for. </item>
|
/// <item>Parameter is the object index of the game object this is written for. </item>
|
||||||
|
/// <item>Parameter is the full path to the directory being set up for the PCP creation. </item>
|
||||||
/// </list>
|
/// </list>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class PcpCreation() : EventWrapper<JObject, ushort, PcpCreation.Priority>(nameof(PcpCreation))
|
public sealed class PcpCreation() : EventWrapper<JObject, ushort, string, PcpCreation.Priority>(nameof(PcpCreation))
|
||||||
{
|
{
|
||||||
public enum Priority
|
public enum Priority
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,15 @@ using ErrorEventArgs = Newtonsoft.Json.Serialization.ErrorEventArgs;
|
||||||
|
|
||||||
namespace Penumbra;
|
namespace Penumbra;
|
||||||
|
|
||||||
|
public record PcpSettings
|
||||||
|
{
|
||||||
|
public bool CreateCollection { get; set; } = true;
|
||||||
|
public bool AssignCollection { get; set; } = true;
|
||||||
|
public bool AllowIpc { get; set; } = true;
|
||||||
|
public bool DisableHandling { get; set; } = false;
|
||||||
|
public string FolderName { get; set; } = "PCP";
|
||||||
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class Configuration : IPluginConfiguration, ISavable, IService
|
public class Configuration : IPluginConfiguration, ISavable, IService
|
||||||
{
|
{
|
||||||
|
|
@ -68,11 +77,10 @@ public class Configuration : IPluginConfiguration, ISavable, IService
|
||||||
public bool HideMachinistOffhandFromChangedItems { get; set; } = true;
|
public bool HideMachinistOffhandFromChangedItems { get; set; } = true;
|
||||||
public bool DefaultTemporaryMode { get; set; } = false;
|
public bool DefaultTemporaryMode { get; set; } = false;
|
||||||
public bool EnableCustomShapes { get; set; } = true;
|
public bool EnableCustomShapes { get; set; } = true;
|
||||||
public bool DisablePcpHandling { get; set; } = false;
|
public PcpSettings PcpSettings = new();
|
||||||
public bool AllowPcpIpc { get; set; } = true;
|
public RenameField ShowRename { get; set; } = RenameField.BothDataPrio;
|
||||||
public RenameField ShowRename { get; set; } = RenameField.BothDataPrio;
|
public ChangedItemMode ChangedItemDisplay { get; set; } = ChangedItemMode.GroupedCollapsed;
|
||||||
public ChangedItemMode ChangedItemDisplay { get; set; } = ChangedItemMode.GroupedCollapsed;
|
public int OptionGroupCollapsibleMin { get; set; } = 5;
|
||||||
public int OptionGroupCollapsibleMin { get; set; } = 5;
|
|
||||||
|
|
||||||
public Vector2 MinimumSize = new(Constants.MinimumSizeX, Constants.MinimumSizeY);
|
public Vector2 MinimumSize = new(Constants.MinimumSizeX, Constants.MinimumSizeY);
|
||||||
|
|
||||||
|
|
@ -90,7 +98,6 @@ public class Configuration : IPluginConfiguration, ISavable, IService
|
||||||
public bool OpenFoldersByDefault { get; set; } = false;
|
public bool OpenFoldersByDefault { get; set; } = false;
|
||||||
public int SingleGroupRadioMax { get; set; } = 2;
|
public int SingleGroupRadioMax { get; set; } = 2;
|
||||||
public string DefaultImportFolder { get; set; } = string.Empty;
|
public string DefaultImportFolder { get; set; } = string.Empty;
|
||||||
public string PcpFolderName { get; set; } = "PCP";
|
|
||||||
public string QuickMoveFolder1 { get; set; } = string.Empty;
|
public string QuickMoveFolder1 { get; set; } = string.Empty;
|
||||||
public string QuickMoveFolder2 { get; set; } = string.Empty;
|
public string QuickMoveFolder2 { get; set; } = string.Empty;
|
||||||
public string QuickMoveFolder3 { get; set; } = string.Empty;
|
public string QuickMoveFolder3 { get; set; } = string.Empty;
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ public class PcpService : IApiService, IDisposable
|
||||||
|
|
||||||
private void OnModPathChange(ModPathChangeType type, Mod mod, DirectoryInfo? oldDirectory, DirectoryInfo? newDirectory)
|
private void OnModPathChange(ModPathChangeType type, Mod mod, DirectoryInfo? oldDirectory, DirectoryInfo? newDirectory)
|
||||||
{
|
{
|
||||||
if (type is not ModPathChangeType.Added || _config.DisablePcpHandling || newDirectory is null)
|
if (type is not ModPathChangeType.Added || _config.PcpSettings.DisableHandling || newDirectory is null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
try
|
try
|
||||||
|
|
@ -107,29 +107,37 @@ public class PcpService : IApiService, IDisposable
|
||||||
}
|
}
|
||||||
|
|
||||||
Penumbra.Log.Information($"[PCPService] Found a PCP file for {mod.Name}, applying.");
|
Penumbra.Log.Information($"[PCPService] Found a PCP file for {mod.Name}, applying.");
|
||||||
var text = File.ReadAllText(file);
|
var text = File.ReadAllText(file);
|
||||||
var jObj = JObject.Parse(text);
|
var jObj = JObject.Parse(text);
|
||||||
var identifier = _actors.FromJson(jObj["Actor"] as JObject);
|
var collection = ModCollection.Empty;
|
||||||
if (!identifier.IsValid)
|
// Create collection.
|
||||||
return;
|
if (_config.PcpSettings.CreateCollection)
|
||||||
|
{
|
||||||
|
var identifier = _actors.FromJson(jObj["Actor"] as JObject);
|
||||||
|
if (identifier.IsValid && jObj["Collection"]?.ToObject<string>() is { } collectionName)
|
||||||
|
{
|
||||||
|
var name = $"PCP/{collectionName}";
|
||||||
|
if (_collections.Storage.AddCollection(name, null))
|
||||||
|
{
|
||||||
|
collection = _collections.Storage[^1];
|
||||||
|
_collections.Editor.SetModState(collection, mod, true);
|
||||||
|
|
||||||
if (jObj["Collection"]?.ToObject<string>() is not { } collectionName)
|
// Assign collection.
|
||||||
return;
|
if (_config.PcpSettings.AssignCollection)
|
||||||
|
{
|
||||||
|
var identifierGroup = _collections.Active.Individuals.GetGroup(identifier);
|
||||||
|
_collections.Active.SetCollection(collection, CollectionType.Individual, identifierGroup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var name = $"PCP/{collectionName}";
|
// Move to folder.
|
||||||
if (!_collections.Storage.AddCollection(name, null))
|
|
||||||
return;
|
|
||||||
|
|
||||||
var collection = _collections.Storage[^1];
|
|
||||||
_collections.Editor.SetModState(collection, mod, true);
|
|
||||||
|
|
||||||
var identifierGroup = _collections.Active.Individuals.GetGroup(identifier);
|
|
||||||
_collections.Active.SetCollection(collection, CollectionType.Individual, identifierGroup);
|
|
||||||
if (_fileSystem.TryGetValue(mod, out var leaf))
|
if (_fileSystem.TryGetValue(mod, out var leaf))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var folder = _fileSystem.FindOrCreateAllFolders(_config.PcpFolderName);
|
var folder = _fileSystem.FindOrCreateAllFolders(_config.PcpSettings.FolderName);
|
||||||
_fileSystem.Move(leaf, folder);
|
_fileSystem.Move(leaf, folder);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
|
|
@ -138,7 +146,8 @@ public class PcpService : IApiService, IDisposable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_config.AllowPcpIpc)
|
// Invoke IPC.
|
||||||
|
if (_config.PcpSettings.AllowIpc)
|
||||||
_communicator.PcpParsing.Invoke(jObj, mod.Identifier, collection.Identity.Id);
|
_communicator.PcpParsing.Invoke(jObj, mod.Identifier, collection.Identity.Id);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|
@ -208,8 +217,8 @@ public class PcpService : IApiService, IDisposable
|
||||||
};
|
};
|
||||||
if (note.Length > 0)
|
if (note.Length > 0)
|
||||||
cancel.ThrowIfCancellationRequested();
|
cancel.ThrowIfCancellationRequested();
|
||||||
if (_config.AllowPcpIpc)
|
if (_config.PcpSettings.AllowIpc)
|
||||||
await _framework.Framework.RunOnFrameworkThread(() => _communicator.PcpCreation.Invoke(jObj, index.Index));
|
await _framework.Framework.RunOnFrameworkThread(() => _communicator.PcpCreation.Invoke(jObj, index.Index, directory.FullName));
|
||||||
var filePath = Path.Combine(directory.FullName, "character.json");
|
var filePath = Path.Combine(directory.FullName, "character.json");
|
||||||
await using var file = File.Open(filePath, File.Exists(filePath) ? FileMode.Truncate : FileMode.CreateNew);
|
await using var file = File.Open(filePath, File.Exists(filePath) ? FileMode.Truncate : FileMode.CreateNew);
|
||||||
await using var stream = new StreamWriter(file);
|
await using var stream = new StreamWriter(file);
|
||||||
|
|
|
||||||
|
|
@ -602,7 +602,7 @@ public class SettingsTab : ITab, IUiService
|
||||||
_config.AlwaysOpenDefaultImport, v => _config.AlwaysOpenDefaultImport = v);
|
_config.AlwaysOpenDefaultImport, v => _config.AlwaysOpenDefaultImport = v);
|
||||||
Checkbox("Handle PCP Files",
|
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.",
|
"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);
|
!_config.PcpSettings.DisableHandling, v => _config.PcpSettings.DisableHandling = !v);
|
||||||
|
|
||||||
var active = _config.DeleteModModifier.IsActive();
|
var active = _config.DeleteModModifier.IsActive();
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
|
|
@ -612,14 +612,23 @@ public class SettingsTab : ITab, IUiService
|
||||||
ImUtf8.HoverTooltip(ImGuiHoveredFlags.AllowWhenDisabled, $"Hold {_config.DeleteModModifier} while clicking.");
|
ImUtf8.HoverTooltip(ImGuiHoveredFlags.AllowWhenDisabled, $"Hold {_config.DeleteModModifier} while clicking.");
|
||||||
|
|
||||||
ImGui.SameLine();
|
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))
|
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();
|
_pcpService.CleanPcpCollections();
|
||||||
if (!active)
|
if (!active)
|
||||||
ImUtf8.HoverTooltip(ImGuiHoveredFlags.AllowWhenDisabled, $"Hold {_config.DeleteModModifier} while clicking.");
|
ImUtf8.HoverTooltip(ImGuiHoveredFlags.AllowWhenDisabled, $"Hold {_config.DeleteModModifier} while clicking.");
|
||||||
|
|
||||||
Checkbox("Allow Other Plugins Access to PCP Handling",
|
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.",
|
"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);
|
_config.PcpSettings.AllowIpc, v => _config.PcpSettings.AllowIpc = v);
|
||||||
|
|
||||||
|
Checkbox("Create PCP Collections",
|
||||||
|
"When importing PCP files, create the associated collection.",
|
||||||
|
_config.PcpSettings.CreateCollection, v => _config.PcpSettings.CreateCollection = v);
|
||||||
|
|
||||||
|
Checkbox("Assign PCP Collections",
|
||||||
|
"When importing PCP files and creating the associated collection, assign it to the associated character.",
|
||||||
|
_config.PcpSettings.AssignCollection, v => _config.PcpSettings.AssignCollection = v);
|
||||||
DrawDefaultModImportPath();
|
DrawDefaultModImportPath();
|
||||||
DrawDefaultModAuthor();
|
DrawDefaultModAuthor();
|
||||||
DrawDefaultModImportFolder();
|
DrawDefaultModImportFolder();
|
||||||
|
|
@ -736,10 +745,10 @@ public class SettingsTab : ITab, IUiService
|
||||||
/// <summary> Draw input for the default folder to sort put newly imported mods into. </summary>
|
/// <summary> Draw input for the default folder to sort put newly imported mods into. </summary>
|
||||||
private void DrawPcpFolder()
|
private void DrawPcpFolder()
|
||||||
{
|
{
|
||||||
var tmp = _config.PcpFolderName;
|
var tmp = _config.PcpSettings.FolderName;
|
||||||
ImGui.SetNextItemWidth(UiHelpers.InputTextWidth.X);
|
ImGui.SetNextItemWidth(UiHelpers.InputTextWidth.X);
|
||||||
if (ImUtf8.InputText("##pcpFolder"u8, ref tmp))
|
if (ImUtf8.InputText("##pcpFolder"u8, ref tmp))
|
||||||
_config.PcpFolderName = tmp;
|
_config.PcpSettings.FolderName = tmp;
|
||||||
|
|
||||||
if (ImGui.IsItemDeactivatedAfterEdit())
|
if (ImGui.IsItemDeactivatedAfterEdit())
|
||||||
_config.Save();
|
_config.Save();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue