mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 10:17:22 +01:00
Compare commits
No commits in common. "d79e6871621eb6781958bfd3e774803e03756b99" and "34f067f13d68eb310fce111e39d94a2bb131d5a9" have entirely different histories.
d79e687162
...
34f067f13d
15 changed files with 94 additions and 421 deletions
2
Luna
2
Luna
|
|
@ -1 +1 @@
|
||||||
Subproject commit c764db88097c88cd49f2bed4f60268d617f97fdb
|
Subproject commit 78216203f4570a6194fce9422204d8abb536c828
|
||||||
2
OtterGui
2
OtterGui
|
|
@ -1 +1 @@
|
||||||
Subproject commit a63f6735cf4bed4f7502a022a10378607082b770
|
Subproject commit 9af1e5fce4c13ef98842807d4f593dec8ae80c87
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit c23ee05c1e9fa103eaa52e6aa7e855ef568ee669
|
Subproject commit 97fe622e4ec0a5469a26aba8a8c3933fa8ef7fd6
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit cf3d868eeeb4ea3ea728ae15a8d09ec127ce80e9
|
Subproject commit 182cca56a49411430233d73d7a8a6bb3d983f8f0
|
||||||
|
|
@ -51,7 +51,6 @@ public class Configuration : IPluginConfiguration, ISavable, IService
|
||||||
|
|
||||||
public string ModDirectory { get; set; } = string.Empty;
|
public string ModDirectory { get; set; } = string.Empty;
|
||||||
public string ExportDirectory { get; set; } = string.Empty;
|
public string ExportDirectory { get; set; } = string.Empty;
|
||||||
public string WatchDirectory { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
public bool? UseCrashHandler { get; set; } = null;
|
public bool? UseCrashHandler { get; set; } = null;
|
||||||
public bool OpenWindowAtStart { get; set; } = false;
|
public bool OpenWindowAtStart { get; set; } = false;
|
||||||
|
|
@ -75,8 +74,6 @@ public class Configuration : IPluginConfiguration, ISavable, IService
|
||||||
public bool HideRedrawBar { get; set; } = false;
|
public bool HideRedrawBar { get; set; } = false;
|
||||||
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 EnableDirectoryWatch { get; set; } = false;
|
|
||||||
public bool EnableAutomaticModImport { get; set; } = false;
|
|
||||||
public bool EnableCustomShapes { get; set; } = true;
|
public bool EnableCustomShapes { get; set; } = true;
|
||||||
public PcpSettings PcpSettings = new();
|
public PcpSettings PcpSettings = new();
|
||||||
public RenameField ShowRename { get; set; } = RenameField.BothDataPrio;
|
public RenameField ShowRename { get; set; } = RenameField.BothDataPrio;
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ public class EphemeralConfig : ISavable, IDisposable, IService
|
||||||
public ChangedItemIconFlag ChangedItemFilter { get; set; } = ChangedItemFlagExtensions.DefaultFlags;
|
public ChangedItemIconFlag ChangedItemFilter { get; set; } = ChangedItemFlagExtensions.DefaultFlags;
|
||||||
public bool FixMainWindow { get; set; } = false;
|
public bool FixMainWindow { get; set; } = false;
|
||||||
public string LastModPath { get; set; } = string.Empty;
|
public string LastModPath { get; set; } = string.Empty;
|
||||||
public HashSet<string> AdvancedEditingOpenForModPaths { get; set; } = [];
|
public bool AdvancedEditingOpen { get; set; } = false;
|
||||||
public bool ForceRedrawOnFileChange { get; set; } = false;
|
public bool ForceRedrawOnFileChange { get; set; } = false;
|
||||||
public bool IncognitoMode { get; set; } = false;
|
public bool IncognitoMode { get; set; } = false;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,6 @@ public sealed class CutsceneService : Luna.IRequiredService, IDisposable
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
_copiedCharacters[copyIdx - CutsceneStartIdx] = (short)parentIdx;
|
_copiedCharacters[copyIdx - CutsceneStartIdx] = (short)parentIdx;
|
||||||
_objects.InvokeRequiredUpdates();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,24 +32,12 @@ public class ModStorage : IReadOnlyList<Mod>
|
||||||
IEnumerator IEnumerable.GetEnumerator()
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
=> GetEnumerator();
|
=> GetEnumerator();
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Try to obtain a mod by its directory name (unique identifier).
|
|
||||||
/// </summary>
|
|
||||||
public bool TryGetMod(string identifier, [NotNullWhen(true)] out Mod? mod)
|
|
||||||
{
|
|
||||||
mod = this.FirstOrDefault(m => string.Equals(m.Identifier, identifier, StringComparison.OrdinalIgnoreCase));
|
|
||||||
return mod is not null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Try to obtain a mod by its directory name (unique identifier, preferred),
|
/// Try to obtain a mod by its directory name (unique identifier, preferred),
|
||||||
/// or the first mod of the given name if no directory fits.
|
/// or the first mod of the given name if no directory fits.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool TryGetMod(string identifier, string modName, [NotNullWhen(true)] out Mod? mod)
|
public bool TryGetMod(string identifier, string modName, [NotNullWhen(true)] out Mod? mod)
|
||||||
{
|
{
|
||||||
if (modName.Length is 0)
|
|
||||||
return TryGetMod(identifier, out mod);
|
|
||||||
|
|
||||||
mod = null;
|
mod = null;
|
||||||
foreach (var m in Mods)
|
foreach (var m in Mods)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -27,8 +27,8 @@ public class ModSelection : EventBase<ModSelection.Arguments, ModSelection.Prior
|
||||||
_communicator = communicator;
|
_communicator = communicator;
|
||||||
_collections = collections;
|
_collections = collections;
|
||||||
_config = config;
|
_config = config;
|
||||||
if (_config.LastModPath.Length > 0 && mods.TryGetMod(config.LastModPath, out var mod))
|
if (_config.LastModPath.Length > 0)
|
||||||
SelectMod(mod);
|
SelectMod(mods.FirstOrDefault(m => string.Equals(m.Identifier, config.LastModPath, StringComparison.OrdinalIgnoreCase)));
|
||||||
|
|
||||||
_communicator.CollectionChange.Subscribe(OnCollectionChange, CollectionChange.Priority.ModSelection);
|
_communicator.CollectionChange.Subscribe(OnCollectionChange, CollectionChange.Priority.ModSelection);
|
||||||
_communicator.CollectionInheritanceChanged.Subscribe(OnInheritanceChange, CollectionInheritanceChanged.Priority.ModSelection);
|
_communicator.CollectionInheritanceChanged.Subscribe(OnInheritanceChange, CollectionInheritanceChanged.Priority.ModSelection);
|
||||||
|
|
|
||||||
|
|
@ -141,14 +141,8 @@ public class Penumbra : IDalamudPlugin
|
||||||
if (!_disposed)
|
if (!_disposed)
|
||||||
{
|
{
|
||||||
_windowSystem = system;
|
_windowSystem = system;
|
||||||
if (_config is { OpenWindowAtStart: true, Ephemeral.AdvancedEditingOpenForModPaths.Count: > 0 })
|
if (_config is { OpenWindowAtStart: true, Ephemeral.AdvancedEditingOpen: true } && _services.GetService<ModSelection>().Mod is {} mod)
|
||||||
{
|
_services.GetService<ModEditWindowFactory>().OpenForMod(mod);
|
||||||
var mods = _services.GetService<ModManager>();
|
|
||||||
var editWindowFactory = _services.GetService<ModEditWindowFactory>();
|
|
||||||
foreach (var identifier in _config.Ephemeral.AdvancedEditingOpenForModPaths)
|
|
||||||
if (mods.TryGetMod(identifier, out var mod))
|
|
||||||
editWindowFactory.OpenForMod(mod);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
system.Dispose();
|
system.Dispose();
|
||||||
|
|
|
||||||
|
|
@ -1,209 +0,0 @@
|
||||||
using Luna;
|
|
||||||
using Penumbra.Mods.Manager;
|
|
||||||
|
|
||||||
namespace Penumbra.Services;
|
|
||||||
|
|
||||||
public class FileWatcher : IDisposable, IService
|
|
||||||
{
|
|
||||||
private readonly ConcurrentSet<string> _pending = new(StringComparer.OrdinalIgnoreCase);
|
|
||||||
private readonly ModImportManager _modImportManager;
|
|
||||||
private readonly MessageService _messageService;
|
|
||||||
private readonly Configuration _config;
|
|
||||||
|
|
||||||
private bool _pausedConsumer;
|
|
||||||
private FileSystemWatcher? _fsw;
|
|
||||||
private CancellationTokenSource? _cts = new();
|
|
||||||
private Task? _consumer;
|
|
||||||
|
|
||||||
public FileWatcher(ModImportManager modImportManager, MessageService messageService, Configuration config)
|
|
||||||
{
|
|
||||||
_modImportManager = modImportManager;
|
|
||||||
_messageService = messageService;
|
|
||||||
_config = config;
|
|
||||||
|
|
||||||
if (_config.EnableDirectoryWatch)
|
|
||||||
{
|
|
||||||
SetupFileWatcher(_config.WatchDirectory);
|
|
||||||
SetupConsumerTask();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Toggle(bool value)
|
|
||||||
{
|
|
||||||
if (_config.EnableDirectoryWatch == value)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_config.EnableDirectoryWatch = value;
|
|
||||||
_config.Save();
|
|
||||||
if (value)
|
|
||||||
{
|
|
||||||
SetupFileWatcher(_config.WatchDirectory);
|
|
||||||
SetupConsumerTask();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
EndFileWatcher();
|
|
||||||
EndConsumerTask();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void PauseConsumer(bool pause)
|
|
||||||
=> _pausedConsumer = pause;
|
|
||||||
|
|
||||||
private void EndFileWatcher()
|
|
||||||
{
|
|
||||||
if (_fsw is null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_fsw.Dispose();
|
|
||||||
_fsw = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetupFileWatcher(string directory)
|
|
||||||
{
|
|
||||||
EndFileWatcher();
|
|
||||||
_fsw = new FileSystemWatcher
|
|
||||||
{
|
|
||||||
IncludeSubdirectories = false,
|
|
||||||
NotifyFilter = NotifyFilters.FileName | NotifyFilters.CreationTime,
|
|
||||||
InternalBufferSize = 32 * 1024,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Only wake us for the exact patterns we care about
|
|
||||||
_fsw.Filters.Add("*.pmp");
|
|
||||||
_fsw.Filters.Add("*.pcp");
|
|
||||||
_fsw.Filters.Add("*.ttmp");
|
|
||||||
_fsw.Filters.Add("*.ttmp2");
|
|
||||||
|
|
||||||
_fsw.Created += OnPath;
|
|
||||||
_fsw.Renamed += OnPath;
|
|
||||||
UpdateDirectory(directory);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void EndConsumerTask()
|
|
||||||
{
|
|
||||||
if (_cts is not null)
|
|
||||||
{
|
|
||||||
_cts.Cancel();
|
|
||||||
_cts = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
_consumer = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetupConsumerTask()
|
|
||||||
{
|
|
||||||
EndConsumerTask();
|
|
||||||
_cts = new CancellationTokenSource();
|
|
||||||
_consumer = Task.Factory.StartNew(
|
|
||||||
() => ConsumerLoopAsync(_cts.Token),
|
|
||||||
_cts.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default).Unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UpdateDirectory(string newPath)
|
|
||||||
{
|
|
||||||
if (_config.WatchDirectory != newPath)
|
|
||||||
{
|
|
||||||
_config.WatchDirectory = newPath;
|
|
||||||
_config.Save();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_fsw is null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_fsw.EnableRaisingEvents = false;
|
|
||||||
if (!Directory.Exists(newPath) || newPath.Length is 0)
|
|
||||||
{
|
|
||||||
_fsw.Path = string.Empty;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_fsw.Path = newPath;
|
|
||||||
_fsw.EnableRaisingEvents = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnPath(object? sender, FileSystemEventArgs e)
|
|
||||||
=> _pending.TryAdd(e.FullPath);
|
|
||||||
|
|
||||||
private async Task ConsumerLoopAsync(CancellationToken token)
|
|
||||||
{
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
var path = _pending.FirstOrDefault<string>();
|
|
||||||
if (path is null || _pausedConsumer)
|
|
||||||
{
|
|
||||||
await Task.Delay(500, token).ConfigureAwait(false);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await ProcessOneAsync(path, token).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
catch (OperationCanceledException)
|
|
||||||
{
|
|
||||||
Penumbra.Log.Debug("[FileWatcher] Canceled via Token.");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Penumbra.Log.Warning($"[FileWatcher] Error during Processing: {ex}");
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
_pending.TryRemove(path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task ProcessOneAsync(string path, CancellationToken token)
|
|
||||||
{
|
|
||||||
// Downloads often finish via rename; file may be locked briefly.
|
|
||||||
// Wait until it exists and is readable; also require two stable size checks.
|
|
||||||
const int maxTries = 40;
|
|
||||||
long lastLen = -1;
|
|
||||||
|
|
||||||
for (var i = 0; i < maxTries && !token.IsCancellationRequested; i++)
|
|
||||||
{
|
|
||||||
if (!File.Exists(path))
|
|
||||||
{
|
|
||||||
await Task.Delay(100, token);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var fi = new FileInfo(path);
|
|
||||||
var len = fi.Length;
|
|
||||||
if (len > 0 && len == lastLen)
|
|
||||||
{
|
|
||||||
if (_config.EnableAutomaticModImport)
|
|
||||||
_modImportManager.AddUnpack(path);
|
|
||||||
else
|
|
||||||
_messageService.AddMessage(new InstallNotification(_modImportManager, path), false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
lastLen = len;
|
|
||||||
}
|
|
||||||
catch (IOException)
|
|
||||||
{
|
|
||||||
Penumbra.Log.Debug($"[FileWatcher] File is still being written to.");
|
|
||||||
}
|
|
||||||
catch (UnauthorizedAccessException)
|
|
||||||
{
|
|
||||||
Penumbra.Log.Debug($"[FileWatcher] File is locked.");
|
|
||||||
}
|
|
||||||
|
|
||||||
await Task.Delay(150, token);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
EndConsumerTask();
|
|
||||||
EndFileWatcher();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,49 +0,0 @@
|
||||||
using Dalamud.Bindings.ImGui;
|
|
||||||
using Dalamud.Game.Text.SeStringHandling;
|
|
||||||
using Dalamud.Interface.ImGuiNotification;
|
|
||||||
using Dalamud.Interface.ImGuiNotification.EventArgs;
|
|
||||||
using ImSharp;
|
|
||||||
using Penumbra.Mods.Manager;
|
|
||||||
|
|
||||||
namespace Penumbra.Services;
|
|
||||||
|
|
||||||
public class InstallNotification(ModImportManager modImportManager, string filePath) : Luna.IMessage
|
|
||||||
{
|
|
||||||
public NotificationType NotificationType
|
|
||||||
=> NotificationType.Info;
|
|
||||||
|
|
||||||
public string NotificationMessage
|
|
||||||
=> "A new mod has been found!";
|
|
||||||
|
|
||||||
public TimeSpan NotificationDuration
|
|
||||||
=> TimeSpan.MaxValue;
|
|
||||||
|
|
||||||
public string NotificationTitle { get; } = Path.GetFileNameWithoutExtension(filePath);
|
|
||||||
|
|
||||||
public string LogMessage
|
|
||||||
=> $"A new mod has been found: {Path.GetFileName(filePath)}";
|
|
||||||
|
|
||||||
public SeString ChatMessage
|
|
||||||
=> SeString.Empty;
|
|
||||||
|
|
||||||
public StringU8 StoredMessage
|
|
||||||
=> StringU8.Empty;
|
|
||||||
|
|
||||||
public StringU8 StoredTooltip
|
|
||||||
=> StringU8.Empty;
|
|
||||||
|
|
||||||
public void OnNotificationActions(INotificationDrawArgs args)
|
|
||||||
{
|
|
||||||
var region = Im.ContentRegion.Available;
|
|
||||||
var buttonSize = new Vector2((region.X - Im.Style.ItemSpacing.X) / 2, 0);
|
|
||||||
if (Im.Button("Install"u8, buttonSize))
|
|
||||||
{
|
|
||||||
modImportManager.AddUnpack(filePath);
|
|
||||||
args.Notification.DismissNow();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui.SameLine();
|
|
||||||
if (Im.Button("Ignore"u8, buttonSize))
|
|
||||||
args.Notification.DismissNow();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -180,7 +180,7 @@ public partial class ModEditWindow : IndexedWindow, IDisposable
|
||||||
public override void OnClose()
|
public override void OnClose()
|
||||||
{
|
{
|
||||||
base.OnClose();
|
base.OnClose();
|
||||||
if (Mod is not null && _config.Ephemeral.AdvancedEditingOpenForModPaths.Remove(Mod.Identifier))
|
_config.Ephemeral.AdvancedEditingOpen = false;
|
||||||
_config.Ephemeral.Save();
|
_config.Ephemeral.Save();
|
||||||
AppendTask(() =>
|
AppendTask(() =>
|
||||||
{
|
{
|
||||||
|
|
@ -194,8 +194,11 @@ public partial class ModEditWindow : IndexedWindow, IDisposable
|
||||||
|
|
||||||
public override void Draw()
|
public override void Draw()
|
||||||
{
|
{
|
||||||
if (Mod is not null && _config.Ephemeral.AdvancedEditingOpenForModPaths.Add(Mod.Identifier))
|
if (!_config.Ephemeral.AdvancedEditingOpen)
|
||||||
|
{
|
||||||
|
_config.Ephemeral.AdvancedEditingOpen = true;
|
||||||
_config.Ephemeral.Save();
|
_config.Ephemeral.Save();
|
||||||
|
}
|
||||||
|
|
||||||
if (IsLoading)
|
if (IsLoading)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,6 @@ public class SettingsTab : ITab, IUiService
|
||||||
private readonly Penumbra _penumbra;
|
private readonly Penumbra _penumbra;
|
||||||
private readonly FileDialogService _fileDialog;
|
private readonly FileDialogService _fileDialog;
|
||||||
private readonly ModManager _modManager;
|
private readonly ModManager _modManager;
|
||||||
private readonly FileWatcher _fileWatcher;
|
|
||||||
private readonly ModExportManager _modExportManager;
|
private readonly ModExportManager _modExportManager;
|
||||||
private readonly ModFileSystemSelector _selector;
|
private readonly ModFileSystemSelector _selector;
|
||||||
private readonly CharacterUtility _characterUtility;
|
private readonly CharacterUtility _characterUtility;
|
||||||
|
|
@ -65,8 +64,7 @@ public class SettingsTab : ITab, IUiService
|
||||||
|
|
||||||
public SettingsTab(IDalamudPluginInterface pluginInterface, Configuration config, FontReloader fontReloader, TutorialService tutorial,
|
public SettingsTab(IDalamudPluginInterface pluginInterface, Configuration config, FontReloader fontReloader, TutorialService tutorial,
|
||||||
Penumbra penumbra, FileDialogService fileDialog, ModManager modManager, ModFileSystemSelector selector,
|
Penumbra penumbra, FileDialogService fileDialog, ModManager modManager, ModFileSystemSelector selector,
|
||||||
CharacterUtility characterUtility, ResidentResourceManager residentResources, ModExportManager modExportManager,
|
CharacterUtility characterUtility, ResidentResourceManager residentResources, ModExportManager modExportManager, HttpApi httpApi,
|
||||||
FileWatcher fileWatcher, HttpApi httpApi,
|
|
||||||
DalamudSubstitutionProvider dalamudSubstitutionProvider, FileCompactor compactor, DalamudConfigService dalamudConfig,
|
DalamudSubstitutionProvider dalamudSubstitutionProvider, FileCompactor compactor, DalamudConfigService dalamudConfig,
|
||||||
IDataManager gameData, PredefinedTagManager predefinedTagConfig, CrashHandlerService crashService,
|
IDataManager gameData, PredefinedTagManager predefinedTagConfig, CrashHandlerService crashService,
|
||||||
MigrationSectionDrawer migrationDrawer, CollectionAutoSelector autoSelector, CleanupService cleanupService,
|
MigrationSectionDrawer migrationDrawer, CollectionAutoSelector autoSelector, CleanupService cleanupService,
|
||||||
|
|
@ -83,7 +81,6 @@ public class SettingsTab : ITab, IUiService
|
||||||
_characterUtility = characterUtility;
|
_characterUtility = characterUtility;
|
||||||
_residentResources = residentResources;
|
_residentResources = residentResources;
|
||||||
_modExportManager = modExportManager;
|
_modExportManager = modExportManager;
|
||||||
_fileWatcher = fileWatcher;
|
|
||||||
_httpApi = httpApi;
|
_httpApi = httpApi;
|
||||||
_dalamudSubstitutionProvider = dalamudSubstitutionProvider;
|
_dalamudSubstitutionProvider = dalamudSubstitutionProvider;
|
||||||
_compactor = compactor;
|
_compactor = compactor;
|
||||||
|
|
@ -725,13 +722,6 @@ public class SettingsTab : ITab, IUiService
|
||||||
DrawPcpFolder();
|
DrawPcpFolder();
|
||||||
DrawPcpExtension();
|
DrawPcpExtension();
|
||||||
DrawDefaultModExportPath();
|
DrawDefaultModExportPath();
|
||||||
Checkbox("Enable Directory Watcher",
|
|
||||||
"Enables a File Watcher that automatically listens for Mod files that enter a specified directory, causing Penumbra to open a popup to import these mods.",
|
|
||||||
_config.EnableDirectoryWatch, _fileWatcher.Toggle);
|
|
||||||
Checkbox("Enable Fully Automatic Import",
|
|
||||||
"Uses the File Watcher in order to skip the query popup and automatically import any new mods.",
|
|
||||||
_config.EnableAutomaticModImport, v => _config.EnableAutomaticModImport = v);
|
|
||||||
DrawFileWatcherPath();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -811,46 +801,6 @@ public class SettingsTab : ITab, IUiService
|
||||||
+ "Keep this empty to use the root directory.");
|
+ "Keep this empty to use the root directory.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private string? _tempWatchDirectory;
|
|
||||||
|
|
||||||
/// <summary> Draw input for the Automatic Mod import path. </summary>
|
|
||||||
private void DrawFileWatcherPath()
|
|
||||||
{
|
|
||||||
var tmp = _tempWatchDirectory ?? _config.WatchDirectory;
|
|
||||||
var spacing = new Vector2(UiHelpers.ScaleX3);
|
|
||||||
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, spacing);
|
|
||||||
ImGui.SetNextItemWidth(UiHelpers.InputTextMinusButton3);
|
|
||||||
if (ImGui.InputText("##fileWatchPath", ref tmp, 256))
|
|
||||||
_tempWatchDirectory = tmp;
|
|
||||||
|
|
||||||
if (ImGui.IsItemDeactivated() && _tempWatchDirectory is not null)
|
|
||||||
{
|
|
||||||
if (ImGui.IsItemDeactivatedAfterEdit())
|
|
||||||
_fileWatcher.UpdateDirectory(_tempWatchDirectory);
|
|
||||||
_tempWatchDirectory = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui.SameLine();
|
|
||||||
if (ImGuiUtil.DrawDisabledButton($"{FontAwesomeIcon.Folder.ToIconString()}##fileWatch", UiHelpers.IconButtonSize,
|
|
||||||
"Select a directory via dialog.", false, true))
|
|
||||||
{
|
|
||||||
var startDir = _config.WatchDirectory.Length > 0 && Directory.Exists(_config.WatchDirectory)
|
|
||||||
? _config.WatchDirectory
|
|
||||||
: Directory.Exists(_config.ModDirectory)
|
|
||||||
? _config.ModDirectory
|
|
||||||
: null;
|
|
||||||
_fileDialog.OpenFolderPicker("Choose Automatic Import Directory", (b, s) =>
|
|
||||||
{
|
|
||||||
if (b)
|
|
||||||
_fileWatcher.UpdateDirectory(s);
|
|
||||||
}, startDir, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
style.Pop();
|
|
||||||
ImGuiUtil.LabeledHelpMarker("Automatic Import Director",
|
|
||||||
"Choose the Directory the File Watcher listens to.");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary> Draw input for the default name to input as author into newly generated mods. </summary>
|
/// <summary> Draw input for the default name to input as author into newly generated mods. </summary>
|
||||||
private void DrawDefaultModAuthor()
|
private void DrawDefaultModAuthor()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
"Description": "Runtime mod loader and manager.",
|
"Description": "Runtime mod loader and manager.",
|
||||||
"InternalName": "Penumbra",
|
"InternalName": "Penumbra",
|
||||||
"AssemblyVersion": "1.5.1.6",
|
"AssemblyVersion": "1.5.1.6",
|
||||||
"TestingAssemblyVersion": "1.5.1.7",
|
"TestingAssemblyVersion": "1.5.1.6",
|
||||||
"RepoUrl": "https://github.com/xivdev/Penumbra",
|
"RepoUrl": "https://github.com/xivdev/Penumbra",
|
||||||
"ApplicableVersion": "any",
|
"ApplicableVersion": "any",
|
||||||
"DalamudApiLevel": 13,
|
"DalamudApiLevel": 13,
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
"LoadRequiredState": 2,
|
"LoadRequiredState": 2,
|
||||||
"LoadSync": true,
|
"LoadSync": true,
|
||||||
"DownloadLinkInstall": "https://github.com/xivdev/Penumbra/releases/download/1.5.1.6/Penumbra.zip",
|
"DownloadLinkInstall": "https://github.com/xivdev/Penumbra/releases/download/1.5.1.6/Penumbra.zip",
|
||||||
"DownloadLinkTesting": "https://github.com/xivdev/Penumbra/releases/download/testing_1.5.1.7/Penumbra.zip",
|
"DownloadLinkTesting": "https://github.com/xivdev/Penumbra/releases/download/1.5.1.6/Penumbra.zip",
|
||||||
"DownloadLinkUpdate": "https://github.com/xivdev/Penumbra/releases/download/1.5.1.6/Penumbra.zip",
|
"DownloadLinkUpdate": "https://github.com/xivdev/Penumbra/releases/download/1.5.1.6/Penumbra.zip",
|
||||||
"IconUrl": "https://raw.githubusercontent.com/xivdev/Penumbra/master/images/icon.png"
|
"IconUrl": "https://raw.githubusercontent.com/xivdev/Penumbra/master/images/icon.png"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue