mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-18 06:34:19 +01:00
Compare commits
No commits in common. "master" and "1.5.1.6" have entirely different histories.
24 changed files with 57 additions and 363 deletions
2
OtterGui
2
OtterGui
|
|
@ -1 +1 @@
|
||||||
Subproject commit 6f3236453b1edfaa25c8edcc8b39a9d9b2fc18ac
|
Subproject commit f354444776591ae423e2d8374aae346308d81424
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit e4934ccca0379f22dadf989ab2d34f30b3c5c7ea
|
Subproject commit dd14131793e5ae47cc8e9232f46469216017b5aa
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<Project Sdk="Dalamud.NET.Sdk/14.0.0">
|
<Project Sdk="Dalamud.NET.Sdk/13.1.0">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
{
|
{
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"net10.0-windows7.0": {
|
"net9.0-windows7.0": {
|
||||||
"DotNet.ReproducibleBuilds": {
|
"DotNet.ReproducibleBuilds": {
|
||||||
"type": "Direct",
|
"type": "Direct",
|
||||||
"requested": "[1.2.39, )",
|
"requested": "[1.2.25, )",
|
||||||
"resolved": "1.2.39",
|
"resolved": "1.2.25",
|
||||||
"contentHash": "fcFN01tDTIQqDuTwr1jUQK/geofiwjG5DycJQOnC72i1SsLAk1ELe+apBOuZ11UMQG8YKFZG1FgvjZPbqHyatg=="
|
"contentHash": "xCXiw7BCxHJ8pF6wPepRUddlh2dlQlbr81gXA72hdk4FLHkKXas7EH/n+fk5UCA/YfMqG1Z6XaPiUjDbUNBUzg=="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit 2ff50e68f7c951f0f8b25957a400a2e32ed9d6dc
|
Subproject commit 3baace73c828271dcb71a8156e3e7b91e1dd12ae
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit 0315144ab5614c11911e2a4dddf436fb18c5d7e3
|
Subproject commit c8611a0c546b6b2ec29214ab319fc2c38fe74793
|
||||||
|
|
@ -17,7 +17,7 @@ public class PenumbraApi(
|
||||||
UiApi ui) : IDisposable, IApiService, IPenumbraApi
|
UiApi ui) : IDisposable, IApiService, IPenumbraApi
|
||||||
{
|
{
|
||||||
public const int BreakingVersion = 5;
|
public const int BreakingVersion = 5;
|
||||||
public const int FeatureVersion = 13;
|
public const int FeatureVersion = 12;
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,11 @@ using Dalamud.Game.ClientState.Objects.Types;
|
||||||
using Dalamud.Plugin.Services;
|
using Dalamud.Plugin.Services;
|
||||||
using OtterGui.Services;
|
using OtterGui.Services;
|
||||||
using Penumbra.Api.Enums;
|
using Penumbra.Api.Enums;
|
||||||
using Penumbra.Collections;
|
|
||||||
using Penumbra.Collections.Manager;
|
|
||||||
using Penumbra.GameData.Interop;
|
|
||||||
using Penumbra.Interop.Services;
|
using Penumbra.Interop.Services;
|
||||||
|
|
||||||
namespace Penumbra.Api.Api;
|
namespace Penumbra.Api.Api;
|
||||||
|
|
||||||
public class RedrawApi(RedrawService redrawService, IFramework framework, CollectionManager collections, ObjectManager objects, ApiHelpers helpers) : IPenumbraApiRedraw, IApiService
|
public class RedrawApi(RedrawService redrawService, IFramework framework) : IPenumbraApiRedraw, IApiService
|
||||||
{
|
{
|
||||||
public void RedrawObject(int gameObjectIndex, RedrawType setting)
|
public void RedrawObject(int gameObjectIndex, RedrawType setting)
|
||||||
{
|
{
|
||||||
|
|
@ -31,24 +28,6 @@ public class RedrawApi(RedrawService redrawService, IFramework framework, Collec
|
||||||
framework.RunOnFrameworkThread(() => redrawService.RedrawAll(setting));
|
framework.RunOnFrameworkThread(() => redrawService.RedrawAll(setting));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RedrawCollectionMembers(Guid collectionId, RedrawType setting)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (!collections.Storage.ById(collectionId, out var collection))
|
|
||||||
collection = ModCollection.Empty;
|
|
||||||
framework.RunOnFrameworkThread(() =>
|
|
||||||
{
|
|
||||||
foreach (var actor in objects.Objects)
|
|
||||||
{
|
|
||||||
helpers.AssociatedCollection(actor.ObjectIndex, out var modCollection);
|
|
||||||
if (collection == modCollection)
|
|
||||||
{
|
|
||||||
redrawService.RedrawObject(actor.ObjectIndex, setting);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public event GameObjectRedrawnDelegate? GameObjectRedrawn
|
public event GameObjectRedrawnDelegate? GameObjectRedrawn
|
||||||
{
|
{
|
||||||
add => redrawService.GameObjectRedrawn += value;
|
add => redrawService.GameObjectRedrawn += value;
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,6 @@ public sealed class IpcProviders : IDisposable, IApiService
|
||||||
IpcSubscribers.RedrawObject.Provider(pi, api.Redraw),
|
IpcSubscribers.RedrawObject.Provider(pi, api.Redraw),
|
||||||
IpcSubscribers.RedrawAll.Provider(pi, api.Redraw),
|
IpcSubscribers.RedrawAll.Provider(pi, api.Redraw),
|
||||||
IpcSubscribers.GameObjectRedrawn.Provider(pi, api.Redraw),
|
IpcSubscribers.GameObjectRedrawn.Provider(pi, api.Redraw),
|
||||||
IpcSubscribers.RedrawCollectionMembers.Provider(pi, api.Redraw),
|
|
||||||
|
|
||||||
IpcSubscribers.ResolveDefaultPath.Provider(pi, api.Resolve),
|
IpcSubscribers.ResolveDefaultPath.Provider(pi, api.Resolve),
|
||||||
IpcSubscribers.ResolveInterfacePath.Provider(pi, api.Resolve),
|
IpcSubscribers.ResolveInterfacePath.Provider(pi, api.Resolve),
|
||||||
|
|
|
||||||
|
|
@ -121,10 +121,6 @@ public class CollectionsIpcTester(IDalamudPluginInterface pi) : IUiService
|
||||||
}).ToArray();
|
}).ToArray();
|
||||||
ImGui.OpenPopup("Changed Item List");
|
ImGui.OpenPopup("Changed Item List");
|
||||||
}
|
}
|
||||||
IpcTester.DrawIntro(RedrawCollectionMembers.Label, "Redraw Collection Members");
|
|
||||||
if (ImGui.Button("Redraw##ObjectCollection"))
|
|
||||||
new RedrawCollectionMembers(pi).Invoke(collectionList[0].Id, RedrawType.Redraw);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawChangedItemPopup()
|
private void DrawChangedItemPopup()
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,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;
|
||||||
|
|
@ -77,8 +76,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;
|
||||||
|
|
|
||||||
|
|
@ -137,7 +137,7 @@ public sealed unsafe class CollectionResolver(
|
||||||
{
|
{
|
||||||
var item = charaEntry.Value;
|
var item = charaEntry.Value;
|
||||||
var identifier = actors.CreatePlayer(new ByteString(item->Name), item->HomeWorldId);
|
var identifier = actors.CreatePlayer(new ByteString(item->Name), item->HomeWorldId);
|
||||||
Penumbra.Log.Excessive(
|
Penumbra.Log.Verbose(
|
||||||
$"Identified {identifier.Incognito(null)} in cutscene for actor {idx + 200} at 0x{(ulong)gameObject:X} of race {(gameObject->IsCharacter() ? ((Character*)gameObject)->DrawData.CustomizeData.Race.ToString() : "Unknown")}.");
|
$"Identified {identifier.Incognito(null)} in cutscene for actor {idx + 200} at 0x{(ulong)gameObject:X} of race {(gameObject->IsCharacter() ? ((Character*)gameObject)->DrawData.CustomizeData.Race.ToString() : "Unknown")}.");
|
||||||
if (identifier.IsValid && CollectionByIdentifier(identifier) is { } coll)
|
if (identifier.IsValid && CollectionByIdentifier(identifier) is { } coll)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,6 @@ public sealed class CutsceneService : IRequiredService, IDisposable
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
_copiedCharacters[copyIdx - CutsceneStartIdx] = (short)parentIdx;
|
_copiedCharacters[copyIdx - CutsceneStartIdx] = (short)parentIdx;
|
||||||
_objects.InvokeRequiredUpdates();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<Project Sdk="Dalamud.NET.Sdk/14.0.0">
|
<Project Sdk="Dalamud.NET.Sdk/13.1.0">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<AssemblyTitle>Penumbra</AssemblyTitle>
|
<AssemblyTitle>Penumbra</AssemblyTitle>
|
||||||
<Company>absolute gangstas</Company>
|
<Company>absolute gangstas</Company>
|
||||||
|
|
|
||||||
|
|
@ -1,209 +0,0 @@
|
||||||
using OtterGui.Services;
|
|
||||||
using Penumbra.Mods.Manager;
|
|
||||||
|
|
||||||
namespace Penumbra.Services;
|
|
||||||
|
|
||||||
public class FileWatcher : IDisposable, IService
|
|
||||||
{
|
|
||||||
// TODO: use ConcurrentSet when it supports comparers in Luna.
|
|
||||||
private readonly ConcurrentDictionary<string, byte> _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, 0);
|
|
||||||
|
|
||||||
private async Task ConsumerLoopAsync(CancellationToken token)
|
|
||||||
{
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
var (path, _) = _pending.FirstOrDefault();
|
|
||||||
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, out _);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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,39 +0,0 @@
|
||||||
using Dalamud.Bindings.ImGui;
|
|
||||||
using Dalamud.Interface.ImGuiNotification;
|
|
||||||
using Dalamud.Interface.ImGuiNotification.EventArgs;
|
|
||||||
using OtterGui.Text;
|
|
||||||
using Penumbra.Mods.Manager;
|
|
||||||
|
|
||||||
namespace Penumbra.Services;
|
|
||||||
|
|
||||||
public class InstallNotification(ModImportManager modImportManager, string filePath) : OtterGui.Classes.MessageService.IMessage
|
|
||||||
{
|
|
||||||
public string Message
|
|
||||||
=> "A new mod has been found!";
|
|
||||||
|
|
||||||
public NotificationType NotificationType
|
|
||||||
=> NotificationType.Info;
|
|
||||||
|
|
||||||
public uint NotificationDuration
|
|
||||||
=> uint.MaxValue;
|
|
||||||
|
|
||||||
public string NotificationTitle { get; } = Path.GetFileNameWithoutExtension(filePath);
|
|
||||||
|
|
||||||
public string LogMessage
|
|
||||||
=> $"A new mod has been found: {Path.GetFileName(filePath)}";
|
|
||||||
|
|
||||||
public void OnNotificationActions(INotificationDrawArgs args)
|
|
||||||
{
|
|
||||||
var region = ImGui.GetContentRegionAvail();
|
|
||||||
var buttonSize = new Vector2((region.X - ImGui.GetStyle().ItemSpacing.X) / 2, 0);
|
|
||||||
if (ImUtf8.ButtonEx("Install"u8, ""u8, buttonSize))
|
|
||||||
{
|
|
||||||
modImportManager.AddUnpack(filePath);
|
|
||||||
args.Notification.DismissNow();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui.SameLine();
|
|
||||||
if (ImUtf8.ButtonEx("Ignore"u8, ""u8, buttonSize))
|
|
||||||
args.Notification.DismissNow();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -7,7 +7,6 @@ using Dalamud.Interface.ManagedFontAtlas;
|
||||||
using Dalamud.Interface.Utility;
|
using Dalamud.Interface.Utility;
|
||||||
using Dalamud.Plugin;
|
using Dalamud.Plugin;
|
||||||
using Dalamud.Bindings.ImGui;
|
using Dalamud.Bindings.ImGui;
|
||||||
using Dalamud.Plugin.Services;
|
|
||||||
using OtterGui;
|
using OtterGui;
|
||||||
using OtterGui.Classes;
|
using OtterGui.Classes;
|
||||||
using OtterGui.Extensions;
|
using OtterGui.Extensions;
|
||||||
|
|
@ -18,6 +17,7 @@ using Penumbra.Collections.Manager;
|
||||||
using Penumbra.GameData.Actors;
|
using Penumbra.GameData.Actors;
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
using Penumbra.Mods.Manager;
|
using Penumbra.Mods.Manager;
|
||||||
|
using Penumbra.Mods.Settings;
|
||||||
using Penumbra.Services;
|
using Penumbra.Services;
|
||||||
using Penumbra.UI.Classes;
|
using Penumbra.UI.Classes;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
using Dalamud.Bindings.ImGui;
|
using Dalamud.Bindings.ImGui;
|
||||||
|
using Dalamud.Game.ClientState.Objects;
|
||||||
using Dalamud.Plugin;
|
using Dalamud.Plugin;
|
||||||
using Dalamud.Plugin.Services;
|
|
||||||
using OtterGui.Raii;
|
using OtterGui.Raii;
|
||||||
using OtterGui.Services;
|
using OtterGui.Services;
|
||||||
using OtterGui.Widgets;
|
using OtterGui.Widgets;
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
||||||
using FFXIVClientStructs.FFXIV.Client.System.Resource;
|
using FFXIVClientStructs.FFXIV.Client.System.Resource;
|
||||||
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
|
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
|
||||||
using Dalamud.Bindings.ImGui;
|
using Dalamud.Bindings.ImGui;
|
||||||
using Dalamud.Game.ClientState.Objects.SubKinds;
|
|
||||||
using Dalamud.Interface.Colors;
|
using Dalamud.Interface.Colors;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using OtterGui;
|
using OtterGui;
|
||||||
|
|
@ -1034,7 +1033,7 @@ public class DebugTab : Window, ITab, IUiService
|
||||||
/// <summary> Draw information about the models, materials and resources currently loaded by the local player. </summary>
|
/// <summary> Draw information about the models, materials and resources currently loaded by the local player. </summary>
|
||||||
private unsafe void DrawPlayerModelInfo()
|
private unsafe void DrawPlayerModelInfo()
|
||||||
{
|
{
|
||||||
var player = _objects.Objects.LocalPlayer;
|
var player = _clientState.LocalPlayer;
|
||||||
var name = player?.Name.ToString() ?? "NULL";
|
var name = player?.Name.ToString() ?? "NULL";
|
||||||
if (!ImGui.CollapsingHeader($"Player Model Info: {name}##Draw") || player == null)
|
if (!ImGui.CollapsingHeader($"Player Model Info: {name}##Draw") || player == null)
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ public class ModsTab(
|
||||||
TutorialService tutorial,
|
TutorialService tutorial,
|
||||||
RedrawService redrawService,
|
RedrawService redrawService,
|
||||||
Configuration config,
|
Configuration config,
|
||||||
|
IClientState clientState,
|
||||||
CollectionSelectHeader collectionHeader,
|
CollectionSelectHeader collectionHeader,
|
||||||
ITargetManager targets,
|
ITargetManager targets,
|
||||||
ObjectManager objects)
|
ObjectManager objects)
|
||||||
|
|
@ -112,7 +113,7 @@ public class ModsTab(
|
||||||
ImGui.SetTooltip($"The supported modifiers for '/penumbra redraw' are:\n{TutorialService.SupportedRedrawModifiers}");
|
ImGui.SetTooltip($"The supported modifiers for '/penumbra redraw' are:\n{TutorialService.SupportedRedrawModifiers}");
|
||||||
|
|
||||||
using var id = ImRaii.PushId("Redraw");
|
using var id = ImRaii.PushId("Redraw");
|
||||||
using var disabled = ImRaii.Disabled(objects.Objects.LocalPlayer is null);
|
using var disabled = ImRaii.Disabled(clientState.LocalPlayer == null);
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
var buttonWidth = frameHeight with { X = ImGui.GetContentRegionAvail().X / 5 };
|
var buttonWidth = frameHeight with { X = ImGui.GetContentRegionAvail().X / 5 };
|
||||||
var tt = !objects[0].Valid
|
var tt = !objects[0].Valid
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
using Dalamud.Bindings.ImGui;
|
using Dalamud.Bindings.ImGui;
|
||||||
using Dalamud.Plugin.Services;
|
using Dalamud.Game;
|
||||||
using FFXIVClientStructs.FFXIV.Client.System.Resource;
|
using FFXIVClientStructs.FFXIV.Client.System.Resource;
|
||||||
using FFXIVClientStructs.FFXIV.Client.System.Resource.Handle;
|
using FFXIVClientStructs.FFXIV.Client.System.Resource.Handle;
|
||||||
using FFXIVClientStructs.Interop;
|
using FFXIVClientStructs.Interop;
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,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;
|
||||||
|
|
@ -66,8 +65,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,
|
||||||
|
|
@ -84,7 +82,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;
|
||||||
|
|
@ -650,13 +647,6 @@ public class SettingsTab : ITab, IUiService
|
||||||
DrawDefaultModImportFolder();
|
DrawDefaultModImportFolder();
|
||||||
DrawPcpFolder();
|
DrawPcpFolder();
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -736,46 +726,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()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
{
|
{
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"net10.0-windows7.0": {
|
"net9.0-windows7.0": {
|
||||||
"DotNet.ReproducibleBuilds": {
|
"DotNet.ReproducibleBuilds": {
|
||||||
"type": "Direct",
|
"type": "Direct",
|
||||||
"requested": "[1.2.39, )",
|
"requested": "[1.2.25, )",
|
||||||
"resolved": "1.2.39",
|
"resolved": "1.2.25",
|
||||||
"contentHash": "fcFN01tDTIQqDuTwr1jUQK/geofiwjG5DycJQOnC72i1SsLAk1ELe+apBOuZ11UMQG8YKFZG1FgvjZPbqHyatg=="
|
"contentHash": "xCXiw7BCxHJ8pF6wPepRUddlh2dlQlbr81gXA72hdk4FLHkKXas7EH/n+fk5UCA/YfMqG1Z6XaPiUjDbUNBUzg=="
|
||||||
},
|
},
|
||||||
"EmbedIO": {
|
"EmbedIO": {
|
||||||
"type": "Direct",
|
"type": "Direct",
|
||||||
|
|
@ -33,6 +33,7 @@
|
||||||
"resolved": "0.40.0",
|
"resolved": "0.40.0",
|
||||||
"contentHash": "yP/aFX1jqGikVF7u2f05VEaWN4aCaKNLxSas82UgA2GGVECxq/BcqZx3STHCJ78qilo1azEOk1XpBglIuGMb7w==",
|
"contentHash": "yP/aFX1jqGikVF7u2f05VEaWN4aCaKNLxSas82UgA2GGVECxq/BcqZx3STHCJ78qilo1azEOk1XpBglIuGMb7w==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"System.Buffers": "4.6.0",
|
||||||
"ZstdSharp.Port": "0.8.5"
|
"ZstdSharp.Port": "0.8.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -65,7 +66,10 @@
|
||||||
"FlatSharp.Runtime": {
|
"FlatSharp.Runtime": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "7.9.0",
|
"resolved": "7.9.0",
|
||||||
"contentHash": "Bm8+WqzEsWNpxqrD5x4x+zQ8dyINlToCreM5FI2oNSfUVc9U9ZB+qztX/jd8rlJb3r0vBSlPwVLpw0xBtPa3Vw=="
|
"contentHash": "Bm8+WqzEsWNpxqrD5x4x+zQ8dyINlToCreM5FI2oNSfUVc9U9ZB+qztX/jd8rlJb3r0vBSlPwVLpw0xBtPa3Vw==",
|
||||||
|
"dependencies": {
|
||||||
|
"System.Memory": "4.5.5"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"JetBrains.Annotations": {
|
"JetBrains.Annotations": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
|
|
@ -98,15 +102,33 @@
|
||||||
"SharpGLTF.Core": "1.0.5"
|
"SharpGLTF.Core": "1.0.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"System.Buffers": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "4.6.0",
|
||||||
|
"contentHash": "lN6tZi7Q46zFzAbRYXTIvfXcyvQQgxnY7Xm6C6xQ9784dEL1amjM6S6Iw4ZpsvesAKnRVsM4scrDQaDqSClkjA=="
|
||||||
|
},
|
||||||
|
"System.Memory": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "4.5.5",
|
||||||
|
"contentHash": "XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw=="
|
||||||
|
},
|
||||||
"System.Security.Cryptography.Pkcs": {
|
"System.Security.Cryptography.Pkcs": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "8.0.1",
|
"resolved": "8.0.1",
|
||||||
"contentHash": "CoCRHFym33aUSf/NtWSVSZa99dkd0Hm7OCZUxORBjRB16LNhIEOf8THPqzIYlvKM0nNDAPTRBa1FxEECrgaxxA=="
|
"contentHash": "CoCRHFym33aUSf/NtWSVSZa99dkd0Hm7OCZUxORBjRB16LNhIEOf8THPqzIYlvKM0nNDAPTRBa1FxEECrgaxxA=="
|
||||||
},
|
},
|
||||||
|
"System.ValueTuple": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "4.5.0",
|
||||||
|
"contentHash": "okurQJO6NRE/apDIP23ajJ0hpiNmJ+f0BwOlB/cSqTLQlw5upkf+5+96+iG2Jw40G1fCVCyPz/FhIABUjMR+RQ=="
|
||||||
|
},
|
||||||
"Unosquare.Swan.Lite": {
|
"Unosquare.Swan.Lite": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "3.1.0",
|
"resolved": "3.1.0",
|
||||||
"contentHash": "X3s5QE/KMj3WAPFqFve7St+Ds10BB50u8kW8PmKIn7FVkn7yEXe9Yxr2htt1WV85DRqfFR0MN/BUNHkGHtL4OQ=="
|
"contentHash": "X3s5QE/KMj3WAPFqFve7St+Ds10BB50u8kW8PmKIn7FVkn7yEXe9Yxr2htt1WV85DRqfFR0MN/BUNHkGHtL4OQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"System.ValueTuple": "4.5.0"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"ZstdSharp.Port": {
|
"ZstdSharp.Port": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
|
|
@ -132,7 +154,7 @@
|
||||||
"FlatSharp.Compiler": "[7.9.0, )",
|
"FlatSharp.Compiler": "[7.9.0, )",
|
||||||
"FlatSharp.Runtime": "[7.9.0, )",
|
"FlatSharp.Runtime": "[7.9.0, )",
|
||||||
"OtterGui": "[1.0.0, )",
|
"OtterGui": "[1.0.0, )",
|
||||||
"Penumbra.Api": "[5.13.0, )",
|
"Penumbra.Api": "[5.10.0, )",
|
||||||
"Penumbra.String": "[1.0.6, )"
|
"Penumbra.String": "[1.0.6, )"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
10
repo.json
10
repo.json
|
|
@ -5,8 +5,8 @@
|
||||||
"Punchline": "Runtime mod loader and manager.",
|
"Punchline": "Runtime mod loader and manager.",
|
||||||
"Description": "Runtime mod loader and manager.",
|
"Description": "Runtime mod loader and manager.",
|
||||||
"InternalName": "Penumbra",
|
"InternalName": "Penumbra",
|
||||||
"AssemblyVersion": "1.5.1.8",
|
"AssemblyVersion": "1.5.1.2",
|
||||||
"TestingAssemblyVersion": "1.5.1.8",
|
"TestingAssemblyVersion": "1.5.1.5",
|
||||||
"RepoUrl": "https://github.com/xivdev/Penumbra",
|
"RepoUrl": "https://github.com/xivdev/Penumbra",
|
||||||
"ApplicableVersion": "any",
|
"ApplicableVersion": "any",
|
||||||
"DalamudApiLevel": 13,
|
"DalamudApiLevel": 13,
|
||||||
|
|
@ -18,9 +18,9 @@
|
||||||
"LoadPriority": 69420,
|
"LoadPriority": 69420,
|
||||||
"LoadRequiredState": 2,
|
"LoadRequiredState": 2,
|
||||||
"LoadSync": true,
|
"LoadSync": true,
|
||||||
"DownloadLinkInstall": "https://github.com/xivdev/Penumbra/releases/download/1.5.1.8/Penumbra.zip",
|
"DownloadLinkInstall": "https://github.com/xivdev/Penumbra/releases/download/1.5.1.2/Penumbra.zip",
|
||||||
"DownloadLinkTesting": "https://github.com/xivdev/Penumbra/releases/download/1.5.1.8/Penumbra.zip",
|
"DownloadLinkTesting": "https://github.com/xivdev/Penumbra/releases/download/testing_1.5.1.5/Penumbra.zip",
|
||||||
"DownloadLinkUpdate": "https://github.com/xivdev/Penumbra/releases/download/1.5.1.8/Penumbra.zip",
|
"DownloadLinkUpdate": "https://github.com/xivdev/Penumbra/releases/download/1.5.1.2/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