Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
ac22227
Implement Container Peeking
StoiaCode May 5, 2026
71c0906
Merge branch 'xivdev:testing' into fileWatcher/archivePeeking
StoiaCode May 5, 2026
91d63c4
Fix Spacing
StoiaCode May 5, 2026
1c3d548
Remove redundant FileInfo call
StoiaCode May 5, 2026
f30a4bf
Merge branch 'stable' into fileWatcher/archivePeeking
Exter-N May 8, 2026
59b25f3
Make mod imports awaitable
Exter-N May 9, 2026
9ed3c19
Current state.
Ottermandias May 16, 2026
b028372
Fix issue with substitution, possibly.
Ottermandias May 19, 2026
0c0a818
Update libraries.
Ottermandias May 19, 2026
da11299
Merge branch 'testing' into identifiers
Ottermandias May 19, 2026
3f11e00
Add MetaDeserialization.
Ottermandias May 19, 2026
0fbbf81
Add AddToJson for STJ to meta identifiers.
Ottermandias May 20, 2026
cfc846f
Add colors and separators to options, update parsers.
Ottermandias May 21, 2026
65e7f99
Fix some issues with unnecessary saves.
Ottermandias May 21, 2026
91bc158
New Mod parsing equal to existing parsing achieved.
Ottermandias May 21, 2026
9f8f4fb
Fix remaining ser/deser issues, update schemas.
Ottermandias May 22, 2026
e64ab1f
Use IndexList and update things.
Ottermandias May 23, 2026
faafcce
Merge remote-tracking branch 'origin/testing' into identifiers
Ottermandias May 23, 2026
19dc3bc
Merge pull request #1 from Exter-N/fileWatcher/archivePeeking
StoiaCode May 24, 2026
c0dfa20
Merge branch 'xivdev:testing' into fileWatcher/archivePeeking
StoiaCode May 24, 2026
80a587a
Fix parsing errors.
Ottermandias May 24, 2026
2481ba3
Make model stuff start from 0 instead of 1.
Ottermandias May 24, 2026
92850f3
Change Folder & Add Notification System
StoiaCode May 25, 2026
3f09e4e
Only allow 3 at most mod installation query notifications at once.
Ottermandias May 25, 2026
e76698c
Fix TreeLineDrawer for parents that do not indent or start lines.
Ottermandias May 25, 2026
670f7ec
Fix issue with unclamped values in color table edits.
Ottermandias May 26, 2026
692a63e
discard return task from TriggerImport
StoiaCode May 27, 2026
864af6f
Fix Move to Quick Folder for selection.
Ottermandias Jun 3, 2026
7b03fae
Current state.
Ottermandias Jun 4, 2026
dd66ff9
Remove some import vulnerabilities.
Ottermandias Jun 15, 2026
0772802
Current condition state.
Ottermandias Jun 15, 2026
832bd61
Make the mass-descendant buttons require misclick protection, update …
Ottermandias Jun 21, 2026
cbf31a4
Use Luna SafeHandles, add Luna.DirectX tester
Exter-N Jun 11, 2026
9d608da
Documentation
Exter-N Jun 14, 2026
51d48ef
Use Dimensions
Exter-N Jun 16, 2026
8208e27
Remove warning for EasyEyes path.
Ottermandias Jun 24, 2026
aa8aae0
Fix filter save.
Ottermandias Jun 24, 2026
50c1556
Use node tester in condition drawer for the moment.
Ottermandias Jun 24, 2026
9b7f08a
Leave streams open after saving.
Ottermandias Jun 25, 2026
d476cfb
Check hostiles when using ownership.
Ottermandias Jun 28, 2026
7d7caea
Remove unused parameter.
Ottermandias Jun 28, 2026
7d88884
Fix crash when resolving accessory-skin materials in ResourceTree.
Ottermandias Jul 7, 2026
4d09ec5
Add IPC caller tracking for debug info.
Ottermandias Jul 7, 2026
689a887
Current state of condition drawing.
Ottermandias Jul 7, 2026
1f807bd
Fix mod parse test utility.
Ottermandias Jul 7, 2026
5d81e19
Merge remote-tracking branch 'Exter-N/identifiers-dx' into identifiers
Ottermandias Jul 7, 2026
07e9dc0
Merge remote-tracking branch 'upstream/identifiers' into fileWatcher/…
StoiaCode Jul 8, 2026
16847ee
Update to SharpCompress 0.48.1's renamed OpenArchive factory methods
StoiaCode Jul 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7,314 changes: 3,657 additions & 3,657 deletions .editorconfig

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Luna
Submodule Luna updated 131 files
38 changes: 19 additions & 19 deletions Penumbra.CrashHandler/Penumbra.CrashHandler.csproj
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
<Project Sdk="Dalamud.NET.Sdk/15.0.0">
<PropertyGroup>
<OutputType>Exe</OutputType>
<SuppressNETCoreSdkPreviewMessage>true</SuppressNETCoreSdkPreviewMessage>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DebugType>embedded</DebugType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DebugType>embedded</DebugType>
</PropertyGroup>
<PropertyGroup>
<Use_DalamudPackager>false</Use_DalamudPackager>
</PropertyGroup>
</Project>
<Project Sdk="Dalamud.NET.Sdk/15.0.0">
<PropertyGroup>
<OutputType>Exe</OutputType>
<SuppressNETCoreSdkPreviewMessage>true</SuppressNETCoreSdkPreviewMessage>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DebugType>embedded</DebugType>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DebugType>embedded</DebugType>
</PropertyGroup>

<PropertyGroup>
<Use_DalamudPackager>false</Use_DalamudPackager>
</PropertyGroup>

</Project>
16 changes: 14 additions & 2 deletions Penumbra.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@
<Folder Name="/Solution Items/Schemas/">
<File Path="schemas/default_mod.json" />
<File Path="schemas/group.json" />
<File Path="schemas/local_mod_data-v3.json" />
<File Path="schemas/shpk_devkit.json" />
<File Path="schemas/mod_meta-v3.json" />
<File Path="schemas/mod_meta-v4.json" />
</Folder>
<Folder Name="/Solution Items/Schemas/structs/">
<Folder Name="/Solution Items/Schemas/Structs/">
<File Path="schemas/structs/option_condition.json" />
<File Path="schemas/structs/container.json" />
<File Path="schemas/structs/group_combining.json" />
<File Path="schemas/structs/group_imc.json" />
Expand All @@ -35,6 +37,16 @@
<File Path="schemas/structs/meta_shp.json" />
<File Path="schemas/structs/option.json" />
</Folder>
<Folder Name="/Solution Items/Schemas/Structs/Conditions/">
<File Path="schemas/structs/all_settings_condition.json" />
<File Path="schemas/structs/any_setting_condition.json" />
<File Path="schemas/structs/condition.json" />
<File Path="Luna/schemas/and_condition.json" />
<File Path="Luna/schemas/or_condition.json" />
<File Path="Luna/schemas/not_condition.json" />
<File Path="Luna/schemas/true_condition.json" />
<File Path="Luna/schemas/false_condition.json" />
</Folder>
<Project Path="Luna/Luna.Generators/Luna.Generators.csproj">
<Platform Project="x64" />
</Project>
Expand Down
1 change: 1 addition & 0 deletions Penumbra/Api/Api/ModSettingsApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,7 @@ private void OnModOptionEdited(in ModOptionChanged.Arguments arguments)
case ModOptionChangeType.OptionFilesAdded:
case ModOptionChangeType.OptionSwapsChanged:
case ModOptionChangeType.OptionMetaChanged:
case ModOptionChangeType.ConditionChanged:
TriggerSettingEdited(arguments.Mod);
break;
}
Expand Down
20 changes: 15 additions & 5 deletions Penumbra/Api/DalamudSubstitutionProvider.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Dalamud.Interface;
using Dalamud.Plugin.Services;
using Penumbra.Collections.Cache;
using Penumbra.Collections.Manager;
using Penumbra.Communication;
using Penumbra.Services;
Expand All @@ -12,17 +13,19 @@ public class DalamudSubstitutionProvider : IDisposable, Luna.IApiService
private readonly ITextureSubstitutionProvider _substitution;
private readonly IUiBuilder _uiBuilder;
private readonly ActiveCollectionData _activeCollectionData;
private readonly CollectionCacheManager _caches; // May be required to not be disposed on disposal.
private readonly Configuration _config;
private readonly CommunicatorService _communicator;

public bool Enabled
=> _config.UseDalamudUiTextureRedirection;

public DalamudSubstitutionProvider(ITextureSubstitutionProvider substitution, ActiveCollectionData activeCollectionData,
Configuration config, CommunicatorService communicator, IUiBuilder ui)
Configuration config, CommunicatorService communicator, IUiBuilder ui, CollectionCacheManager caches)
{
_substitution = substitution;
_uiBuilder = ui;
_caches = caches;
_activeCollectionData = activeCollectionData;
_config = config;
_communicator = communicator;
Expand All @@ -43,10 +46,17 @@ public void ResetSubstitutions(IEnumerable<Utf8GamePath> paths)
if (!_uiBuilder.UiPrepared)
return;

var transformed = paths
.Where(p => (p.Path.StartsWith("ui/"u8) || p.Path.StartsWith("common/font/"u8)) && p.Path.EndsWith(".tex"u8))
.Select(p => p.ToString());
_substitution.InvalidatePaths(transformed);
try
{
var transformed = paths
.Where(p => (p.Path.StartsWith("ui/"u8) || p.Path.StartsWith("common/font/"u8)) && p.Path.EndsWith(".tex"u8))
.Select(p => p.ToString());
_substitution.InvalidatePaths(transformed);
}
catch (Exception ex)
{
Penumbra.Log.Error($"Failed to reset texture substitutions:\n{ex}");
}
}

public void Enable()
Expand Down
18 changes: 12 additions & 6 deletions Penumbra/Api/IpcProviders.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,13 @@ namespace Penumbra.Api;

public sealed class IpcProviders : IDisposable, IApiService, IRequiredService
{
private static readonly HashSet<CallerPlugin> InternalCallers = [];

private readonly List<IDisposable> _providers;

public static IReadOnlySet<CallerPlugin> Callers
=> InternalCallers;

private readonly EventProvider _disposedProvider;
private readonly EventProvider _initializedProvider;
private readonly CharacterUtility _characterUtility;
Expand Down Expand Up @@ -77,9 +82,10 @@ public IpcProviders(IDalamudPluginInterface pi, IPenumbraApi api, CharacterUtili
IpcSubscribers.ModSettingChanged.Provider(pi, api.ModSettings),
IpcSubscribers.CopyModSettings.Provider(pi, api.ModSettings),

IpcSubscribers.ApiVersion.Provider(pi, api),
new FuncProvider<(int Major, int Minor)>(pi, "Penumbra.ApiVersions", () => api.ApiVersion), // backward compatibility
new FuncProvider<int>(pi, "Penumbra.ApiVersion", () => api.ApiVersion.Breaking), // backward compatibility
IpcSubscribers.ApiVersion.Provider(pi, InternalCallers, api),
new FuncProvider<(int Major, int Minor)>(pi, InternalCallers, "Penumbra.ApiVersions",
() => api.ApiVersion), // backward compatibility
new FuncProvider<int>(pi, InternalCallers, "Penumbra.ApiVersion", () => api.ApiVersion.Breaking), // backward compatibility
IpcSubscribers.GetModDirectory.Provider(pi, api.PluginState),
IpcSubscribers.GetConfiguration.Provider(pi, api.PluginState),
IpcSubscribers.ModDirectoryChanged.Provider(pi, api.PluginState),
Expand Down Expand Up @@ -111,11 +117,11 @@ public IpcProviders(IDalamudPluginInterface pi, IPenumbraApi api, CharacterUtili
IpcSubscribers.GetGameObjectResourceTrees.Provider(pi, api.ResourceTree),
IpcSubscribers.GetPlayerResourceTrees.Provider(pi, api.ResourceTree),

IpcSubscribers.CreateTemporaryCollection.Provider(pi, api.Temporary),
IpcSubscribers.CreateTemporaryCollection.Provider(pi, InternalCallers, api.Temporary),
IpcSubscribers.DeleteTemporaryCollection.Provider(pi, api.Temporary),
IpcSubscribers.AssignTemporaryCollection.Provider(pi, api.Temporary),
IpcSubscribers.AddTemporaryModAll.Provider(pi, api.Temporary),
IpcSubscribers.AddTemporaryMod.Provider(pi, api.Temporary),
IpcSubscribers.AddTemporaryModAll.Provider(pi, InternalCallers, api.Temporary),
IpcSubscribers.AddTemporaryMod.Provider(pi, InternalCallers, api.Temporary),
IpcSubscribers.RemoveTemporaryModAll.Provider(pi, api.Temporary),
IpcSubscribers.RemoveTemporaryMod.Provider(pi, api.Temporary),
IpcSubscribers.SetTemporaryModSettings.Provider(pi, api.Temporary),
Expand Down
2 changes: 1 addition & 1 deletion Penumbra/Collections/Cache/CustomResourceCache.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using FFXIVClientStructs.FFXIV.Client.System.Resource;
using Luna;
using Penumbra.Api.Enums;
using Penumbra.Interop.Hooks.ResourceLoading;
using Penumbra.Interop.SafeHandles;
using Penumbra.String.Classes;

namespace Penumbra.Collections.Cache;
Expand Down
3 changes: 1 addition & 2 deletions Penumbra/Collections/Manager/ActiveCollectionMigration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Penumbra.Files;
using Penumbra.Services;

namespace Penumbra.Collections.Manager;

Expand All @@ -19,7 +18,7 @@ public static void MigrateUngenderedCollections(FilenameService fileNames)
{
var oldName = type.ToString()[4..];
var value = jObject[oldName];
if (value == null)
if (value is null)
continue;

jObject.Remove(oldName);
Expand Down
18 changes: 9 additions & 9 deletions Penumbra/Collections/Manager/ActiveCollections.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ public ModCollection Interface

/// <summary> Get the collection assigned to an individual or Default if unassigned. </summary>
public ModCollection Individual(ActorIdentifier identifier)
=> Individuals.TryGetCollection(identifier, out var c) ? c : Default;
=> Individuals.TryGetCollection(identifier, out var c, false) ? c : Default;

/// <summary> The list of group assignments. </summary>
private ModCollection?[] SpecialCollections
Expand Down Expand Up @@ -547,16 +547,16 @@ public string RedundancyCheck(CollectionType type, ActorIdentifier id)
return
$"Assignment is redundant due to overwriting Male Players and Female Players{racialString} with an identical collection.\nYou can remove it.";

if (male == null)
if (male is null)
{
if (female == null && @base == yourself)
if (female is null && @base == yourself)
return
$"Assignment is redundant due to overwriting Base{racialString} with an identical collection.\nYou can remove it.";
if (female == yourself && @base == yourself)
return
$"Assignment is redundant due to overwriting Base and Female Players{racialString} with an identical collection.\nYou can remove it.";
}
else if (male == yourself && female == null && @base == yourself)
else if (male == yourself && female is null && @base == yourself)
{
return
$"Assignment is redundant due to overwriting Base and Male Players{racialString} with an identical collection.\nYou can remove it.";
Expand All @@ -570,7 +570,7 @@ public string RedundancyCheck(CollectionType type, ActorIdentifier id)
case IdentifierType.Player when id.HomeWorld != ushort.MaxValue:
{
var global = ByType(CollectionType.Individual, _actors.CreatePlayer(id.PlayerName, ushort.MaxValue));
return (global != null ? global.Identity.Index : null) == checkAssignment.Identity.Index
return global?.Identity.Index == checkAssignment.Identity.Index
? "Assignment is redundant due to an identical Any-World assignment existing.\nYou can remove it."
: string.Empty;
}
Expand All @@ -579,12 +579,12 @@ public string RedundancyCheck(CollectionType type, ActorIdentifier id)
{
var global = ByType(CollectionType.Individual,
_actors.CreateOwned(id.PlayerName, ushort.MaxValue, id.Kind, id.DataId));
if ((global != null ? global.Identity.Index : null) == checkAssignment.Identity.Index)
if (global?.Identity.Index == checkAssignment.Identity.Index)
return "Assignment is redundant due to an identical Any-World assignment existing.\nYou can remove it.";
}

var unowned = ByType(CollectionType.Individual, _actors.CreateNpc(id.Kind, id.DataId));
return (unowned != null ? unowned.Identity.Index : null) == checkAssignment.Identity.Index
return unowned?.Identity.Index == checkAssignment.Identity.Index
? "Assignment is redundant due to an identical unowned NPC assignment existing.\nYou can remove it."
: string.Empty;
}
Expand All @@ -606,7 +606,7 @@ public string RedundancyCheck(CollectionType type, ActorIdentifier id)
collection1 = CollectionType.Default;
}

if (femaleNpc == null)
if (femaleNpc is null)
{
femaleNpc = Default;
if (femaleNpc.Identity.Index != checkAssignment.Identity.Index)
Expand All @@ -626,7 +626,7 @@ public string RedundancyCheck(CollectionType type, ActorIdentifier id)
foreach (var parentType in group)
{
var assignment = ByType(parentType);
if (assignment == null)
if (assignment is null)
continue;

if (assignment.Identity.Index == checkAssignment.Identity.Index)
Expand Down
17 changes: 9 additions & 8 deletions Penumbra/Collections/Manager/IndividualCollections.Access.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using Dalamud.Game.ClientState.Objects.Types;
using Penumbra.GameData.Actors;
using Penumbra.GameData.Enums;
using Penumbra.GameData.Interop;
using Penumbra.String;

namespace Penumbra.Collections.Manager;
Expand All @@ -20,9 +21,9 @@ public int Count
public (string DisplayName, ModCollection Collection) this[int index]
=> (_assignments[index].DisplayName, _assignments[index].Collection);

public bool TryGetCollection(ActorIdentifier identifier, [NotNullWhen(true)] out ModCollection? collection)
public bool TryGetCollection(ActorIdentifier identifier, [NotNullWhen(true)] out ModCollection? collection, bool hostile)
{
if (Count == 0)
if (Count is 0)
{
collection = null;
return false;
Expand Down Expand Up @@ -53,7 +54,7 @@ public bool TryGetCollection(ActorIdentifier identifier, [NotNullWhen(true)] out
return true;

// Handle Ownership.
if (!_config.UseOwnerNameForCharacterCollection)
if (!_config.UseOwnerNameForCharacterCollection || hostile && !_config.UseOwnerForHostiles)
return false;

identifier = _actors.CreateIndividualUnchecked(IdentifierType.Player, identifier.PlayerName,
Expand Down Expand Up @@ -85,7 +86,7 @@ public enum SpecialResult

public (ActorIdentifier, SpecialResult) ConvertSpecialIdentifier(ActorIdentifier identifier)
{
if (identifier.Type != IdentifierType.Special)
if (identifier.Type is not IdentifierType.Special)
return (identifier, SpecialResult.Invalid);

if (_actors.ResolvePartyBannerPlayer(identifier.Special, out var id))
Expand All @@ -105,8 +106,7 @@ public enum SpecialResult
return (_actors.GetCurrentPlayer(), SpecialResult.FittingRoom);
case ScreenActor.DyePreview when _config.UseCharacterCollectionInTryOn:
return (_actors.GetCurrentPlayer(), SpecialResult.DyePreview);
case ScreenActor.Portrait when _config.UseCharacterCollectionsInCards:
return (_actors.GetCurrentPlayer(), SpecialResult.Portrait);
case ScreenActor.Portrait when _config.UseCharacterCollectionsInCards: return (_actors.GetCurrentPlayer(), SpecialResult.Portrait);
case ScreenActor.ExamineScreen:
{
identifier = _actors.GetInspectPlayer();
Expand All @@ -126,10 +126,11 @@ public enum SpecialResult
}

public bool TryGetCollection(IGameObject? gameObject, out ModCollection? collection)
=> TryGetCollection(_actors.FromObject(gameObject, true, false, false), out collection);
=> TryGetCollection(_actors.FromObject(gameObject, true, false, false), out collection,
gameObject is ICharacter c && c.StatusFlags.HasFlag(StatusFlags.Hostile));

public unsafe bool TryGetCollection(FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject* gameObject, out ModCollection? collection)
=> TryGetCollection(_actors.FromObject(gameObject, out _, true, false, false), out collection);
=> TryGetCollection(_actors.FromObject(gameObject, out _, true, false, false), out collection, ((Actor)gameObject).IsHostile);

private bool CheckWorlds(ActorIdentifier identifier, out ModCollection? collection)
{
Expand Down
4 changes: 1 addition & 3 deletions Penumbra/Collections/ModCollectionSave.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using Penumbra.Files;
using Penumbra.Mods.Manager;
using Penumbra.Mods.Settings;
using Penumbra.Services;

namespace Penumbra.Collections;

Expand All @@ -29,10 +28,9 @@ public void Save(Stream stream)
j.WriteNumber("Version"u8, ModCollection.CurrentVersion);
j.WriteString("Id"u8, modCollection.Identity.Identifier);
j.WriteString("Name"u8, modCollection.Identity.Name);
j.WritePropertyName("Settings"u8);

// Write all used and unused settings by mod directory name.
j.WriteStartObject();
j.WriteStartObject("Settings"u8);
var list = new List<(string, ModSettings.SavedSettings)>(modCollection.Settings.Count + modCollection.Settings.Unused.Count);
for (var i = 0; i < modCollection.Settings.Count; ++i)
{
Expand Down
5 changes: 4 additions & 1 deletion Penumbra/Communication/ModDataChanged.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public sealed class ModDataChanged(LunaLogger log) : EventBase<ModDataChanged.Ar
{
public enum Priority
{
/// <seealso cref="UI.ModsTab.ModFileSystemSelector.OnModDataChange"/>
/// <seealso cref="UI.ModsTab.Selector.ModFileSystemCache.OnModDataChange"/>
ModFileSystemCache = -10,

/// <seealso cref="Mods.Manager.ModCacheManager.OnModDataChange"/>
Expand All @@ -20,6 +20,9 @@ public enum Priority

/// <seealso cref="UI.ModsTab.ModPanelHeader.OnModDataChange"/>
ModPanelHeader = 0,

/// <seealso cref="UI.ModsTab.Groups.GroupNameCache.OnModDataChange"/>
GroupNameCache = 0,
}

/// <summary> The arguments for a ModDataChanged event. </summary>
Expand Down
Loading
Loading