diff --git a/Penumbra.GameData b/Penumbra.GameData index 27893a85..3baace73 160000 --- a/Penumbra.GameData +++ b/Penumbra.GameData @@ -1 +1 @@ -Subproject commit 27893a85adb57a301dd93fd2c7d318bfd4c12a0f +Subproject commit 3baace73c828271dcb71a8156e3e7b91e1dd12ae diff --git a/Penumbra/Api/HttpApi.cs b/Penumbra/Api/HttpApi.cs index 8f8b44f4..79348a88 100644 --- a/Penumbra/Api/HttpApi.cs +++ b/Penumbra/Api/HttpApi.cs @@ -5,6 +5,7 @@ using EmbedIO.WebApi; using OtterGui.Services; using Penumbra.Api.Api; using Penumbra.Api.Enums; +using Penumbra.Mods.Settings; namespace Penumbra.Api; @@ -13,13 +14,15 @@ public class HttpApi : IDisposable, IApiService private partial class Controller : WebApiController { // @formatter:off - [Route( HttpVerbs.Get, "/mods" )] public partial object? GetMods(); - [Route( HttpVerbs.Post, "/redraw" )] public partial Task Redraw(); - [Route( HttpVerbs.Post, "/redrawAll" )] public partial Task RedrawAll(); - [Route( HttpVerbs.Post, "/reloadmod" )] public partial Task ReloadMod(); - [Route( HttpVerbs.Post, "/installmod" )] public partial Task InstallMod(); - [Route( HttpVerbs.Post, "/openwindow" )] public partial void OpenWindow(); - [Route( HttpVerbs.Post, "/focusmod" )] public partial Task FocusMod(); + [Route( HttpVerbs.Get, "/moddirectory" )] public partial string GetModDirectory(); + [Route( HttpVerbs.Get, "/mods" )] public partial object? GetMods(); + [Route( HttpVerbs.Post, "/redraw" )] public partial Task Redraw(); + [Route( HttpVerbs.Post, "/redrawAll" )] public partial Task RedrawAll(); + [Route( HttpVerbs.Post, "/reloadmod" )] public partial Task ReloadMod(); + [Route( HttpVerbs.Post, "/installmod" )] public partial Task InstallMod(); + [Route( HttpVerbs.Post, "/openwindow" )] public partial void OpenWindow(); + [Route( HttpVerbs.Post, "/focusmod" )] public partial Task FocusMod(); + [Route( HttpVerbs.Post, "/setmodsettings")] public partial Task SetModSettings(); // @formatter:on } @@ -65,6 +68,12 @@ public class HttpApi : IDisposable, IApiService private partial class Controller(IPenumbraApi api, IFramework framework) { + public partial string GetModDirectory() + { + Penumbra.Log.Debug($"[HTTP] {nameof(GetModDirectory)} triggered."); + return api.PluginState.GetModDirectory(); + } + public partial object? GetMods() { Penumbra.Log.Debug($"[HTTP] {nameof(GetMods)} triggered."); @@ -116,6 +125,7 @@ public class HttpApi : IDisposable, IApiService Penumbra.Log.Debug($"[HTTP] {nameof(OpenWindow)} triggered."); api.Ui.OpenMainWindow(TabType.Mods, string.Empty, string.Empty); } + public async partial Task FocusMod() { var data = await HttpContext.GetRequestDataAsync().ConfigureAwait(false); @@ -124,6 +134,30 @@ public class HttpApi : IDisposable, IApiService api.Ui.OpenMainWindow(TabType.Mods, data.Path, data.Name); } + public async partial Task SetModSettings() + { + var data = await HttpContext.GetRequestDataAsync().ConfigureAwait(false); + Penumbra.Log.Debug($"[HTTP] {nameof(SetModSettings)} triggered."); + await framework.RunOnFrameworkThread(() => + { + var collection = data.CollectionId ?? api.Collection.GetCollection(ApiCollectionType.Current)!.Value.Id; + if (data.Inherit.HasValue) + { + api.ModSettings.TryInheritMod(collection, data.ModPath, data.ModName, data.Inherit.Value); + if (data.Inherit.Value) + return; + } + + if (data.State.HasValue) + api.ModSettings.TrySetMod(collection, data.ModPath, data.ModName, data.State.Value); + if (data.Priority.HasValue) + api.ModSettings.TrySetModPriority(collection, data.ModPath, data.ModName, data.Priority.Value); + foreach (var (group, settings) in data.Settings ?? []) + api.ModSettings.TrySetModSettings(collection, data.ModPath, data.ModName, group, settings); + } + ).ConfigureAwait(false); + } + private record ModReloadData(string Path, string Name) { public ModReloadData() @@ -151,5 +185,19 @@ public class HttpApi : IDisposable, IApiService : this(string.Empty, RedrawType.Redraw, -1) { } } + + private record SetModSettingsData( + Guid? CollectionId, + string ModPath, + string ModName, + bool? Inherit, + bool? State, + int? Priority, + Dictionary>? Settings) + { + public SetModSettingsData() + : this(null, string.Empty, string.Empty, null, null, null, null) + {} + } } } diff --git a/Penumbra/Interop/PathResolving/CollectionResolver.cs b/Penumbra/Interop/PathResolving/CollectionResolver.cs index 10795e6d..136393d4 100644 --- a/Penumbra/Interop/PathResolving/CollectionResolver.cs +++ b/Penumbra/Interop/PathResolving/CollectionResolver.cs @@ -137,7 +137,7 @@ public sealed unsafe class CollectionResolver( { var item = charaEntry.Value; var identifier = actors.CreatePlayer(new ByteString(item->Name), item->HomeWorldId); - Penumbra.Log.Verbose( + Penumbra.Log.Excessive( $"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) { diff --git a/Penumbra/Interop/Services/RedrawService.cs b/Penumbra/Interop/Services/RedrawService.cs index 08e9ddf5..2d741277 100644 --- a/Penumbra/Interop/Services/RedrawService.cs +++ b/Penumbra/Interop/Services/RedrawService.cs @@ -421,9 +421,9 @@ public sealed unsafe partial class RedrawService : IDisposable return; - foreach (ref var f in currentTerritory->Furniture) + foreach (ref var f in currentTerritory->FurnitureManager.FurnitureMemory) { - var gameObject = f.Index >= 0 ? currentTerritory->HousingObjectManager.Objects[f.Index].Value : null; + var gameObject = f.Index >= 0 ? currentTerritory->FurnitureManager.ObjectManager.ObjectArray.Objects[f.Index].Value : null; if (gameObject == null) continue; diff --git a/Penumbra/Penumbra.cs b/Penumbra/Penumbra.cs index 0f5703a3..8ed2c585 100644 --- a/Penumbra/Penumbra.cs +++ b/Penumbra/Penumbra.cs @@ -21,7 +21,6 @@ using Penumbra.UI; using ResidentResourceManager = Penumbra.Interop.Services.ResidentResourceManager; using Dalamud.Plugin.Services; using Lumina.Excel.Sheets; -using Penumbra.GameData; using Penumbra.GameData.Data; using Penumbra.Interop; using Penumbra.Interop.Hooks; diff --git a/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.cs b/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.cs index e15d1c90..2c7c889e 100644 --- a/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.cs +++ b/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.cs @@ -216,7 +216,7 @@ public sealed partial class MtrlTab : IWritable, IDisposable } public bool Valid - => _shadersKnown && Mtrl.Valid; + => Mtrl.Valid; // FIXME This should be _shadersKnown && Mtrl.Valid but the algorithm for _shadersKnown is flawed as of 7.2. public byte[] Write() { diff --git a/Penumbra/UI/CollectionTab/CollectionPanel.cs b/Penumbra/UI/CollectionTab/CollectionPanel.cs index 26fa2b14..e41ceade 100644 --- a/Penumbra/UI/CollectionTab/CollectionPanel.cs +++ b/Penumbra/UI/CollectionTab/CollectionPanel.cs @@ -11,6 +11,7 @@ using OtterGui; using OtterGui.Classes; using OtterGui.Extensions; using OtterGui.Raii; +using OtterGui.Text; using Penumbra.Collections; using Penumbra.Collections.Manager; using Penumbra.GameData.Actors; @@ -222,26 +223,31 @@ public sealed class CollectionPanel( ImGui.EndGroup(); ImGui.SameLine(); ImGui.BeginGroup(); - using var style = ImRaii.PushStyle(ImGuiStyleVar.ButtonTextAlign, new Vector2(0, 0.5f)); - var name = _newName ?? collection.Identity.Name; - var identifier = collection.Identity.Identifier; - var width = ImGui.GetContentRegionAvail().X; - var fileName = saveService.FileNames.CollectionFile(collection); - ImGui.SetNextItemWidth(width); - if (ImGui.InputText("##name", ref name, 128)) - _newName = name; - if (ImGui.IsItemDeactivatedAfterEdit() && _newName != null && _newName != collection.Identity.Name) + var width = ImGui.GetContentRegionAvail().X; + using (ImRaii.Disabled(_collections.DefaultNamed == collection)) { - collection.Identity.Name = _newName; - saveService.QueueSave(new ModCollectionSave(mods, collection)); - selector.RestoreCollections(); - _newName = null; - } - else if (ImGui.IsItemDeactivated()) - { - _newName = null; + using var style = ImRaii.PushStyle(ImGuiStyleVar.ButtonTextAlign, new Vector2(0, 0.5f)); + var name = _newName ?? collection.Identity.Name; + ImGui.SetNextItemWidth(width); + if (ImGui.InputText("##name", ref name, 128)) + _newName = name; + if (ImGui.IsItemDeactivatedAfterEdit() && _newName != null && _newName != collection.Identity.Name) + { + collection.Identity.Name = _newName; + saveService.QueueSave(new ModCollectionSave(mods, collection)); + selector.RestoreCollections(); + _newName = null; + } + else if (ImGui.IsItemDeactivated()) + { + _newName = null; + } } + if (_collections.DefaultNamed == collection) + ImUtf8.HoverTooltip(ImGuiHoveredFlags.AllowWhenDisabled, "The Default collection can not be renamed."u8); + var identifier = collection.Identity.Identifier; + var fileName = saveService.FileNames.CollectionFile(collection); using (ImRaii.PushFont(UiBuilder.MonoFont)) { if (ImGui.Button(collection.Identity.Identifier, new Vector2(width, 0))) @@ -375,9 +381,7 @@ public sealed class CollectionPanel( ImGuiUtil.TextWrapped(type.ToDescription()); switch (type) { - case CollectionType.Default: - ImGui.TextUnformatted("Overruled by any other Assignment."); - break; + case CollectionType.Default: ImGui.TextUnformatted("Overruled by any other Assignment."); break; case CollectionType.Yourself: ImGuiUtil.DrawColoredText(("Overruled by ", 0), ("Individual ", ColorId.NewMod.Value()), ("Assignments.", 0)); break; diff --git a/Penumbra/UI/CollectionTab/CollectionSelector.cs b/Penumbra/UI/CollectionTab/CollectionSelector.cs index e54f994e..79254090 100644 --- a/Penumbra/UI/CollectionTab/CollectionSelector.cs +++ b/Penumbra/UI/CollectionTab/CollectionSelector.cs @@ -116,7 +116,8 @@ public sealed class CollectionSelector : ItemSelector, IDisposabl public void RestoreCollections() { Items.Clear(); - foreach (var c in _storage.OrderBy(c => c.Identity.Name)) + Items.Add(_storage.DefaultNamed); + foreach (var c in _storage.OrderBy(c => c.Identity.Name).Where(c => c != _storage.DefaultNamed)) Items.Add(c); SetFilterDirty(); SetCurrent(_active.Current); diff --git a/repo.json b/repo.json index 9ff227b6..2a31b75e 100644 --- a/repo.json +++ b/repo.json @@ -5,8 +5,8 @@ "Punchline": "Runtime mod loader and manager.", "Description": "Runtime mod loader and manager.", "InternalName": "Penumbra", - "AssemblyVersion": "1.5.1.2", - "TestingAssemblyVersion": "1.5.1.2", + "AssemblyVersion": "1.5.1.6", + "TestingAssemblyVersion": "1.5.1.6", "RepoUrl": "https://github.com/xivdev/Penumbra", "ApplicableVersion": "any", "DalamudApiLevel": 13, @@ -18,9 +18,9 @@ "LoadPriority": 69420, "LoadRequiredState": 2, "LoadSync": true, - "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.2/Penumbra.zip", - "DownloadLinkUpdate": "https://github.com/xivdev/Penumbra/releases/download/1.5.1.2/Penumbra.zip", + "DownloadLinkInstall": "https://github.com/xivdev/Penumbra/releases/download/1.5.1.6/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", "IconUrl": "https://raw.githubusercontent.com/xivdev/Penumbra/master/images/icon.png" } ]