mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-13 12:14:17 +01:00
Update for changed GameData.
This commit is contained in:
parent
3305250482
commit
7d612df951
42 changed files with 374 additions and 455 deletions
2
OtterGui
2
OtterGui
|
|
@ -1 +1 @@
|
||||||
Subproject commit 5f0eec50ea7f7a4727ceab056bc3756f0ed58a30
|
Subproject commit bde59c34f7108520002c21cdbf21e8ee5b586944
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit ffdb966fec5a657893289e655c641ceb3af1d59f
|
Subproject commit afc56d9f07a2a54ab791a4c85cf627b6f884aec2
|
||||||
|
|
@ -95,7 +95,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
||||||
private DalamudServices _dalamud;
|
private DalamudServices _dalamud;
|
||||||
private TempCollectionManager _tempCollections;
|
private TempCollectionManager _tempCollections;
|
||||||
private TempModManager _tempMods;
|
private TempModManager _tempMods;
|
||||||
private ActorService _actors;
|
private ActorManager _actors;
|
||||||
private CollectionResolver _collectionResolver;
|
private CollectionResolver _collectionResolver;
|
||||||
private CutsceneService _cutsceneService;
|
private CutsceneService _cutsceneService;
|
||||||
private ModImportManager _modImportManager;
|
private ModImportManager _modImportManager;
|
||||||
|
|
@ -108,7 +108,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
||||||
|
|
||||||
public unsafe PenumbraApi(CommunicatorService communicator, ModManager modManager, ResourceLoader resourceLoader,
|
public unsafe PenumbraApi(CommunicatorService communicator, ModManager modManager, ResourceLoader resourceLoader,
|
||||||
Configuration config, CollectionManager collectionManager, DalamudServices dalamud, TempCollectionManager tempCollections,
|
Configuration config, CollectionManager collectionManager, DalamudServices dalamud, TempCollectionManager tempCollections,
|
||||||
TempModManager tempMods, ActorService actors, CollectionResolver collectionResolver, CutsceneService cutsceneService,
|
TempModManager tempMods, ActorManager actors, CollectionResolver collectionResolver, CutsceneService cutsceneService,
|
||||||
ModImportManager modImportManager, CollectionEditor collectionEditor, RedrawService redrawService, ModFileSystem modFileSystem,
|
ModImportManager modImportManager, CollectionEditor collectionEditor, RedrawService redrawService, ModFileSystem modFileSystem,
|
||||||
ConfigWindow configWindow, TextureManager textureManager, ResourceTreeFactory resourceTreeFactory)
|
ConfigWindow configWindow, TextureManager textureManager, ResourceTreeFactory resourceTreeFactory)
|
||||||
{
|
{
|
||||||
|
|
@ -889,13 +889,10 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
||||||
{
|
{
|
||||||
CheckInitialized();
|
CheckInitialized();
|
||||||
|
|
||||||
if (!_actors.Valid)
|
|
||||||
return PenumbraApiEc.SystemDisposed;
|
|
||||||
|
|
||||||
if (actorIndex < 0 || actorIndex >= _dalamud.Objects.Length)
|
if (actorIndex < 0 || actorIndex >= _dalamud.Objects.Length)
|
||||||
return PenumbraApiEc.InvalidArgument;
|
return PenumbraApiEc.InvalidArgument;
|
||||||
|
|
||||||
var identifier = _actors.AwaitedService.FromObject(_dalamud.Objects[actorIndex], false, false, true);
|
var identifier = _actors.FromObject(_dalamud.Objects[actorIndex], false, false, true);
|
||||||
if (!identifier.IsValid)
|
if (!identifier.IsValid)
|
||||||
return PenumbraApiEc.InvalidArgument;
|
return PenumbraApiEc.InvalidArgument;
|
||||||
|
|
||||||
|
|
@ -1143,11 +1140,11 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||||
private unsafe ActorIdentifier AssociatedIdentifier(int gameObjectIdx)
|
private unsafe ActorIdentifier AssociatedIdentifier(int gameObjectIdx)
|
||||||
{
|
{
|
||||||
if (gameObjectIdx < 0 || gameObjectIdx >= _dalamud.Objects.Length || !_actors.Valid)
|
if (gameObjectIdx < 0 || gameObjectIdx >= _dalamud.Objects.Length)
|
||||||
return ActorIdentifier.Invalid;
|
return ActorIdentifier.Invalid;
|
||||||
|
|
||||||
var ptr = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)_dalamud.Objects.GetObjectAddress(gameObjectIdx);
|
var ptr = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)_dalamud.Objects.GetObjectAddress(gameObjectIdx);
|
||||||
return _actors.AwaitedService.FromObject(ptr, out _, false, true, true);
|
return _actors.FromObject(ptr, out _, false, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve a path given by string for a specific collection.
|
// Resolve a path given by string for a specific collection.
|
||||||
|
|
@ -1241,12 +1238,9 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
||||||
// TODO: replace all usages with ActorIdentifier stuff when incrementing API
|
// TODO: replace all usages with ActorIdentifier stuff when incrementing API
|
||||||
private ActorIdentifier NameToIdentifier(string name, ushort worldId)
|
private ActorIdentifier NameToIdentifier(string name, ushort worldId)
|
||||||
{
|
{
|
||||||
if (!_actors.Valid)
|
|
||||||
return ActorIdentifier.Invalid;
|
|
||||||
|
|
||||||
// Verified to be valid name beforehand.
|
// Verified to be valid name beforehand.
|
||||||
var b = ByteString.FromStringUnsafe(name, false);
|
var b = ByteString.FromStringUnsafe(name, false);
|
||||||
return _actors.AwaitedService.CreatePlayer(b, worldId);
|
return _actors.CreatePlayer(b, worldId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnModSettingChange(ModCollection collection, ModSettingChange type, Mod? mod, int _1, int _2, bool inherited)
|
private void OnModSettingChange(ModCollection collection, ModSettingChange type, Mod? mod, int _1, int _2, bool inherited)
|
||||||
|
|
|
||||||
|
|
@ -22,10 +22,10 @@ public class CollectionCache : IDisposable
|
||||||
private readonly CollectionCacheManager _manager;
|
private readonly CollectionCacheManager _manager;
|
||||||
private readonly ModCollection _collection;
|
private readonly ModCollection _collection;
|
||||||
public readonly CollectionModData ModData = new();
|
public readonly CollectionModData ModData = new();
|
||||||
public readonly SortedList<string, (SingleArray<IMod>, object?)> _changedItems = new();
|
private readonly SortedList<string, (SingleArray<IMod>, object?)> _changedItems = [];
|
||||||
public readonly ConcurrentDictionary<Utf8GamePath, ModPath> ResolvedFiles = new();
|
public readonly ConcurrentDictionary<Utf8GamePath, ModPath> ResolvedFiles = new();
|
||||||
public readonly MetaCache Meta;
|
public readonly MetaCache Meta;
|
||||||
public readonly Dictionary<IMod, SingleArray<ModConflicts>> _conflicts = new();
|
public readonly Dictionary<IMod, SingleArray<ModConflicts>> ConflictDict = [];
|
||||||
|
|
||||||
public int Calculating = -1;
|
public int Calculating = -1;
|
||||||
|
|
||||||
|
|
@ -33,10 +33,10 @@ public class CollectionCache : IDisposable
|
||||||
=> _collection.AnonymizedName;
|
=> _collection.AnonymizedName;
|
||||||
|
|
||||||
public IEnumerable<SingleArray<ModConflicts>> AllConflicts
|
public IEnumerable<SingleArray<ModConflicts>> AllConflicts
|
||||||
=> _conflicts.Values;
|
=> ConflictDict.Values;
|
||||||
|
|
||||||
public SingleArray<ModConflicts> Conflicts(IMod mod)
|
public SingleArray<ModConflicts> Conflicts(IMod mod)
|
||||||
=> _conflicts.TryGetValue(mod, out var c) ? c : new SingleArray<ModConflicts>();
|
=> ConflictDict.TryGetValue(mod, out SingleArray<ModConflicts> c) ? c : new SingleArray<ModConflicts>();
|
||||||
|
|
||||||
private int _changedItemsSaveCounter = -1;
|
private int _changedItemsSaveCounter = -1;
|
||||||
|
|
||||||
|
|
@ -195,7 +195,7 @@ public class CollectionCache : IDisposable
|
||||||
$"Invalid mod state, removing {mod.Name} and associated manipulation {manipulation} returned current mod {mp.Name}.");
|
$"Invalid mod state, removing {mod.Name} and associated manipulation {manipulation} returned current mod {mp.Name}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
_conflicts.Remove(mod);
|
ConflictDict.Remove(mod);
|
||||||
foreach (var conflict in conflicts)
|
foreach (var conflict in conflicts)
|
||||||
{
|
{
|
||||||
if (conflict.HasPriority)
|
if (conflict.HasPriority)
|
||||||
|
|
@ -206,9 +206,9 @@ public class CollectionCache : IDisposable
|
||||||
{
|
{
|
||||||
var newConflicts = Conflicts(conflict.Mod2).Remove(c => c.Mod2 == mod);
|
var newConflicts = Conflicts(conflict.Mod2).Remove(c => c.Mod2 == mod);
|
||||||
if (newConflicts.Count > 0)
|
if (newConflicts.Count > 0)
|
||||||
_conflicts[conflict.Mod2] = newConflicts;
|
ConflictDict[conflict.Mod2] = newConflicts;
|
||||||
else
|
else
|
||||||
_conflicts.Remove(conflict.Mod2);
|
ConflictDict.Remove(conflict.Mod2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -336,9 +336,9 @@ public class CollectionCache : IDisposable
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
if (changedConflicts.Count == 0)
|
if (changedConflicts.Count == 0)
|
||||||
_conflicts.Remove(mod);
|
ConflictDict.Remove(mod);
|
||||||
else
|
else
|
||||||
_conflicts[mod] = changedConflicts;
|
ConflictDict[mod] = changedConflicts;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a new conflict between the added mod and the existing mod.
|
// Add a new conflict between the added mod and the existing mod.
|
||||||
|
|
@ -373,9 +373,9 @@ public class CollectionCache : IDisposable
|
||||||
{
|
{
|
||||||
// Add the same conflict list to both conflict directions.
|
// Add the same conflict list to both conflict directions.
|
||||||
var conflictList = new List<object> { data };
|
var conflictList = new List<object> { data };
|
||||||
_conflicts[addedMod] = addedConflicts.Append(new ModConflicts(existingMod, conflictList, existingPriority < addedPriority,
|
ConflictDict[addedMod] = addedConflicts.Append(new ModConflicts(existingMod, conflictList, existingPriority < addedPriority,
|
||||||
existingPriority != addedPriority));
|
existingPriority != addedPriority));
|
||||||
_conflicts[existingMod] = existingConflicts.Append(new ModConflicts(addedMod, conflictList,
|
ConflictDict[existingMod] = existingConflicts.Append(new ModConflicts(addedMod, conflictList,
|
||||||
existingPriority >= addedPriority,
|
existingPriority >= addedPriority,
|
||||||
existingPriority != addedPriority));
|
existingPriority != addedPriority));
|
||||||
}
|
}
|
||||||
|
|
@ -426,7 +426,7 @@ public class CollectionCache : IDisposable
|
||||||
_changedItems.Clear();
|
_changedItems.Clear();
|
||||||
// Skip IMCs because they would result in far too many false-positive items,
|
// Skip IMCs because they would result in far too many false-positive items,
|
||||||
// since they are per set instead of per item-slot/item/variant.
|
// since they are per set instead of per item-slot/item/variant.
|
||||||
var identifier = _manager.MetaFileManager.Identifier.AwaitedService;
|
var identifier = _manager.MetaFileManager.Identifier;
|
||||||
var items = new SortedList<string, object?>(512);
|
var items = new SortedList<string, object?>(512);
|
||||||
|
|
||||||
void AddItems(IMod mod)
|
void AddItems(IMod mod)
|
||||||
|
|
|
||||||
|
|
@ -159,7 +159,7 @@ public class CollectionCacheManager : IDisposable
|
||||||
null);
|
null);
|
||||||
cache.ResolvedFiles.Clear();
|
cache.ResolvedFiles.Clear();
|
||||||
cache.Meta.Reset();
|
cache.Meta.Reset();
|
||||||
cache._conflicts.Clear();
|
cache.ConflictDict.Clear();
|
||||||
|
|
||||||
// Add all forced redirects.
|
// Add all forced redirects.
|
||||||
foreach (var tempMod in _tempMods.ModsForAllCollections
|
foreach (var tempMod in _tempMods.ModsForAllCollections
|
||||||
|
|
@ -372,7 +372,7 @@ public class CollectionCacheManager : IDisposable
|
||||||
{
|
{
|
||||||
collection._cache!.ResolvedFiles.Clear();
|
collection._cache!.ResolvedFiles.Clear();
|
||||||
collection._cache!.Meta.Reset();
|
collection._cache!.Meta.Reset();
|
||||||
collection._cache!._conflicts.Clear();
|
collection._cache!.ConflictDict.Clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,9 +28,9 @@ public class ActiveCollections : ISavable, IDisposable
|
||||||
private readonly CommunicatorService _communicator;
|
private readonly CommunicatorService _communicator;
|
||||||
private readonly SaveService _saveService;
|
private readonly SaveService _saveService;
|
||||||
private readonly ActiveCollectionData _data;
|
private readonly ActiveCollectionData _data;
|
||||||
private readonly ActorService _actors;
|
private readonly ActorManager _actors;
|
||||||
|
|
||||||
public ActiveCollections(Configuration config, CollectionStorage storage, ActorService actors, CommunicatorService communicator,
|
public ActiveCollections(Configuration config, CollectionStorage storage, ActorManager actors, CommunicatorService communicator,
|
||||||
SaveService saveService, ActiveCollectionData data)
|
SaveService saveService, ActiveCollectionData data)
|
||||||
{
|
{
|
||||||
_storage = storage;
|
_storage = storage;
|
||||||
|
|
@ -475,7 +475,7 @@ public class ActiveCollections : ISavable, IDisposable
|
||||||
{
|
{
|
||||||
case IdentifierType.Player when id.HomeWorld != ushort.MaxValue:
|
case IdentifierType.Player when id.HomeWorld != ushort.MaxValue:
|
||||||
{
|
{
|
||||||
var global = ByType(CollectionType.Individual, _actors.AwaitedService.CreatePlayer(id.PlayerName, ushort.MaxValue));
|
var global = ByType(CollectionType.Individual, _actors.CreatePlayer(id.PlayerName, ushort.MaxValue));
|
||||||
return global?.Index == checkAssignment.Index
|
return global?.Index == checkAssignment.Index
|
||||||
? "Assignment is redundant due to an identical Any-World assignment existing.\nYou can remove it."
|
? "Assignment is redundant due to an identical Any-World assignment existing.\nYou can remove it."
|
||||||
: string.Empty;
|
: string.Empty;
|
||||||
|
|
@ -484,12 +484,12 @@ public class ActiveCollections : ISavable, IDisposable
|
||||||
if (id.HomeWorld != ushort.MaxValue)
|
if (id.HomeWorld != ushort.MaxValue)
|
||||||
{
|
{
|
||||||
var global = ByType(CollectionType.Individual,
|
var global = ByType(CollectionType.Individual,
|
||||||
_actors.AwaitedService.CreateOwned(id.PlayerName, ushort.MaxValue, id.Kind, id.DataId));
|
_actors.CreateOwned(id.PlayerName, ushort.MaxValue, id.Kind, id.DataId));
|
||||||
if (global?.Index == checkAssignment.Index)
|
if (global?.Index == checkAssignment.Index)
|
||||||
return "Assignment is redundant due to an identical Any-World assignment existing.\nYou can remove it.";
|
return "Assignment is redundant due to an identical Any-World assignment existing.\nYou can remove it.";
|
||||||
}
|
}
|
||||||
|
|
||||||
var unowned = ByType(CollectionType.Individual, _actors.AwaitedService.CreateNpc(id.Kind, id.DataId));
|
var unowned = ByType(CollectionType.Individual, _actors.CreateNpc(id.Kind, id.DataId));
|
||||||
return unowned?.Index == checkAssignment.Index
|
return unowned?.Index == checkAssignment.Index
|
||||||
? "Assignment is redundant due to an identical unowned NPC assignment existing.\nYou can remove it."
|
? "Assignment is redundant due to an identical unowned NPC assignment existing.\nYou can remove it."
|
||||||
: string.Empty;
|
: string.Empty;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
using Dalamud.Game.ClientState.Objects.Enums;
|
using Dalamud.Game.ClientState.Objects.Enums;
|
||||||
using Dalamud.Game.ClientState.Objects.Types;
|
using Dalamud.Game.ClientState.Objects.Types;
|
||||||
using Penumbra.GameData.Actors;
|
using Penumbra.GameData.Actors;
|
||||||
|
using Penumbra.GameData.Enums;
|
||||||
using Penumbra.String;
|
using Penumbra.String;
|
||||||
|
|
||||||
namespace Penumbra.Collections.Manager;
|
namespace Penumbra.Collections.Manager;
|
||||||
|
|
@ -36,7 +37,7 @@ public sealed partial class IndividualCollections : IReadOnlyList<(string Displa
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (identifier.Retainer is not ActorIdentifier.RetainerType.Mannequin && _config.UseOwnerNameForCharacterCollection)
|
if (identifier.Retainer is not ActorIdentifier.RetainerType.Mannequin && _config.UseOwnerNameForCharacterCollection)
|
||||||
return CheckWorlds(_actorService.AwaitedService.GetCurrentPlayer(), out collection);
|
return CheckWorlds(_actors.GetCurrentPlayer(), out collection);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -46,7 +47,7 @@ public sealed partial class IndividualCollections : IReadOnlyList<(string Displa
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Handle generic NPC
|
// Handle generic NPC
|
||||||
var npcIdentifier = _actorService.AwaitedService.CreateIndividualUnchecked(IdentifierType.Npc, ByteString.Empty,
|
var npcIdentifier = _actors.CreateIndividualUnchecked(IdentifierType.Npc, ByteString.Empty,
|
||||||
ushort.MaxValue,
|
ushort.MaxValue,
|
||||||
identifier.Kind, identifier.DataId);
|
identifier.Kind, identifier.DataId);
|
||||||
if (npcIdentifier.IsValid && _individuals.TryGetValue(npcIdentifier, out collection))
|
if (npcIdentifier.IsValid && _individuals.TryGetValue(npcIdentifier, out collection))
|
||||||
|
|
@ -56,7 +57,7 @@ public sealed partial class IndividualCollections : IReadOnlyList<(string Displa
|
||||||
if (!_config.UseOwnerNameForCharacterCollection)
|
if (!_config.UseOwnerNameForCharacterCollection)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
identifier = _actorService.AwaitedService.CreateIndividualUnchecked(IdentifierType.Player, identifier.PlayerName,
|
identifier = _actors.CreateIndividualUnchecked(IdentifierType.Player, identifier.PlayerName,
|
||||||
identifier.HomeWorld.Id,
|
identifier.HomeWorld.Id,
|
||||||
ObjectKind.None, uint.MaxValue);
|
ObjectKind.None, uint.MaxValue);
|
||||||
return CheckWorlds(identifier, out collection);
|
return CheckWorlds(identifier, out collection);
|
||||||
|
|
@ -89,37 +90,37 @@ public sealed partial class IndividualCollections : IReadOnlyList<(string Displa
|
||||||
if (identifier.Type != IdentifierType.Special)
|
if (identifier.Type != IdentifierType.Special)
|
||||||
return (identifier, SpecialResult.Invalid);
|
return (identifier, SpecialResult.Invalid);
|
||||||
|
|
||||||
if (_actorService.AwaitedService.ResolvePartyBannerPlayer(identifier.Special, out var id))
|
if (_actors.ResolvePartyBannerPlayer(identifier.Special, out var id))
|
||||||
return _config.UseCharacterCollectionsInCards ? (id, SpecialResult.PartyBanner) : (identifier, SpecialResult.Invalid);
|
return _config.UseCharacterCollectionsInCards ? (id, SpecialResult.PartyBanner) : (identifier, SpecialResult.Invalid);
|
||||||
|
|
||||||
if (_actorService.AwaitedService.ResolvePvPBannerPlayer(identifier.Special, out id))
|
if (_actors.ResolvePvPBannerPlayer(identifier.Special, out id))
|
||||||
return _config.UseCharacterCollectionsInCards ? (id, SpecialResult.PvPBanner) : (identifier, SpecialResult.Invalid);
|
return _config.UseCharacterCollectionsInCards ? (id, SpecialResult.PvPBanner) : (identifier, SpecialResult.Invalid);
|
||||||
|
|
||||||
if (_actorService.AwaitedService.ResolveMahjongPlayer(identifier.Special, out id))
|
if (_actors.ResolveMahjongPlayer(identifier.Special, out id))
|
||||||
return _config.UseCharacterCollectionsInCards ? (id, SpecialResult.Mahjong) : (identifier, SpecialResult.Invalid);
|
return _config.UseCharacterCollectionsInCards ? (id, SpecialResult.Mahjong) : (identifier, SpecialResult.Invalid);
|
||||||
|
|
||||||
switch (identifier.Special)
|
switch (identifier.Special)
|
||||||
{
|
{
|
||||||
case ScreenActor.CharacterScreen when _config.UseCharacterCollectionInMainWindow:
|
case ScreenActor.CharacterScreen when _config.UseCharacterCollectionInMainWindow:
|
||||||
return (_actorService.AwaitedService.GetCurrentPlayer(), SpecialResult.CharacterScreen);
|
return (_actors.GetCurrentPlayer(), SpecialResult.CharacterScreen);
|
||||||
case ScreenActor.FittingRoom when _config.UseCharacterCollectionInTryOn:
|
case ScreenActor.FittingRoom when _config.UseCharacterCollectionInTryOn:
|
||||||
return (_actorService.AwaitedService.GetCurrentPlayer(), SpecialResult.FittingRoom);
|
return (_actors.GetCurrentPlayer(), SpecialResult.FittingRoom);
|
||||||
case ScreenActor.DyePreview when _config.UseCharacterCollectionInTryOn:
|
case ScreenActor.DyePreview when _config.UseCharacterCollectionInTryOn:
|
||||||
return (_actorService.AwaitedService.GetCurrentPlayer(), SpecialResult.DyePreview);
|
return (_actors.GetCurrentPlayer(), SpecialResult.DyePreview);
|
||||||
case ScreenActor.Portrait when _config.UseCharacterCollectionsInCards:
|
case ScreenActor.Portrait when _config.UseCharacterCollectionsInCards:
|
||||||
return (_actorService.AwaitedService.GetCurrentPlayer(), SpecialResult.Portrait);
|
return (_actors.GetCurrentPlayer(), SpecialResult.Portrait);
|
||||||
case ScreenActor.ExamineScreen:
|
case ScreenActor.ExamineScreen:
|
||||||
{
|
{
|
||||||
identifier = _actorService.AwaitedService.GetInspectPlayer();
|
identifier = _actors.GetInspectPlayer();
|
||||||
if (identifier.IsValid)
|
if (identifier.IsValid)
|
||||||
return (_config.UseCharacterCollectionInInspect ? identifier : ActorIdentifier.Invalid, SpecialResult.Inspect);
|
return (_config.UseCharacterCollectionInInspect ? identifier : ActorIdentifier.Invalid, SpecialResult.Inspect);
|
||||||
|
|
||||||
identifier = _actorService.AwaitedService.GetCardPlayer();
|
identifier = _actors.GetCardPlayer();
|
||||||
if (identifier.IsValid)
|
if (identifier.IsValid)
|
||||||
return (_config.UseCharacterCollectionInInspect ? identifier : ActorIdentifier.Invalid, SpecialResult.Card);
|
return (_config.UseCharacterCollectionInInspect ? identifier : ActorIdentifier.Invalid, SpecialResult.Card);
|
||||||
|
|
||||||
return _config.UseCharacterCollectionInTryOn
|
return _config.UseCharacterCollectionInTryOn
|
||||||
? (_actorService.AwaitedService.GetGlamourPlayer(), SpecialResult.Glamour)
|
? (_actors.GetGlamourPlayer(), SpecialResult.Glamour)
|
||||||
: (identifier, SpecialResult.Invalid);
|
: (identifier, SpecialResult.Invalid);
|
||||||
}
|
}
|
||||||
default: return (identifier, SpecialResult.Invalid);
|
default: return (identifier, SpecialResult.Invalid);
|
||||||
|
|
@ -127,10 +128,10 @@ public sealed partial class IndividualCollections : IReadOnlyList<(string Displa
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryGetCollection(GameObject? gameObject, out ModCollection? collection)
|
public bool TryGetCollection(GameObject? gameObject, out ModCollection? collection)
|
||||||
=> TryGetCollection(_actorService.AwaitedService.FromObject(gameObject, true, false, false), out collection);
|
=> TryGetCollection(_actors.FromObject(gameObject, true, false, false), out collection);
|
||||||
|
|
||||||
public unsafe bool TryGetCollection(FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject* gameObject, out ModCollection? collection)
|
public unsafe bool TryGetCollection(FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject* gameObject, out ModCollection? collection)
|
||||||
=> TryGetCollection(_actorService.AwaitedService.FromObject(gameObject, out _, true, false, false), out collection);
|
=> TryGetCollection(_actors.FromObject(gameObject, out _, true, false, false), out collection);
|
||||||
|
|
||||||
private bool CheckWorlds(ActorIdentifier identifier, out ModCollection? collection)
|
private bool CheckWorlds(ActorIdentifier identifier, out ModCollection? collection)
|
||||||
{
|
{
|
||||||
|
|
@ -143,7 +144,7 @@ public sealed partial class IndividualCollections : IReadOnlyList<(string Displa
|
||||||
if (_individuals.TryGetValue(identifier, out collection))
|
if (_individuals.TryGetValue(identifier, out collection))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
identifier = _actorService.AwaitedService.CreateIndividualUnchecked(identifier.Type, identifier.PlayerName, ushort.MaxValue,
|
identifier = _actors.CreateIndividualUnchecked(identifier.Type, identifier.PlayerName, ushort.MaxValue,
|
||||||
identifier.Kind,
|
identifier.Kind,
|
||||||
identifier.DataId);
|
identifier.DataId);
|
||||||
if (identifier.IsValid && _individuals.TryGetValue(identifier, out collection))
|
if (identifier.IsValid && _individuals.TryGetValue(identifier, out collection))
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@ using Dalamud.Interface.Internal.Notifications;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using OtterGui.Classes;
|
using OtterGui.Classes;
|
||||||
using Penumbra.GameData.Actors;
|
using Penumbra.GameData.Actors;
|
||||||
|
using Penumbra.GameData.DataContainers.Bases;
|
||||||
|
using Penumbra.GameData.Structs;
|
||||||
using Penumbra.Services;
|
using Penumbra.Services;
|
||||||
using Penumbra.String;
|
using Penumbra.String;
|
||||||
|
|
||||||
|
|
@ -26,23 +28,20 @@ public partial class IndividualCollections
|
||||||
|
|
||||||
public bool ReadJObject(SaveService saver, ActiveCollections parent, JArray? obj, CollectionStorage storage)
|
public bool ReadJObject(SaveService saver, ActiveCollections parent, JArray? obj, CollectionStorage storage)
|
||||||
{
|
{
|
||||||
if (_actorService.Valid)
|
if (_actors.Awaiter.IsCompletedSuccessfully)
|
||||||
{
|
{
|
||||||
var ret = ReadJObjectInternal(obj, storage);
|
var ret = ReadJObjectInternal(obj, storage);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Func()
|
Penumbra.Log.Debug("[Collections] Delayed reading individual assignments until actor service is ready...");
|
||||||
|
_actors.Awaiter.ContinueWith(_ =>
|
||||||
{
|
{
|
||||||
if (ReadJObjectInternal(obj, storage))
|
if (ReadJObjectInternal(obj, storage))
|
||||||
saver.ImmediateSave(parent);
|
saver.ImmediateSave(parent);
|
||||||
IsLoaded = true;
|
IsLoaded = true;
|
||||||
Loaded.Invoke();
|
Loaded.Invoke();
|
||||||
_actorService.FinishedCreation -= Func;
|
});
|
||||||
}
|
|
||||||
|
|
||||||
Penumbra.Log.Debug("[Collections] Delayed reading individual assignments until actor service is ready...");
|
|
||||||
_actorService.FinishedCreation += Func;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -60,7 +59,7 @@ public partial class IndividualCollections
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var identifier = _actorService.AwaitedService.FromJson(data as JObject);
|
var identifier = _actors.FromJson(data as JObject);
|
||||||
var group = GetGroup(identifier);
|
var group = GetGroup(identifier);
|
||||||
if (group.Length == 0 || group.Any(i => !i.IsValid))
|
if (group.Length == 0 || group.Any(i => !i.IsValid))
|
||||||
{
|
{
|
||||||
|
|
@ -101,10 +100,10 @@ public partial class IndividualCollections
|
||||||
|
|
||||||
internal void Migrate0To1(Dictionary<string, ModCollection> old)
|
internal void Migrate0To1(Dictionary<string, ModCollection> old)
|
||||||
{
|
{
|
||||||
static bool FindDataId(string name, IReadOnlyDictionary<uint, string> data, out uint dataId)
|
static bool FindDataId(string name, NameDictionary data, out NpcId dataId)
|
||||||
{
|
{
|
||||||
var kvp = data.FirstOrDefault(kvp => kvp.Value.Equals(name, StringComparison.OrdinalIgnoreCase),
|
var kvp = data.FirstOrDefault(kvp => kvp.Value.Equals(name, StringComparison.OrdinalIgnoreCase),
|
||||||
new KeyValuePair<uint, string>(uint.MaxValue, string.Empty));
|
new KeyValuePair<NpcId, string>(uint.MaxValue, string.Empty));
|
||||||
dataId = kvp.Key;
|
dataId = kvp.Key;
|
||||||
return kvp.Value.Length > 0;
|
return kvp.Value.Length > 0;
|
||||||
}
|
}
|
||||||
|
|
@ -114,22 +113,22 @@ public partial class IndividualCollections
|
||||||
var kind = ObjectKind.None;
|
var kind = ObjectKind.None;
|
||||||
var lowerName = name.ToLowerInvariant();
|
var lowerName = name.ToLowerInvariant();
|
||||||
// Prefer matching NPC names, fewer false positives than preferring players.
|
// Prefer matching NPC names, fewer false positives than preferring players.
|
||||||
if (FindDataId(lowerName, _actorService.AwaitedService.Data.Companions, out var dataId))
|
if (FindDataId(lowerName, _actors.Data.Companions, out var dataId))
|
||||||
kind = ObjectKind.Companion;
|
kind = ObjectKind.Companion;
|
||||||
else if (FindDataId(lowerName, _actorService.AwaitedService.Data.Mounts, out dataId))
|
else if (FindDataId(lowerName, _actors.Data.Mounts, out dataId))
|
||||||
kind = ObjectKind.MountType;
|
kind = ObjectKind.MountType;
|
||||||
else if (FindDataId(lowerName, _actorService.AwaitedService.Data.BNpcs, out dataId))
|
else if (FindDataId(lowerName, _actors.Data.BNpcs, out dataId))
|
||||||
kind = ObjectKind.BattleNpc;
|
kind = ObjectKind.BattleNpc;
|
||||||
else if (FindDataId(lowerName, _actorService.AwaitedService.Data.ENpcs, out dataId))
|
else if (FindDataId(lowerName, _actors.Data.ENpcs, out dataId))
|
||||||
kind = ObjectKind.EventNpc;
|
kind = ObjectKind.EventNpc;
|
||||||
|
|
||||||
var identifier = _actorService.AwaitedService.CreateNpc(kind, dataId);
|
var identifier = _actors.CreateNpc(kind, dataId);
|
||||||
if (identifier.IsValid)
|
if (identifier.IsValid)
|
||||||
{
|
{
|
||||||
// If the name corresponds to a valid npc, add it as a group. If this fails, notify users.
|
// If the name corresponds to a valid npc, add it as a group. If this fails, notify users.
|
||||||
var group = GetGroup(identifier);
|
var group = GetGroup(identifier);
|
||||||
var ids = string.Join(", ", group.Select(i => i.DataId.ToString()));
|
var ids = string.Join(", ", group.Select(i => i.DataId.ToString()));
|
||||||
if (Add($"{_actorService.AwaitedService.Data.ToName(kind, dataId)} ({kind.ToName()})", group, collection))
|
if (Add($"{_actors.Data.ToName(kind, dataId)} ({kind.ToName()})", group, collection))
|
||||||
Penumbra.Log.Information($"Migrated {name} ({kind.ToName()}) to NPC Identifiers [{ids}].");
|
Penumbra.Log.Information($"Migrated {name} ({kind.ToName()}) to NPC Identifiers [{ids}].");
|
||||||
else
|
else
|
||||||
Penumbra.Messager.NotificationMessage(
|
Penumbra.Messager.NotificationMessage(
|
||||||
|
|
@ -137,15 +136,12 @@ public partial class IndividualCollections
|
||||||
NotificationType.Error);
|
NotificationType.Error);
|
||||||
}
|
}
|
||||||
// If it is not a valid NPC name, check if it can be a player name.
|
// If it is not a valid NPC name, check if it can be a player name.
|
||||||
else if (ActorManager.VerifyPlayerName(name))
|
else if (ActorIdentifierFactory.VerifyPlayerName(name))
|
||||||
{
|
{
|
||||||
identifier = _actorService.AwaitedService.CreatePlayer(ByteString.FromStringUnsafe(name, false), ushort.MaxValue);
|
identifier = _actors.CreatePlayer(ByteString.FromStringUnsafe(name, false), ushort.MaxValue);
|
||||||
var shortName = string.Join(" ", name.Split().Select(n => $"{n[0]}."));
|
var shortName = string.Join(" ", name.Split().Select(n => $"{n[0]}."));
|
||||||
// Try to migrate the player name without logging full names.
|
// Try to migrate the player name without logging full names.
|
||||||
if (Add($"{name} ({_actorService.AwaitedService.Data.ToWorldName(identifier.HomeWorld)})", new[]
|
if (Add($"{name} ({_actors.Data.ToWorldName(identifier.HomeWorld)})", [identifier], collection))
|
||||||
{
|
|
||||||
identifier,
|
|
||||||
}, collection))
|
|
||||||
Penumbra.Log.Information($"Migrated {shortName} ({collection.AnonymizedName}) to Player Identifier.");
|
Penumbra.Log.Information($"Migrated {shortName} ({collection.AnonymizedName}) to Player Identifier.");
|
||||||
else
|
else
|
||||||
Penumbra.Messager.NotificationMessage(
|
Penumbra.Messager.NotificationMessage(
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
using Dalamud.Game.ClientState.Objects.Enums;
|
using Dalamud.Game.ClientState.Objects.Enums;
|
||||||
using OtterGui.Filesystem;
|
using OtterGui.Filesystem;
|
||||||
using Penumbra.GameData.Actors;
|
using Penumbra.GameData.Actors;
|
||||||
using Penumbra.Services;
|
using Penumbra.GameData.DataContainers.Bases;
|
||||||
|
using Penumbra.GameData.Enums;
|
||||||
|
using Penumbra.GameData.Structs;
|
||||||
using Penumbra.String;
|
using Penumbra.String;
|
||||||
|
|
||||||
namespace Penumbra.Collections.Manager;
|
namespace Penumbra.Collections.Manager;
|
||||||
|
|
@ -11,9 +13,9 @@ public sealed partial class IndividualCollections
|
||||||
public record struct IndividualAssignment(string DisplayName, IReadOnlyList<ActorIdentifier> Identifiers, ModCollection Collection);
|
public record struct IndividualAssignment(string DisplayName, IReadOnlyList<ActorIdentifier> Identifiers, ModCollection Collection);
|
||||||
|
|
||||||
private readonly Configuration _config;
|
private readonly Configuration _config;
|
||||||
private readonly ActorService _actorService;
|
private readonly ActorManager _actors;
|
||||||
private readonly Dictionary<ActorIdentifier, ModCollection> _individuals = new();
|
private readonly Dictionary<ActorIdentifier, ModCollection> _individuals = [];
|
||||||
private readonly List<IndividualAssignment> _assignments = new();
|
private readonly List<IndividualAssignment> _assignments = [];
|
||||||
|
|
||||||
public event Action Loaded;
|
public event Action Loaded;
|
||||||
public bool IsLoaded { get; private set; }
|
public bool IsLoaded { get; private set; }
|
||||||
|
|
@ -21,12 +23,12 @@ public sealed partial class IndividualCollections
|
||||||
public IReadOnlyList<IndividualAssignment> Assignments
|
public IReadOnlyList<IndividualAssignment> Assignments
|
||||||
=> _assignments;
|
=> _assignments;
|
||||||
|
|
||||||
public IndividualCollections(ActorService actorService, Configuration config, bool temporary)
|
public IndividualCollections(ActorManager actors, Configuration config, bool temporary)
|
||||||
{
|
{
|
||||||
_config = config;
|
_config = config;
|
||||||
_actorService = actorService;
|
_actors = actors;
|
||||||
IsLoaded = temporary;
|
IsLoaded = temporary;
|
||||||
Loaded += () => Penumbra.Log.Information($"{_assignments.Count} Individual Assignments loaded after delay.");
|
Loaded += () => Penumbra.Log.Information($"{_assignments.Count} Individual Assignments loaded after delay.");
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum AddResult
|
public enum AddResult
|
||||||
|
|
@ -69,44 +71,34 @@ public sealed partial class IndividualCollections
|
||||||
return set ? AddResult.AlreadySet : AddResult.Valid;
|
return set ? AddResult.AlreadySet : AddResult.Valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AddResult CanAdd(IdentifierType type, string name, ushort homeWorld, ObjectKind kind, IEnumerable<uint> dataIds,
|
public AddResult CanAdd(IdentifierType type, string name, WorldId homeWorld, ObjectKind kind, IEnumerable<NpcId> dataIds,
|
||||||
out ActorIdentifier[] identifiers)
|
out ActorIdentifier[] identifiers)
|
||||||
{
|
{
|
||||||
identifiers = Array.Empty<ActorIdentifier>();
|
identifiers = [];
|
||||||
|
|
||||||
var manager = _actorService.AwaitedService;
|
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case IdentifierType.Player:
|
case IdentifierType.Player:
|
||||||
if (!ByteString.FromString(name, out var playerName))
|
if (!ByteString.FromString(name, out var playerName))
|
||||||
return AddResult.Invalid;
|
return AddResult.Invalid;
|
||||||
|
|
||||||
identifiers = new[]
|
identifiers = [_actors.CreatePlayer(playerName, homeWorld)];
|
||||||
{
|
|
||||||
manager.CreatePlayer(playerName, homeWorld),
|
|
||||||
};
|
|
||||||
break;
|
break;
|
||||||
case IdentifierType.Retainer:
|
case IdentifierType.Retainer:
|
||||||
if (!ByteString.FromString(name, out var retainerName))
|
if (!ByteString.FromString(name, out var retainerName))
|
||||||
return AddResult.Invalid;
|
return AddResult.Invalid;
|
||||||
|
|
||||||
identifiers = new[]
|
identifiers = [_actors.CreateRetainer(retainerName, ActorIdentifier.RetainerType.Both)];
|
||||||
{
|
|
||||||
manager.CreateRetainer(retainerName, ActorIdentifier.RetainerType.Both),
|
|
||||||
};
|
|
||||||
break;
|
break;
|
||||||
case IdentifierType.Owned:
|
case IdentifierType.Owned:
|
||||||
if (!ByteString.FromString(name, out var ownerName))
|
if (!ByteString.FromString(name, out var ownerName))
|
||||||
return AddResult.Invalid;
|
return AddResult.Invalid;
|
||||||
|
|
||||||
identifiers = dataIds.Select(id => manager.CreateOwned(ownerName, homeWorld, kind, id)).ToArray();
|
identifiers = dataIds.Select(id => _actors.CreateOwned(ownerName, homeWorld, kind, id)).ToArray();
|
||||||
break;
|
break;
|
||||||
case IdentifierType.Npc:
|
case IdentifierType.Npc:
|
||||||
identifiers = dataIds
|
identifiers = dataIds
|
||||||
.Select(id => manager.CreateIndividual(IdentifierType.Npc, ByteString.Empty, ushort.MaxValue, kind, id)).ToArray();
|
.Select(id => _actors.CreateIndividual(IdentifierType.Npc, ByteString.Empty, ushort.MaxValue, kind, id)).ToArray();
|
||||||
break;
|
|
||||||
default:
|
|
||||||
identifiers = Array.Empty<ActorIdentifier>();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -116,12 +108,22 @@ public sealed partial class IndividualCollections
|
||||||
public ActorIdentifier[] GetGroup(ActorIdentifier identifier)
|
public ActorIdentifier[] GetGroup(ActorIdentifier identifier)
|
||||||
{
|
{
|
||||||
if (!identifier.IsValid)
|
if (!identifier.IsValid)
|
||||||
return Array.Empty<ActorIdentifier>();
|
return [];
|
||||||
|
|
||||||
|
return identifier.Type switch
|
||||||
|
{
|
||||||
|
IdentifierType.Player => [identifier.CreatePermanent()],
|
||||||
|
IdentifierType.Special => [identifier],
|
||||||
|
IdentifierType.Retainer => [identifier.CreatePermanent()],
|
||||||
|
IdentifierType.Owned => CreateNpcs(_actors, identifier.CreatePermanent()),
|
||||||
|
IdentifierType.Npc => CreateNpcs(_actors, identifier),
|
||||||
|
_ => [],
|
||||||
|
};
|
||||||
|
|
||||||
static ActorIdentifier[] CreateNpcs(ActorManager manager, ActorIdentifier identifier)
|
static ActorIdentifier[] CreateNpcs(ActorManager manager, ActorIdentifier identifier)
|
||||||
{
|
{
|
||||||
var name = manager.Data.ToName(identifier.Kind, identifier.DataId);
|
var name = manager.Data.ToName(identifier.Kind, identifier.DataId);
|
||||||
var table = identifier.Kind switch
|
NameDictionary table = identifier.Kind switch
|
||||||
{
|
{
|
||||||
ObjectKind.BattleNpc => manager.Data.BNpcs,
|
ObjectKind.BattleNpc => manager.Data.BNpcs,
|
||||||
ObjectKind.EventNpc => manager.Data.ENpcs,
|
ObjectKind.EventNpc => manager.Data.ENpcs,
|
||||||
|
|
@ -134,25 +136,6 @@ public sealed partial class IndividualCollections
|
||||||
.Select(kvp => manager.CreateIndividualUnchecked(identifier.Type, identifier.PlayerName, identifier.HomeWorld.Id,
|
.Select(kvp => manager.CreateIndividualUnchecked(identifier.Type, identifier.PlayerName, identifier.HomeWorld.Id,
|
||||||
identifier.Kind, kvp.Key)).ToArray();
|
identifier.Kind, kvp.Key)).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
return identifier.Type switch
|
|
||||||
{
|
|
||||||
IdentifierType.Player => new[]
|
|
||||||
{
|
|
||||||
identifier.CreatePermanent(),
|
|
||||||
},
|
|
||||||
IdentifierType.Special => new[]
|
|
||||||
{
|
|
||||||
identifier,
|
|
||||||
},
|
|
||||||
IdentifierType.Retainer => new[]
|
|
||||||
{
|
|
||||||
identifier.CreatePermanent(),
|
|
||||||
},
|
|
||||||
IdentifierType.Owned => CreateNpcs(_actorService.AwaitedService, identifier.CreatePermanent()),
|
|
||||||
IdentifierType.Npc => CreateNpcs(_actorService.AwaitedService, identifier),
|
|
||||||
_ => Array.Empty<ActorIdentifier>(),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal bool Add(ActorIdentifier[] identifiers, ModCollection collection)
|
internal bool Add(ActorIdentifier[] identifiers, ModCollection collection)
|
||||||
|
|
@ -241,12 +224,12 @@ public sealed partial class IndividualCollections
|
||||||
{
|
{
|
||||||
return identifier.Type switch
|
return identifier.Type switch
|
||||||
{
|
{
|
||||||
IdentifierType.Player => $"{identifier.PlayerName} ({_actorService.AwaitedService.Data.ToWorldName(identifier.HomeWorld)})",
|
IdentifierType.Player => $"{identifier.PlayerName} ({_actors.Data.ToWorldName(identifier.HomeWorld)})",
|
||||||
IdentifierType.Retainer => $"{identifier.PlayerName} (Retainer)",
|
IdentifierType.Retainer => $"{identifier.PlayerName} (Retainer)",
|
||||||
IdentifierType.Owned =>
|
IdentifierType.Owned =>
|
||||||
$"{identifier.PlayerName} ({_actorService.AwaitedService.Data.ToWorldName(identifier.HomeWorld)})'s {_actorService.AwaitedService.Data.ToName(identifier.Kind, identifier.DataId)}",
|
$"{identifier.PlayerName} ({_actors.Data.ToWorldName(identifier.HomeWorld)})'s {_actors.Data.ToName(identifier.Kind, identifier.DataId)}",
|
||||||
IdentifierType.Npc =>
|
IdentifierType.Npc =>
|
||||||
$"{_actorService.AwaitedService.Data.ToName(identifier.Kind, identifier.DataId)} ({identifier.Kind.ToName()})",
|
$"{_actors.Data.ToName(identifier.Kind, identifier.DataId)} ({identifier.Kind.ToName()})",
|
||||||
_ => string.Empty,
|
_ => string.Empty,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,10 +14,10 @@ public class TempCollectionManager : IDisposable
|
||||||
|
|
||||||
private readonly CommunicatorService _communicator;
|
private readonly CommunicatorService _communicator;
|
||||||
private readonly CollectionStorage _storage;
|
private readonly CollectionStorage _storage;
|
||||||
private readonly ActorService _actors;
|
private readonly ActorManager _actors;
|
||||||
private readonly Dictionary<string, ModCollection> _customCollections = new();
|
private readonly Dictionary<string, ModCollection> _customCollections = new();
|
||||||
|
|
||||||
public TempCollectionManager(Configuration config, CommunicatorService communicator, ActorService actors, CollectionStorage storage)
|
public TempCollectionManager(Configuration config, CommunicatorService communicator, ActorManager actors, CollectionStorage storage)
|
||||||
{
|
{
|
||||||
_communicator = communicator;
|
_communicator = communicator;
|
||||||
_actors = actors;
|
_actors = actors;
|
||||||
|
|
@ -111,7 +111,7 @@ public class TempCollectionManager : IDisposable
|
||||||
if (!ByteString.FromString(characterName, out var byteString, false))
|
if (!ByteString.FromString(characterName, out var byteString, false))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var identifier = _actors.AwaitedService.CreatePlayer(byteString, worldId);
|
var identifier = _actors.CreatePlayer(byteString, worldId);
|
||||||
if (!identifier.IsValid)
|
if (!identifier.IsValid)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
@ -123,7 +123,7 @@ public class TempCollectionManager : IDisposable
|
||||||
if (!ByteString.FromString(characterName, out var byteString, false))
|
if (!ByteString.FromString(characterName, out var byteString, false))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var identifier = _actors.AwaitedService.CreatePlayer(byteString, worldId);
|
var identifier = _actors.CreatePlayer(byteString, worldId);
|
||||||
return Collections.TryGetValue(identifier, out var collection) && RemoveTemporaryCollection(collection.Name);
|
return Collections.TryGetValue(identifier, out var collection) && RemoveTemporaryCollection(collection.Name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ public class CommandHandler : IDisposable
|
||||||
|
|
||||||
public CommandHandler(IFramework framework, ICommandManager commandManager, IChatGui chat, RedrawService redrawService,
|
public CommandHandler(IFramework framework, ICommandManager commandManager, IChatGui chat, RedrawService redrawService,
|
||||||
Configuration config,
|
Configuration config,
|
||||||
ConfigWindow configWindow, ModManager modManager, CollectionManager collectionManager, ActorService actors, Penumbra penumbra,
|
ConfigWindow configWindow, ModManager modManager, CollectionManager collectionManager, ActorManager actors, Penumbra penumbra,
|
||||||
CollectionEditor collectionEditor)
|
CollectionEditor collectionEditor)
|
||||||
{
|
{
|
||||||
_commandManager = commandManager;
|
_commandManager = commandManager;
|
||||||
|
|
@ -41,7 +41,7 @@ public class CommandHandler : IDisposable
|
||||||
_configWindow = configWindow;
|
_configWindow = configWindow;
|
||||||
_modManager = modManager;
|
_modManager = modManager;
|
||||||
_collectionManager = collectionManager;
|
_collectionManager = collectionManager;
|
||||||
_actors = actors.AwaitedService;
|
_actors = actors;
|
||||||
_chat = chat;
|
_chat = chat;
|
||||||
_penumbra = penumbra;
|
_penumbra = penumbra;
|
||||||
_collectionEditor = collectionEditor;
|
_collectionEditor = collectionEditor;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
using Penumbra.GameData;
|
using Penumbra.GameData;
|
||||||
|
using Penumbra.GameData.Data;
|
||||||
|
|
||||||
namespace Penumbra.Import.Structs;
|
namespace Penumbra.Import.Structs;
|
||||||
|
|
||||||
|
|
@ -47,7 +48,7 @@ public partial struct MetaFileInfo
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
|
|
||||||
public MetaFileInfo(IGamePathParser parser, string fileName)
|
public MetaFileInfo(GamePathParser parser, string fileName)
|
||||||
{
|
{
|
||||||
// Set the primary type from the gamePath start.
|
// Set the primary type from the gamePath start.
|
||||||
PrimaryType = parser.PathToObjectType(fileName);
|
PrimaryType = parser.PathToObjectType(fileName);
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using Penumbra.GameData;
|
using Penumbra.GameData;
|
||||||
|
using Penumbra.GameData.Data;
|
||||||
using Penumbra.Import.Structs;
|
using Penumbra.Import.Structs;
|
||||||
using Penumbra.Meta;
|
using Penumbra.Meta;
|
||||||
using Penumbra.Meta.Manipulations;
|
using Penumbra.Meta.Manipulations;
|
||||||
|
|
@ -28,7 +29,7 @@ public partial class TexToolsMeta
|
||||||
|
|
||||||
private readonly MetaFileManager _metaFileManager;
|
private readonly MetaFileManager _metaFileManager;
|
||||||
|
|
||||||
public TexToolsMeta(MetaFileManager metaFileManager, IGamePathParser parser, byte[] data, bool keepDefault)
|
public TexToolsMeta(MetaFileManager metaFileManager, GamePathParser parser, byte[] data, bool keepDefault)
|
||||||
{
|
{
|
||||||
_metaFileManager = metaFileManager;
|
_metaFileManager = metaFileManager;
|
||||||
_keepDefault = keepDefault;
|
_keepDefault = keepDefault;
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
||||||
using Penumbra.Collections;
|
using Penumbra.Collections;
|
||||||
using Penumbra.Collections.Manager;
|
using Penumbra.Collections.Manager;
|
||||||
using Penumbra.GameData.Actors;
|
using Penumbra.GameData.Actors;
|
||||||
using Penumbra.GameData.Data;
|
using Penumbra.GameData.DataContainers;
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
using Penumbra.Services;
|
using Penumbra.Services;
|
||||||
using Penumbra.Util;
|
using Penumbra.Util;
|
||||||
|
|
@ -21,7 +21,7 @@ public unsafe class CollectionResolver
|
||||||
|
|
||||||
private readonly IClientState _clientState;
|
private readonly IClientState _clientState;
|
||||||
private readonly IGameGui _gameGui;
|
private readonly IGameGui _gameGui;
|
||||||
private readonly ActorService _actors;
|
private readonly ActorManager _actors;
|
||||||
private readonly CutsceneService _cutscenes;
|
private readonly CutsceneService _cutscenes;
|
||||||
|
|
||||||
private readonly Configuration _config;
|
private readonly Configuration _config;
|
||||||
|
|
@ -30,7 +30,7 @@ public unsafe class CollectionResolver
|
||||||
private readonly DrawObjectState _drawObjectState;
|
private readonly DrawObjectState _drawObjectState;
|
||||||
|
|
||||||
public CollectionResolver(PerformanceTracker performance, IdentifiedCollectionCache cache, IClientState clientState, IGameGui gameGui,
|
public CollectionResolver(PerformanceTracker performance, IdentifiedCollectionCache cache, IClientState clientState, IGameGui gameGui,
|
||||||
ActorService actors, CutsceneService cutscenes, Configuration config, CollectionManager collectionManager,
|
ActorManager actors, CutsceneService cutscenes, Configuration config, CollectionManager collectionManager,
|
||||||
TempCollectionManager tempCollections, DrawObjectState drawObjectState, HumanModelList humanModels)
|
TempCollectionManager tempCollections, DrawObjectState drawObjectState, HumanModelList humanModels)
|
||||||
{
|
{
|
||||||
_performance = performance;
|
_performance = performance;
|
||||||
|
|
@ -58,7 +58,7 @@ public unsafe class CollectionResolver
|
||||||
return _collectionManager.Active.ByType(CollectionType.Yourself)
|
return _collectionManager.Active.ByType(CollectionType.Yourself)
|
||||||
?? _collectionManager.Active.Default;
|
?? _collectionManager.Active.Default;
|
||||||
|
|
||||||
var player = _actors.AwaitedService.GetCurrentPlayer();
|
var player = _actors.GetCurrentPlayer();
|
||||||
var _ = false;
|
var _ = false;
|
||||||
return CollectionByIdentifier(player)
|
return CollectionByIdentifier(player)
|
||||||
?? CheckYourself(player, gameObject)
|
?? CheckYourself(player, gameObject)
|
||||||
|
|
@ -147,7 +147,7 @@ public unsafe class CollectionResolver
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var player = _actors.AwaitedService.GetCurrentPlayer();
|
var player = _actors.GetCurrentPlayer();
|
||||||
var notYetReady = false;
|
var notYetReady = false;
|
||||||
var collection = (player.IsValid ? CollectionByIdentifier(player) : null)
|
var collection = (player.IsValid ? CollectionByIdentifier(player) : null)
|
||||||
?? _collectionManager.Active.ByType(CollectionType.Yourself)
|
?? _collectionManager.Active.ByType(CollectionType.Yourself)
|
||||||
|
|
@ -163,7 +163,7 @@ public unsafe class CollectionResolver
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private ResolveData DefaultState(GameObject* gameObject)
|
private ResolveData DefaultState(GameObject* gameObject)
|
||||||
{
|
{
|
||||||
var identifier = _actors.AwaitedService.FromObject(gameObject, out var owner, true, false, false);
|
var identifier = _actors.FromObject(gameObject, out var owner, true, false, false);
|
||||||
if (identifier.Type is IdentifierType.Special)
|
if (identifier.Type is IdentifierType.Special)
|
||||||
{
|
{
|
||||||
(identifier, var type) = _collectionManager.Active.Individuals.ConvertSpecialIdentifier(identifier);
|
(identifier, var type) = _collectionManager.Active.Individuals.ConvertSpecialIdentifier(identifier);
|
||||||
|
|
@ -193,7 +193,7 @@ public unsafe class CollectionResolver
|
||||||
{
|
{
|
||||||
if (actor->ObjectIndex == 0
|
if (actor->ObjectIndex == 0
|
||||||
|| _cutscenes.GetParentIndex(actor->ObjectIndex) == 0
|
|| _cutscenes.GetParentIndex(actor->ObjectIndex) == 0
|
||||||
|| identifier.Equals(_actors.AwaitedService.GetCurrentPlayer()))
|
|| identifier.Equals(_actors.GetCurrentPlayer()))
|
||||||
return _collectionManager.Active.ByType(CollectionType.Yourself);
|
return _collectionManager.Active.ByType(CollectionType.Yourself);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -242,7 +242,7 @@ public unsafe class CollectionResolver
|
||||||
if (identifier.Type != IdentifierType.Owned || !_config.UseOwnerNameForCharacterCollection || owner == null)
|
if (identifier.Type != IdentifierType.Owned || !_config.UseOwnerNameForCharacterCollection || owner == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
var id = _actors.AwaitedService.CreateIndividualUnchecked(IdentifierType.Player, identifier.PlayerName, identifier.HomeWorld.Id,
|
var id = _actors.CreateIndividualUnchecked(IdentifierType.Player, identifier.PlayerName, identifier.HomeWorld.Id,
|
||||||
ObjectKind.None,
|
ObjectKind.None,
|
||||||
uint.MaxValue);
|
uint.MaxValue);
|
||||||
return CheckYourself(id, owner)
|
return CheckYourself(id, owner)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
using Dalamud.Plugin.Services;
|
using Dalamud.Plugin.Services;
|
||||||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||||
using Penumbra.GameData.Actors;
|
using Penumbra.GameData.Enums;
|
||||||
using Penumbra.Interop.Services;
|
using Penumbra.Interop.Services;
|
||||||
|
|
||||||
namespace Penumbra.Interop.PathResolving;
|
namespace Penumbra.Interop.PathResolving;
|
||||||
|
|
@ -45,6 +45,9 @@ public class CutsceneService : IDisposable
|
||||||
|
|
||||||
/// <summary> Return the currently set index of a parent or -1 if none is set or the index is invalid. </summary>
|
/// <summary> Return the currently set index of a parent or -1 if none is set or the index is invalid. </summary>
|
||||||
public int GetParentIndex(int idx)
|
public int GetParentIndex(int idx)
|
||||||
|
=> GetParentIndex((ushort)idx);
|
||||||
|
|
||||||
|
public short GetParentIndex(ushort idx)
|
||||||
{
|
{
|
||||||
if (idx is >= CutsceneStartIdx and < CutsceneEndIdx)
|
if (idx is >= CutsceneStartIdx and < CutsceneEndIdx)
|
||||||
return _copiedCharacters[idx - CutsceneStartIdx];
|
return _copiedCharacters[idx - CutsceneStartIdx];
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ using OtterGui;
|
||||||
using Penumbra.Api.Enums;
|
using Penumbra.Api.Enums;
|
||||||
using Penumbra.Collections;
|
using Penumbra.Collections;
|
||||||
using Penumbra.GameData;
|
using Penumbra.GameData;
|
||||||
|
using Penumbra.GameData.Data;
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
using Penumbra.GameData.Structs;
|
using Penumbra.GameData.Structs;
|
||||||
using Penumbra.String;
|
using Penumbra.String;
|
||||||
|
|
@ -19,7 +20,7 @@ using ModelType = FFXIVClientStructs.FFXIV.Client.Graphics.Scene.CharacterBase.M
|
||||||
|
|
||||||
namespace Penumbra.Interop.ResourceTree;
|
namespace Penumbra.Interop.ResourceTree;
|
||||||
|
|
||||||
internal record GlobalResolveContext(IObjectIdentifier Identifier, ModCollection Collection, TreeBuildCache TreeBuildCache, bool WithUiData)
|
internal record GlobalResolveContext(ObjectIdentification Identifier, ModCollection Collection, TreeBuildCache TreeBuildCache, bool WithUiData)
|
||||||
{
|
{
|
||||||
public readonly Dictionary<(Utf8GamePath, nint), ResourceNode> Nodes = new(128);
|
public readonly Dictionary<(Utf8GamePath, nint), ResourceNode> Nodes = new(128);
|
||||||
|
|
||||||
|
|
@ -28,8 +29,13 @@ internal record GlobalResolveContext(IObjectIdentifier Identifier, ModCollection
|
||||||
=> new(this, characterBase, slotIndex, slot, equipment, weaponType);
|
=> new(this, characterBase, slotIndex, slot, equipment, weaponType);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal partial record ResolveContext(GlobalResolveContext Global, Pointer<CharacterBase> CharacterBase, uint SlotIndex,
|
internal partial record ResolveContext(
|
||||||
EquipSlot Slot, CharacterArmor Equipment, WeaponType WeaponType)
|
GlobalResolveContext Global,
|
||||||
|
Pointer<CharacterBase> CharacterBase,
|
||||||
|
uint SlotIndex,
|
||||||
|
EquipSlot Slot,
|
||||||
|
CharacterArmor Equipment,
|
||||||
|
WeaponType WeaponType)
|
||||||
{
|
{
|
||||||
private static readonly ByteString ShpkPrefix = ByteString.FromSpanUnsafe("shader/sm5/shpk"u8, true, true, true);
|
private static readonly ByteString ShpkPrefix = ByteString.FromSpanUnsafe("shader/sm5/shpk"u8, true, true, true);
|
||||||
|
|
||||||
|
|
@ -152,6 +158,7 @@ internal partial record ResolveContext(GlobalResolveContext Global, Pointer<Char
|
||||||
{
|
{
|
||||||
if (mdl == null || mdl->ModelResourceHandle == null)
|
if (mdl == null || mdl->ModelResourceHandle == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
var mdlResource = mdl->ModelResourceHandle;
|
var mdlResource = mdl->ModelResourceHandle;
|
||||||
|
|
||||||
var path = ResolveModelPath();
|
var path = ResolveModelPath();
|
||||||
|
|
@ -224,6 +231,7 @@ internal partial record ResolveContext(GlobalResolveContext Global, Pointer<Char
|
||||||
shpkNode.Name = "Shader Package";
|
shpkNode.Name = "Shader Package";
|
||||||
node.Children.Add(shpkNode);
|
node.Children.Add(shpkNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
var shpkFile = Global.WithUiData && shpkNode != null ? Global.TreeBuildCache.ReadShaderPackage(shpkNode.FullPath) : null;
|
var shpkFile = Global.WithUiData && shpkNode != null ? Global.TreeBuildCache.ReadShaderPackage(shpkNode.FullPath) : null;
|
||||||
var shpk = Global.WithUiData && shpkNode != null ? (ShaderPackage*)shpkNode.ObjectAddress : null;
|
var shpk = Global.WithUiData && shpkNode != null ? (ShaderPackage*)shpkNode.ObjectAddress : null;
|
||||||
|
|
||||||
|
|
@ -255,7 +263,7 @@ internal partial record ResolveContext(GlobalResolveContext Global, Pointer<Char
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
texNode = texNode.Clone();
|
texNode = texNode.Clone();
|
||||||
texNode.Name = name ?? $"Texture #{i}";
|
texNode.Name = name ?? $"Texture #{i}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -310,13 +318,13 @@ internal partial record ResolveContext(GlobalResolveContext Global, Pointer<Char
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal ResourceNode.UiData GuessModelUIData(Utf8GamePath gamePath)
|
internal ResourceNode.UiData GuessModelUiData(Utf8GamePath gamePath)
|
||||||
{
|
{
|
||||||
var path = gamePath.ToString().Split('/', StringSplitOptions.RemoveEmptyEntries);
|
var path = gamePath.ToString().Split('/', StringSplitOptions.RemoveEmptyEntries);
|
||||||
// Weapons intentionally left out.
|
// Weapons intentionally left out.
|
||||||
var isEquipment = SafeGet(path, 0) == "chara" && SafeGet(path, 1) is "accessory" or "equipment";
|
var isEquipment = SafeGet(path, 0) == "chara" && SafeGet(path, 1) is "accessory" or "equipment";
|
||||||
if (isEquipment)
|
if (isEquipment)
|
||||||
foreach (var item in Global.Identifier.Identify(Equipment.Set, Equipment.Variant, Slot.ToSlot()))
|
foreach (var item in Global.Identifier.Identify(Equipment.Set, 0, Equipment.Variant, Slot.ToSlot()))
|
||||||
{
|
{
|
||||||
var name = Slot switch
|
var name = Slot switch
|
||||||
{
|
{
|
||||||
|
|
@ -324,11 +332,11 @@ internal partial record ResolveContext(GlobalResolveContext Global, Pointer<Char
|
||||||
EquipSlot.LFinger => "L: ",
|
EquipSlot.LFinger => "L: ",
|
||||||
_ => string.Empty,
|
_ => string.Empty,
|
||||||
}
|
}
|
||||||
+ item.Name.ToString();
|
+ item.Name;
|
||||||
return new ResourceNode.UiData(name, ChangedItemDrawer.GetCategoryIcon(item.Name, item));
|
return new ResourceNode.UiData(name, ChangedItemDrawer.GetCategoryIcon(item.Name, item));
|
||||||
}
|
}
|
||||||
|
|
||||||
var dataFromPath = GuessUIDataFromPath(gamePath);
|
var dataFromPath = GuessUiDataFromPath(gamePath);
|
||||||
if (dataFromPath.Name != null)
|
if (dataFromPath.Name != null)
|
||||||
return dataFromPath;
|
return dataFromPath;
|
||||||
|
|
||||||
|
|
@ -337,7 +345,7 @@ internal partial record ResolveContext(GlobalResolveContext Global, Pointer<Char
|
||||||
: new ResourceNode.UiData(null, ChangedItemDrawer.ChangedItemIcon.Unknown);
|
: new ResourceNode.UiData(null, ChangedItemDrawer.ChangedItemIcon.Unknown);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal ResourceNode.UiData GuessUIDataFromPath(Utf8GamePath gamePath)
|
internal ResourceNode.UiData GuessUiDataFromPath(Utf8GamePath gamePath)
|
||||||
{
|
{
|
||||||
foreach (var obj in Global.Identifier.Identify(gamePath.ToString()))
|
foreach (var obj in Global.Identifier.Identify(gamePath.ToString()))
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -3,24 +3,25 @@ using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
||||||
using Penumbra.Api.Enums;
|
using Penumbra.Api.Enums;
|
||||||
using Penumbra.Collections;
|
using Penumbra.Collections;
|
||||||
using Penumbra.GameData.Actors;
|
using Penumbra.GameData.Actors;
|
||||||
|
using Penumbra.GameData.Data;
|
||||||
|
using Penumbra.GameData.Enums;
|
||||||
using Penumbra.Interop.PathResolving;
|
using Penumbra.Interop.PathResolving;
|
||||||
using Penumbra.Services;
|
|
||||||
using Penumbra.String.Classes;
|
using Penumbra.String.Classes;
|
||||||
|
|
||||||
namespace Penumbra.Interop.ResourceTree;
|
namespace Penumbra.Interop.ResourceTree;
|
||||||
|
|
||||||
public class ResourceTreeFactory
|
public class ResourceTreeFactory
|
||||||
{
|
{
|
||||||
private readonly IDataManager _gameData;
|
private readonly IDataManager _gameData;
|
||||||
private readonly IObjectTable _objects;
|
private readonly IObjectTable _objects;
|
||||||
private readonly CollectionResolver _collectionResolver;
|
private readonly CollectionResolver _collectionResolver;
|
||||||
private readonly IdentifierService _identifier;
|
private readonly ObjectIdentification _identifier;
|
||||||
private readonly Configuration _config;
|
private readonly Configuration _config;
|
||||||
private readonly ActorService _actors;
|
private readonly ActorManager _actors;
|
||||||
private readonly PathState _pathState;
|
private readonly PathState _pathState;
|
||||||
|
|
||||||
public ResourceTreeFactory(IDataManager gameData, IObjectTable objects, CollectionResolver resolver, IdentifierService identifier,
|
public ResourceTreeFactory(IDataManager gameData, IObjectTable objects, CollectionResolver resolver, ObjectIdentification identifier,
|
||||||
Configuration config, ActorService actors, PathState pathState)
|
Configuration config, ActorManager actors, PathState pathState)
|
||||||
{
|
{
|
||||||
_gameData = gameData;
|
_gameData = gameData;
|
||||||
_objects = objects;
|
_objects = objects;
|
||||||
|
|
@ -88,12 +89,13 @@ public class ResourceTreeFactory
|
||||||
var networked = character.ObjectId != Dalamud.Game.ClientState.Objects.Types.GameObject.InvalidGameObjectId;
|
var networked = character.ObjectId != Dalamud.Game.ClientState.Objects.Types.GameObject.InvalidGameObjectId;
|
||||||
var tree = new ResourceTree(name, character.ObjectIndex, (nint)gameObjStruct, (nint)drawObjStruct, localPlayerRelated, related,
|
var tree = new ResourceTree(name, character.ObjectIndex, (nint)gameObjStruct, (nint)drawObjStruct, localPlayerRelated, related,
|
||||||
networked, collectionResolveData.ModCollection.Name);
|
networked, collectionResolveData.ModCollection.Name);
|
||||||
var globalContext = new GlobalResolveContext(_identifier.AwaitedService, collectionResolveData.ModCollection,
|
var globalContext = new GlobalResolveContext(_identifier, collectionResolveData.ModCollection,
|
||||||
cache, (flags & Flags.WithUiData) != 0);
|
cache, (flags & Flags.WithUiData) != 0);
|
||||||
using (var _ = _pathState.EnterInternalResolve())
|
using (var _ = _pathState.EnterInternalResolve())
|
||||||
{
|
{
|
||||||
tree.LoadResources(globalContext);
|
tree.LoadResources(globalContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
tree.FlatNodes.UnionWith(globalContext.Nodes.Values);
|
tree.FlatNodes.UnionWith(globalContext.Nodes.Values);
|
||||||
tree.ProcessPostfix((node, _) => tree.FlatNodes.Add(node));
|
tree.ProcessPostfix((node, _) => tree.FlatNodes.Add(node));
|
||||||
|
|
||||||
|
|
@ -161,9 +163,9 @@ public class ResourceTreeFactory
|
||||||
var gamePath = node.PossibleGamePaths[0];
|
var gamePath = node.PossibleGamePaths[0];
|
||||||
node.SetUiData(node.Type switch
|
node.SetUiData(node.Type switch
|
||||||
{
|
{
|
||||||
ResourceType.Imc => node.ResolveContext!.GuessModelUIData(gamePath).PrependName("IMC: "),
|
ResourceType.Imc => node.ResolveContext!.GuessModelUiData(gamePath).PrependName("IMC: "),
|
||||||
ResourceType.Mdl => node.ResolveContext!.GuessModelUIData(gamePath),
|
ResourceType.Mdl => node.ResolveContext!.GuessModelUiData(gamePath),
|
||||||
_ => node.ResolveContext!.GuessUIDataFromPath(gamePath),
|
_ => node.ResolveContext!.GuessUiDataFromPath(gamePath),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -215,7 +217,7 @@ public class ResourceTreeFactory
|
||||||
private unsafe (string Name, bool PlayerRelated) GetCharacterName(Dalamud.Game.ClientState.Objects.Types.Character character,
|
private unsafe (string Name, bool PlayerRelated) GetCharacterName(Dalamud.Game.ClientState.Objects.Types.Character character,
|
||||||
TreeBuildCache cache)
|
TreeBuildCache cache)
|
||||||
{
|
{
|
||||||
var identifier = _actors.AwaitedService.FromObject((GameObject*)character.Address, out var owner, true, false, false);
|
var identifier = _actors.FromObject((GameObject*)character.Address, out var owner, true, false, false);
|
||||||
switch (identifier.Type)
|
switch (identifier.Type)
|
||||||
{
|
{
|
||||||
case IdentifierType.Player: return (identifier.PlayerName.ToString(), true);
|
case IdentifierType.Player: return (identifier.PlayerName.ToString(), true);
|
||||||
|
|
|
||||||
|
|
@ -1,36 +1,26 @@
|
||||||
using Dalamud.Game.ClientState.Objects.Types;
|
using Dalamud.Game.ClientState.Objects.Types;
|
||||||
using Dalamud.Plugin.Services;
|
using Dalamud.Plugin.Services;
|
||||||
using Penumbra.GameData.Actors;
|
using Penumbra.GameData.Actors;
|
||||||
|
using Penumbra.GameData.Enums;
|
||||||
using Penumbra.GameData.Files;
|
using Penumbra.GameData.Files;
|
||||||
using Penumbra.GameData.Structs;
|
using Penumbra.GameData.Structs;
|
||||||
using Penumbra.Services;
|
|
||||||
using Penumbra.String;
|
using Penumbra.String;
|
||||||
using Penumbra.String.Classes;
|
using Penumbra.String.Classes;
|
||||||
|
|
||||||
namespace Penumbra.Interop.ResourceTree;
|
namespace Penumbra.Interop.ResourceTree;
|
||||||
|
|
||||||
internal readonly struct TreeBuildCache
|
internal readonly struct TreeBuildCache(IObjectTable objects, IDataManager dataManager, ActorManager actors)
|
||||||
{
|
{
|
||||||
private readonly IDataManager _dataManager;
|
private readonly Dictionary<FullPath, ShpkFile?> _shaderPackages = [];
|
||||||
private readonly ActorService _actors;
|
|
||||||
private readonly Dictionary<FullPath, ShpkFile?> _shaderPackages = new();
|
|
||||||
private readonly IObjectTable _objects;
|
|
||||||
|
|
||||||
public TreeBuildCache(IObjectTable objects, IDataManager dataManager, ActorService actors)
|
|
||||||
{
|
|
||||||
_dataManager = dataManager;
|
|
||||||
_objects = objects;
|
|
||||||
_actors = actors;
|
|
||||||
}
|
|
||||||
|
|
||||||
public unsafe bool IsLocalPlayerRelated(Character character)
|
public unsafe bool IsLocalPlayerRelated(Character character)
|
||||||
{
|
{
|
||||||
var player = _objects[0];
|
var player = objects[0];
|
||||||
if (player == null)
|
if (player == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var gameObject = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)character.Address;
|
var gameObject = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)character.Address;
|
||||||
var parent = _actors.AwaitedService.ToCutsceneParent(gameObject->ObjectIndex);
|
var parent = actors.ToCutsceneParent(gameObject->ObjectIndex);
|
||||||
var actualIndex = parent >= 0 ? (ushort)parent : gameObject->ObjectIndex;
|
var actualIndex = parent >= 0 ? (ushort)parent : gameObject->ObjectIndex;
|
||||||
return actualIndex switch
|
return actualIndex switch
|
||||||
{
|
{
|
||||||
|
|
@ -41,38 +31,38 @@ internal readonly struct TreeBuildCache
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<Character> GetCharacters()
|
public IEnumerable<Character> GetCharacters()
|
||||||
=> _objects.OfType<Character>();
|
=> objects.OfType<Character>();
|
||||||
|
|
||||||
public IEnumerable<Character> GetLocalPlayerRelatedCharacters()
|
public IEnumerable<Character> GetLocalPlayerRelatedCharacters()
|
||||||
{
|
{
|
||||||
var player = _objects[0];
|
var player = objects[0];
|
||||||
if (player == null)
|
if (player == null)
|
||||||
yield break;
|
yield break;
|
||||||
|
|
||||||
yield return (Character)player;
|
yield return (Character)player;
|
||||||
|
|
||||||
var minion = _objects[1];
|
var minion = objects[1];
|
||||||
if (minion != null)
|
if (minion != null)
|
||||||
yield return (Character)minion;
|
yield return (Character)minion;
|
||||||
|
|
||||||
var playerId = player.ObjectId;
|
var playerId = player.ObjectId;
|
||||||
for (var i = 2; i < ObjectIndex.CutsceneStart.Index; i += 2)
|
for (var i = 2; i < ObjectIndex.CutsceneStart.Index; i += 2)
|
||||||
{
|
{
|
||||||
if (_objects[i] is Character owned && owned.OwnerId == playerId)
|
if (objects[i] is Character owned && owned.OwnerId == playerId)
|
||||||
yield return owned;
|
yield return owned;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = ObjectIndex.CutsceneStart.Index; i < ObjectIndex.CharacterScreen.Index; ++i)
|
for (var i = ObjectIndex.CutsceneStart.Index; i < ObjectIndex.CharacterScreen.Index; ++i)
|
||||||
{
|
{
|
||||||
var character = _objects[i] as Character;
|
var character = objects[i] as Character;
|
||||||
if (character == null)
|
if (character == null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var parent = _actors.AwaitedService.ToCutsceneParent(i);
|
var parent = actors.ToCutsceneParent(i);
|
||||||
if (parent < 0)
|
if (parent < 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (parent is 0 or 1 || _objects[parent]?.OwnerId == playerId)
|
if (parent is 0 or 1 || objects[parent]?.OwnerId == playerId)
|
||||||
yield return character;
|
yield return character;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -85,11 +75,11 @@ internal readonly struct TreeBuildCache
|
||||||
|
|
||||||
private unsafe bool GetOwnedId(ByteString playerName, uint playerId, int idx, [NotNullWhen(true)] out Character? character)
|
private unsafe bool GetOwnedId(ByteString playerName, uint playerId, int idx, [NotNullWhen(true)] out Character? character)
|
||||||
{
|
{
|
||||||
character = _objects[idx] as Character;
|
character = objects[idx] as Character;
|
||||||
if (character == null)
|
if (character == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var actorId = _actors.AwaitedService.FromObject(character, out var owner, true, true, true);
|
var actorId = actors.FromObject(character, out var owner, true, true, true);
|
||||||
if (!actorId.IsValid)
|
if (!actorId.IsValid)
|
||||||
return false;
|
return false;
|
||||||
if (owner != null && owner->OwnerID != playerId)
|
if (owner != null && owner->OwnerID != playerId)
|
||||||
|
|
@ -102,7 +92,7 @@ internal readonly struct TreeBuildCache
|
||||||
|
|
||||||
/// <summary> Try to read a shpk file from the given path and cache it on success. </summary>
|
/// <summary> Try to read a shpk file from the given path and cache it on success. </summary>
|
||||||
public ShpkFile? ReadShaderPackage(FullPath path)
|
public ShpkFile? ReadShaderPackage(FullPath path)
|
||||||
=> ReadFile(_dataManager, path, _shaderPackages, bytes => new ShpkFile(bytes));
|
=> ReadFile(dataManager, path, _shaderPackages, bytes => new ShpkFile(bytes));
|
||||||
|
|
||||||
private static T? ReadFile<T>(IDataManager dataManager, FullPath path, Dictionary<FullPath, T?> cache, Func<byte[], T> parseFile)
|
private static T? ReadFile<T>(IDataManager dataManager, FullPath path, Dictionary<FullPath, T?> cache, Func<byte[], T> parseFile)
|
||||||
where T : class
|
where T : class
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ using FFXIVClientStructs.Interop;
|
||||||
using Penumbra.Api;
|
using Penumbra.Api;
|
||||||
using Penumbra.Api.Enums;
|
using Penumbra.Api.Enums;
|
||||||
using Penumbra.GameData;
|
using Penumbra.GameData;
|
||||||
using Penumbra.GameData.Actors;
|
using Penumbra.GameData.Enums;
|
||||||
using Penumbra.Interop.Structs;
|
using Penumbra.Interop.Structs;
|
||||||
using Character = FFXIVClientStructs.FFXIV.Client.Game.Character.Character;
|
using Character = FFXIVClientStructs.FFXIV.Client.Game.Character.Character;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ using OtterGui.Compression;
|
||||||
using Penumbra.Collections;
|
using Penumbra.Collections;
|
||||||
using Penumbra.Collections.Manager;
|
using Penumbra.Collections.Manager;
|
||||||
using Penumbra.GameData;
|
using Penumbra.GameData;
|
||||||
|
using Penumbra.GameData.Data;
|
||||||
using Penumbra.Import;
|
using Penumbra.Import;
|
||||||
using Penumbra.Interop.Services;
|
using Penumbra.Interop.Services;
|
||||||
using Penumbra.Interop.Structs;
|
using Penumbra.Interop.Structs;
|
||||||
|
|
@ -24,11 +25,11 @@ public unsafe class MetaFileManager
|
||||||
internal readonly IDataManager GameData;
|
internal readonly IDataManager GameData;
|
||||||
internal readonly ActiveCollectionData ActiveCollections;
|
internal readonly ActiveCollectionData ActiveCollections;
|
||||||
internal readonly ValidityChecker ValidityChecker;
|
internal readonly ValidityChecker ValidityChecker;
|
||||||
internal readonly IdentifierService Identifier;
|
internal readonly ObjectIdentification Identifier;
|
||||||
internal readonly FileCompactor Compactor;
|
internal readonly FileCompactor Compactor;
|
||||||
|
|
||||||
public MetaFileManager(CharacterUtility characterUtility, ResidentResourceManager residentResources, IDataManager gameData,
|
public MetaFileManager(CharacterUtility characterUtility, ResidentResourceManager residentResources, IDataManager gameData,
|
||||||
ActiveCollectionData activeCollections, Configuration config, ValidityChecker validityChecker, IdentifierService identifier,
|
ActiveCollectionData activeCollections, Configuration config, ValidityChecker validityChecker, ObjectIdentification identifier,
|
||||||
FileCompactor compactor, IGameInteropProvider interop)
|
FileCompactor compactor, IGameInteropProvider interop)
|
||||||
{
|
{
|
||||||
CharacterUtility = characterUtility;
|
CharacterUtility = characterUtility;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
using Penumbra.Api.Enums;
|
using Penumbra.Api.Enums;
|
||||||
using Penumbra.GameData;
|
|
||||||
using Penumbra.GameData.Data;
|
using Penumbra.GameData.Data;
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
using Penumbra.GameData.Files;
|
using Penumbra.GameData.Files;
|
||||||
|
|
@ -41,7 +40,7 @@ public static class EquipmentSwap
|
||||||
: Array.Empty<EquipSlot>();
|
: Array.Empty<EquipSlot>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static EquipItem[] CreateTypeSwap(MetaFileManager manager, IObjectIdentifier identifier, List<Swap> swaps,
|
public static EquipItem[] CreateTypeSwap(MetaFileManager manager, ObjectIdentification identifier, List<Swap> swaps,
|
||||||
Func<Utf8GamePath, FullPath> redirections, Func<MetaManipulation, MetaManipulation> manips,
|
Func<Utf8GamePath, FullPath> redirections, Func<MetaManipulation, MetaManipulation> manips,
|
||||||
EquipSlot slotFrom, EquipItem itemFrom, EquipSlot slotTo, EquipItem itemTo)
|
EquipSlot slotFrom, EquipItem itemFrom, EquipSlot slotTo, EquipItem itemTo)
|
||||||
{
|
{
|
||||||
|
|
@ -99,7 +98,7 @@ public static class EquipmentSwap
|
||||||
return affectedItems;
|
return affectedItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static EquipItem[] CreateItemSwap(MetaFileManager manager, IObjectIdentifier identifier, List<Swap> swaps,
|
public static EquipItem[] CreateItemSwap(MetaFileManager manager, ObjectIdentification identifier, List<Swap> swaps,
|
||||||
Func<Utf8GamePath, FullPath> redirections, Func<MetaManipulation, MetaManipulation> manips, EquipItem itemFrom,
|
Func<Utf8GamePath, FullPath> redirections, Func<MetaManipulation, MetaManipulation> manips, EquipItem itemFrom,
|
||||||
EquipItem itemTo, bool rFinger = true, bool lFinger = true)
|
EquipItem itemTo, bool rFinger = true, bool lFinger = true)
|
||||||
{
|
{
|
||||||
|
|
@ -247,7 +246,7 @@ public static class EquipmentSwap
|
||||||
variant = i.Variant;
|
variant = i.Variant;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static (ImcFile, Variant[], EquipItem[]) GetVariants(MetaFileManager manager, IObjectIdentifier identifier, EquipSlot slotFrom,
|
private static (ImcFile, Variant[], EquipItem[]) GetVariants(MetaFileManager manager, ObjectIdentification identifier, EquipSlot slotFrom,
|
||||||
SetId idFrom, SetId idTo, Variant variantFrom)
|
SetId idFrom, SetId idTo, Variant variantFrom)
|
||||||
{
|
{
|
||||||
var entry = new ImcManipulation(slotFrom, variantFrom.Id, idFrom, default);
|
var entry = new ImcManipulation(slotFrom, variantFrom.Id, idFrom, default);
|
||||||
|
|
@ -256,11 +255,8 @@ public static class EquipmentSwap
|
||||||
Variant[] variants;
|
Variant[] variants;
|
||||||
if (idFrom == idTo)
|
if (idFrom == idTo)
|
||||||
{
|
{
|
||||||
items = identifier.Identify(idFrom, variantFrom, slotFrom).ToArray();
|
items = identifier.Identify(idFrom, 0, variantFrom, slotFrom).ToArray();
|
||||||
variants = new[]
|
variants = [variantFrom];
|
||||||
{
|
|
||||||
variantFrom,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
using Lumina.Excel.GeneratedSheets;
|
|
||||||
using Penumbra.Collections;
|
using Penumbra.Collections;
|
||||||
|
using Penumbra.GameData.Data;
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
using Penumbra.GameData.Structs;
|
using Penumbra.GameData.Structs;
|
||||||
using Penumbra.Meta.Manipulations;
|
using Penumbra.Meta.Manipulations;
|
||||||
|
|
@ -7,17 +7,16 @@ using Penumbra.String.Classes;
|
||||||
using Penumbra.Meta;
|
using Penumbra.Meta;
|
||||||
using Penumbra.Mods.Manager;
|
using Penumbra.Mods.Manager;
|
||||||
using Penumbra.Mods.Subclasses;
|
using Penumbra.Mods.Subclasses;
|
||||||
using Penumbra.Services;
|
|
||||||
|
|
||||||
namespace Penumbra.Mods.ItemSwap;
|
namespace Penumbra.Mods.ItemSwap;
|
||||||
|
|
||||||
public class ItemSwapContainer
|
public class ItemSwapContainer
|
||||||
{
|
{
|
||||||
private readonly MetaFileManager _manager;
|
private readonly MetaFileManager _manager;
|
||||||
private readonly IdentifierService _identifier;
|
private readonly ObjectIdentification _identifier;
|
||||||
|
|
||||||
private Dictionary<Utf8GamePath, FullPath> _modRedirections = new();
|
private Dictionary<Utf8GamePath, FullPath> _modRedirections = [];
|
||||||
private HashSet<MetaManipulation> _modManipulations = new();
|
private HashSet<MetaManipulation> _modManipulations = [];
|
||||||
|
|
||||||
public IReadOnlyDictionary<Utf8GamePath, FullPath> ModRedirections
|
public IReadOnlyDictionary<Utf8GamePath, FullPath> ModRedirections
|
||||||
=> _modRedirections;
|
=> _modRedirections;
|
||||||
|
|
@ -25,7 +24,7 @@ public class ItemSwapContainer
|
||||||
public IReadOnlySet<MetaManipulation> ModManipulations
|
public IReadOnlySet<MetaManipulation> ModManipulations
|
||||||
=> _modManipulations;
|
=> _modManipulations;
|
||||||
|
|
||||||
public readonly List<Swap> Swaps = new();
|
public readonly List<Swap> Swaps = [];
|
||||||
|
|
||||||
public bool Loaded { get; private set; }
|
public bool Loaded { get; private set; }
|
||||||
|
|
||||||
|
|
@ -107,7 +106,7 @@ public class ItemSwapContainer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ItemSwapContainer(MetaFileManager manager, IdentifierService identifier)
|
public ItemSwapContainer(MetaFileManager manager, ObjectIdentification identifier)
|
||||||
{
|
{
|
||||||
_manager = manager;
|
_manager = manager;
|
||||||
_identifier = identifier;
|
_identifier = identifier;
|
||||||
|
|
@ -130,7 +129,7 @@ public class ItemSwapContainer
|
||||||
{
|
{
|
||||||
Swaps.Clear();
|
Swaps.Clear();
|
||||||
Loaded = false;
|
Loaded = false;
|
||||||
var ret = EquipmentSwap.CreateItemSwap(_manager, _identifier.AwaitedService, Swaps, PathResolver(collection), MetaResolver(collection),
|
var ret = EquipmentSwap.CreateItemSwap(_manager, _identifier, Swaps, PathResolver(collection), MetaResolver(collection),
|
||||||
from, to, useRightRing, useLeftRing);
|
from, to, useRightRing, useLeftRing);
|
||||||
Loaded = true;
|
Loaded = true;
|
||||||
return ret;
|
return ret;
|
||||||
|
|
@ -140,7 +139,7 @@ public class ItemSwapContainer
|
||||||
{
|
{
|
||||||
Swaps.Clear();
|
Swaps.Clear();
|
||||||
Loaded = false;
|
Loaded = false;
|
||||||
var ret = EquipmentSwap.CreateTypeSwap(_manager, _identifier.AwaitedService, Swaps, PathResolver(collection), MetaResolver(collection),
|
var ret = EquipmentSwap.CreateTypeSwap(_manager, _identifier, Swaps, PathResolver(collection), MetaResolver(collection),
|
||||||
slotFrom, from, slotTo, to);
|
slotFrom, from, slotTo, to);
|
||||||
Loaded = true;
|
Loaded = true;
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
using Penumbra.Communication;
|
using Penumbra.Communication;
|
||||||
using Penumbra.GameData;
|
|
||||||
using Penumbra.GameData.Data;
|
using Penumbra.GameData.Data;
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
using Penumbra.Meta.Manipulations;
|
using Penumbra.Meta.Manipulations;
|
||||||
|
|
@ -9,11 +8,12 @@ namespace Penumbra.Mods.Manager;
|
||||||
|
|
||||||
public class ModCacheManager : IDisposable
|
public class ModCacheManager : IDisposable
|
||||||
{
|
{
|
||||||
private readonly CommunicatorService _communicator;
|
private readonly CommunicatorService _communicator;
|
||||||
private readonly IdentifierService _identifier;
|
private readonly ObjectIdentification _identifier;
|
||||||
private readonly ModStorage _modManager;
|
private readonly ModStorage _modManager;
|
||||||
|
private bool _updatingItems = false;
|
||||||
|
|
||||||
public ModCacheManager(CommunicatorService communicator, IdentifierService identifier, ModStorage modStorage)
|
public ModCacheManager(CommunicatorService communicator, ObjectIdentification identifier, ModStorage modStorage)
|
||||||
{
|
{
|
||||||
_communicator = communicator;
|
_communicator = communicator;
|
||||||
_identifier = identifier;
|
_identifier = identifier;
|
||||||
|
|
@ -23,8 +23,7 @@ public class ModCacheManager : IDisposable
|
||||||
_communicator.ModPathChanged.Subscribe(OnModPathChange, ModPathChanged.Priority.ModCacheManager);
|
_communicator.ModPathChanged.Subscribe(OnModPathChange, ModPathChanged.Priority.ModCacheManager);
|
||||||
_communicator.ModDataChanged.Subscribe(OnModDataChange, ModDataChanged.Priority.ModCacheManager);
|
_communicator.ModDataChanged.Subscribe(OnModDataChange, ModDataChanged.Priority.ModCacheManager);
|
||||||
_communicator.ModDiscoveryFinished.Subscribe(OnModDiscoveryFinished, ModDiscoveryFinished.Priority.ModCacheManager);
|
_communicator.ModDiscoveryFinished.Subscribe(OnModDiscoveryFinished, ModDiscoveryFinished.Priority.ModCacheManager);
|
||||||
if (!identifier.Valid)
|
identifier.Awaiter.ContinueWith(_ => OnIdentifierCreation());
|
||||||
identifier.FinishedCreation += OnIdentifierCreation;
|
|
||||||
OnModDiscoveryFinished();
|
OnModDiscoveryFinished();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -37,7 +36,7 @@ public class ModCacheManager : IDisposable
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Compute the items changed by a given meta manipulation and put them into the changedItems dictionary. </summary>
|
/// <summary> Compute the items changed by a given meta manipulation and put them into the changedItems dictionary. </summary>
|
||||||
public static void ComputeChangedItems(IObjectIdentifier identifier, IDictionary<string, object?> changedItems, MetaManipulation manip)
|
public static void ComputeChangedItems(ObjectIdentification identifier, IDictionary<string, object?> changedItems, MetaManipulation manip)
|
||||||
{
|
{
|
||||||
switch (manip.ManipulationType)
|
switch (manip.ManipulationType)
|
||||||
{
|
{
|
||||||
|
|
@ -155,10 +154,7 @@ public class ModCacheManager : IDisposable
|
||||||
=> Parallel.ForEach(_modManager, Refresh);
|
=> Parallel.ForEach(_modManager, Refresh);
|
||||||
|
|
||||||
private void OnIdentifierCreation()
|
private void OnIdentifierCreation()
|
||||||
{
|
=> Parallel.ForEach(_modManager, UpdateChangedItems);
|
||||||
Parallel.ForEach(_modManager, UpdateChangedItems);
|
|
||||||
_identifier.FinishedCreation -= OnIdentifierCreation;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void UpdateFileCount(Mod mod)
|
private static void UpdateFileCount(Mod mod)
|
||||||
=> mod.TotalFileCount = mod.AllSubMods.Sum(s => s.Files.Count);
|
=> mod.TotalFileCount = mod.AllSubMods.Sum(s => s.Files.Count);
|
||||||
|
|
@ -177,18 +173,23 @@ public class ModCacheManager : IDisposable
|
||||||
|
|
||||||
private void UpdateChangedItems(Mod mod)
|
private void UpdateChangedItems(Mod mod)
|
||||||
{
|
{
|
||||||
|
if (_updatingItems)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_updatingItems = true;
|
||||||
var changedItems = (SortedList<string, object?>)mod.ChangedItems;
|
var changedItems = (SortedList<string, object?>)mod.ChangedItems;
|
||||||
changedItems.Clear();
|
changedItems.Clear();
|
||||||
if (!_identifier.Valid)
|
if (!_identifier.Awaiter.IsCompletedSuccessfully)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
foreach (var gamePath in mod.AllSubMods.SelectMany(m => m.Files.Keys.Concat(m.FileSwaps.Keys)))
|
foreach (var gamePath in mod.AllSubMods.SelectMany(m => m.Files.Keys.Concat(m.FileSwaps.Keys)))
|
||||||
_identifier.AwaitedService.Identify(changedItems, gamePath.ToString());
|
_identifier.Identify(changedItems, gamePath.ToString());
|
||||||
|
|
||||||
foreach (var manip in mod.AllSubMods.SelectMany(m => m.Manipulations))
|
foreach (var manip in mod.AllSubMods.SelectMany(m => m.Manipulations))
|
||||||
ComputeChangedItems(_identifier.AwaitedService, changedItems, manip);
|
ComputeChangedItems(_identifier, changedItems, manip);
|
||||||
|
|
||||||
mod.LowerChangedItemsString = string.Join("\0", mod.ChangedItems.Keys.Select(k => k.ToLowerInvariant()));
|
mod.LowerChangedItemsString = string.Join("\0", mod.ChangedItems.Keys.Select(k => k.ToLowerInvariant()));
|
||||||
|
_updatingItems = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void UpdateCounts(Mod mod)
|
private static void UpdateCounts(Mod mod)
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ using OtterGui;
|
||||||
using OtterGui.Classes;
|
using OtterGui.Classes;
|
||||||
using OtterGui.Filesystem;
|
using OtterGui.Filesystem;
|
||||||
using Penumbra.Api.Enums;
|
using Penumbra.Api.Enums;
|
||||||
using Penumbra.GameData;
|
using Penumbra.GameData.Data;
|
||||||
using Penumbra.Import;
|
using Penumbra.Import;
|
||||||
using Penumbra.Import.Structs;
|
using Penumbra.Import.Structs;
|
||||||
using Penumbra.Meta;
|
using Penumbra.Meta;
|
||||||
|
|
@ -17,7 +17,7 @@ using Penumbra.String.Classes;
|
||||||
namespace Penumbra.Mods;
|
namespace Penumbra.Mods;
|
||||||
|
|
||||||
public partial class ModCreator(SaveService _saveService, Configuration config, ModDataEditor _dataEditor, MetaFileManager _metaFileManager,
|
public partial class ModCreator(SaveService _saveService, Configuration config, ModDataEditor _dataEditor, MetaFileManager _metaFileManager,
|
||||||
IGamePathParser _gamePathParser)
|
GamePathParser _gamePathParser)
|
||||||
{
|
{
|
||||||
public readonly Configuration Config = config;
|
public readonly Configuration Config = config;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using Dalamud.Plugin;
|
using Dalamud.Plugin;
|
||||||
|
using Dalamud.Plugin.Services;
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
using Lumina.Excel.GeneratedSheets;
|
using Lumina.Excel.GeneratedSheets;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
@ -6,7 +7,6 @@ using OtterGui;
|
||||||
using OtterGui.Log;
|
using OtterGui.Log;
|
||||||
using Penumbra.Api;
|
using Penumbra.Api;
|
||||||
using Penumbra.Api.Enums;
|
using Penumbra.Api.Enums;
|
||||||
using Penumbra.Util;
|
|
||||||
using Penumbra.Collections;
|
using Penumbra.Collections;
|
||||||
using Penumbra.Collections.Cache;
|
using Penumbra.Collections.Cache;
|
||||||
using Penumbra.Interop.ResourceLoading;
|
using Penumbra.Interop.ResourceLoading;
|
||||||
|
|
@ -19,6 +19,7 @@ using Penumbra.UI.Tabs;
|
||||||
using ChangedItemClick = Penumbra.Communication.ChangedItemClick;
|
using ChangedItemClick = Penumbra.Communication.ChangedItemClick;
|
||||||
using ChangedItemHover = Penumbra.Communication.ChangedItemHover;
|
using ChangedItemHover = Penumbra.Communication.ChangedItemHover;
|
||||||
using OtterGui.Tasks;
|
using OtterGui.Tasks;
|
||||||
|
using Penumbra.GameData.Data;
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
using Penumbra.Interop.Structs;
|
using Penumbra.Interop.Structs;
|
||||||
using Penumbra.UI;
|
using Penumbra.UI;
|
||||||
|
|
@ -31,7 +32,7 @@ public class Penumbra : IDalamudPlugin
|
||||||
public string Name
|
public string Name
|
||||||
=> "Penumbra";
|
=> "Penumbra";
|
||||||
|
|
||||||
public static readonly Logger Log = new();
|
public static readonly Logger Log = new();
|
||||||
public static MessageService Messager { get; private set; } = null!;
|
public static MessageService Messager { get; private set; } = null!;
|
||||||
|
|
||||||
private readonly ValidityChecker _validityChecker;
|
private readonly ValidityChecker _validityChecker;
|
||||||
|
|
@ -53,10 +54,8 @@ public class Penumbra : IDalamudPlugin
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var startTimer = new StartTracker();
|
_services = ServiceManager.CreateProvider(this, pluginInterface, Log);
|
||||||
using var timer = startTimer.Measure(StartTimeType.Total);
|
Messager = _services.GetRequiredService<MessageService>();
|
||||||
_services = ServiceManager.CreateProvider(this, pluginInterface, Log, startTimer);
|
|
||||||
Messager = _services.GetRequiredService<MessageService>();
|
|
||||||
_validityChecker = _services.GetRequiredService<ValidityChecker>();
|
_validityChecker = _services.GetRequiredService<ValidityChecker>();
|
||||||
var startup = _services.GetRequiredService<DalamudServices>().GetDalamudConfig(DalamudServices.WaitingForPluginsOption, out bool s)
|
var startup = _services.GetRequiredService<DalamudServices>().GetDalamudConfig(DalamudServices.WaitingForPluginsOption, out bool s)
|
||||||
? s.ToString()
|
? s.ToString()
|
||||||
|
|
@ -74,14 +73,11 @@ public class Penumbra : IDalamudPlugin
|
||||||
_tempCollections = _services.GetRequiredService<TempCollectionManager>();
|
_tempCollections = _services.GetRequiredService<TempCollectionManager>();
|
||||||
_redrawService = _services.GetRequiredService<RedrawService>();
|
_redrawService = _services.GetRequiredService<RedrawService>();
|
||||||
_communicatorService = _services.GetRequiredService<CommunicatorService>();
|
_communicatorService = _services.GetRequiredService<CommunicatorService>();
|
||||||
_services.GetRequiredService<ResourceService>(); // Initialize because not required anywhere else.
|
_services.GetRequiredService<ResourceService>(); // Initialize because not required anywhere else.
|
||||||
_services.GetRequiredService<ModCacheManager>(); // Initialize because not required anywhere else.
|
_services.GetRequiredService<ModCacheManager>(); // Initialize because not required anywhere else.
|
||||||
_services.GetRequiredService<ModelResourceHandleUtility>(); // Initialize because not required anywhere else.
|
_services.GetRequiredService<ModelResourceHandleUtility>(); // Initialize because not required anywhere else.
|
||||||
_collectionManager.Caches.CreateNecessaryCaches();
|
_collectionManager.Caches.CreateNecessaryCaches();
|
||||||
using (var t = _services.GetRequiredService<StartTracker>().Measure(StartTimeType.PathResolver))
|
_services.GetRequiredService<PathResolver>();
|
||||||
{
|
|
||||||
_services.GetRequiredService<PathResolver>();
|
|
||||||
}
|
|
||||||
|
|
||||||
_services.GetRequiredService<SkinFixer>();
|
_services.GetRequiredService<SkinFixer>();
|
||||||
|
|
||||||
|
|
@ -108,8 +104,7 @@ public class Penumbra : IDalamudPlugin
|
||||||
|
|
||||||
private void SetupApi()
|
private void SetupApi()
|
||||||
{
|
{
|
||||||
using var timer = _services.GetRequiredService<StartTracker>().Measure(StartTimeType.Api);
|
var api = _services.GetRequiredService<IPenumbraApi>();
|
||||||
var api = _services.GetRequiredService<IPenumbraApi>();
|
|
||||||
_services.GetRequiredService<PenumbraIpcProviders>();
|
_services.GetRequiredService<PenumbraIpcProviders>();
|
||||||
_communicatorService.ChangedItemHover.Subscribe(it =>
|
_communicatorService.ChangedItemHover.Subscribe(it =>
|
||||||
{
|
{
|
||||||
|
|
@ -128,8 +123,7 @@ public class Penumbra : IDalamudPlugin
|
||||||
{
|
{
|
||||||
AsyncTask.Run(() =>
|
AsyncTask.Run(() =>
|
||||||
{
|
{
|
||||||
using var tInterface = _services.GetRequiredService<StartTracker>().Measure(StartTimeType.Interface);
|
var system = _services.GetRequiredService<PenumbraWindowSystem>();
|
||||||
var system = _services.GetRequiredService<PenumbraWindowSystem>();
|
|
||||||
system.Window.Setup(this, _services.GetRequiredService<ConfigTabBar>());
|
system.Window.Setup(this, _services.GetRequiredService<ConfigTabBar>());
|
||||||
_services.GetRequiredService<CommandHandler>();
|
_services.GetRequiredService<CommandHandler>();
|
||||||
if (!_disposed)
|
if (!_disposed)
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,13 @@
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using OtterGui.Classes;
|
using OtterGui.Classes;
|
||||||
using OtterGui.Log;
|
using OtterGui.Log;
|
||||||
using Penumbra.Util;
|
|
||||||
|
|
||||||
namespace Penumbra.Services;
|
namespace Penumbra.Services;
|
||||||
|
|
||||||
public class BackupService
|
public class BackupService
|
||||||
{
|
{
|
||||||
public BackupService(Logger logger, StartTracker timer, FilenameService fileNames)
|
public BackupService(Logger logger, FilenameService fileNames)
|
||||||
{
|
{
|
||||||
using var t = timer.Measure(StartTimeType.Backup);
|
|
||||||
var files = PenumbraFiles(fileNames);
|
var files = PenumbraFiles(fileNames);
|
||||||
Backup.CreateAutomaticBackup(logger, new DirectoryInfo(fileNames.ConfigDirectory), files);
|
Backup.CreateAutomaticBackup(logger, new DirectoryInfo(fileNames.ConfigDirectory), files);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,10 @@ using Penumbra.Api;
|
||||||
using Penumbra.Collections.Cache;
|
using Penumbra.Collections.Cache;
|
||||||
using Penumbra.Collections.Manager;
|
using Penumbra.Collections.Manager;
|
||||||
using Penumbra.GameData;
|
using Penumbra.GameData;
|
||||||
|
using Penumbra.GameData.Actors;
|
||||||
using Penumbra.GameData.Data;
|
using Penumbra.GameData.Data;
|
||||||
|
using Penumbra.GameData.DataContainers;
|
||||||
|
using Penumbra.GameData.DataContainers.Bases;
|
||||||
using Penumbra.Import.Textures;
|
using Penumbra.Import.Textures;
|
||||||
using Penumbra.Interop.PathResolving;
|
using Penumbra.Interop.PathResolving;
|
||||||
using Penumbra.Interop.ResourceLoading;
|
using Penumbra.Interop.ResourceLoading;
|
||||||
|
|
@ -24,17 +27,17 @@ using Penumbra.UI.Classes;
|
||||||
using Penumbra.UI.ModsTab;
|
using Penumbra.UI.ModsTab;
|
||||||
using Penumbra.UI.ResourceWatcher;
|
using Penumbra.UI.ResourceWatcher;
|
||||||
using Penumbra.UI.Tabs;
|
using Penumbra.UI.Tabs;
|
||||||
|
using Penumbra.UI.Tabs.Debug;
|
||||||
using ResidentResourceManager = Penumbra.Interop.Services.ResidentResourceManager;
|
using ResidentResourceManager = Penumbra.Interop.Services.ResidentResourceManager;
|
||||||
|
|
||||||
namespace Penumbra.Services;
|
namespace Penumbra.Services;
|
||||||
|
|
||||||
public static class ServiceManager
|
public static class ServiceManager
|
||||||
{
|
{
|
||||||
public static ServiceProvider CreateProvider(Penumbra penumbra, DalamudPluginInterface pi, Logger log, StartTracker startTimer)
|
public static ServiceProvider CreateProvider(Penumbra penumbra, DalamudPluginInterface pi, Logger log)
|
||||||
{
|
{
|
||||||
var services = new ServiceCollection()
|
var services = new ServiceCollection()
|
||||||
.AddSingleton(log)
|
.AddSingleton(log)
|
||||||
.AddSingleton(startTimer)
|
|
||||||
.AddSingleton(penumbra)
|
.AddSingleton(penumbra)
|
||||||
.AddDalamud(pi)
|
.AddDalamud(pi)
|
||||||
.AddMeta()
|
.AddMeta()
|
||||||
|
|
@ -47,7 +50,9 @@ public static class ServiceManager
|
||||||
.AddResolvers()
|
.AddResolvers()
|
||||||
.AddInterface()
|
.AddInterface()
|
||||||
.AddModEditor()
|
.AddModEditor()
|
||||||
.AddApi();
|
.AddApi()
|
||||||
|
.AddDataContainers()
|
||||||
|
.AddAsyncServices();
|
||||||
|
|
||||||
return services.BuildServiceProvider(new ServiceProviderOptions { ValidateOnBuild = true });
|
return services.BuildServiceProvider(new ServiceProviderOptions { ValidateOnBuild = true });
|
||||||
}
|
}
|
||||||
|
|
@ -59,6 +64,22 @@ public static class ServiceManager
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static IServiceCollection AddDataContainers(this IServiceCollection services)
|
||||||
|
{
|
||||||
|
foreach (var type in typeof(IDataContainer).Assembly.GetExportedTypes()
|
||||||
|
.Where(t => t is { IsAbstract: false, IsInterface: false } && t.IsAssignableTo(typeof(IDataContainer))))
|
||||||
|
services.AddSingleton(type);
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IServiceCollection AddAsyncServices(this IServiceCollection services)
|
||||||
|
{
|
||||||
|
foreach (var type in typeof(IDataContainer).Assembly.GetExportedTypes()
|
||||||
|
.Where(t => t is { IsAbstract: false, IsInterface: false } && t.IsAssignableTo(typeof(IAsyncService))))
|
||||||
|
services.AddSingleton(type);
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
private static IServiceCollection AddMeta(this IServiceCollection services)
|
private static IServiceCollection AddMeta(this IServiceCollection services)
|
||||||
=> services.AddSingleton<ValidityChecker>()
|
=> services.AddSingleton<ValidityChecker>()
|
||||||
.AddSingleton<PerformanceTracker>()
|
.AddSingleton<PerformanceTracker>()
|
||||||
|
|
@ -71,17 +92,19 @@ public static class ServiceManager
|
||||||
|
|
||||||
|
|
||||||
private static IServiceCollection AddGameData(this IServiceCollection services)
|
private static IServiceCollection AddGameData(this IServiceCollection services)
|
||||||
=> services.AddSingleton<IGamePathParser, GamePathParser>()
|
=> services.AddSingleton<GamePathParser>()
|
||||||
.AddSingleton<IdentifierService>()
|
|
||||||
.AddSingleton<StainService>()
|
.AddSingleton<StainService>()
|
||||||
.AddSingleton<ItemService>()
|
|
||||||
.AddSingleton<ActorService>()
|
|
||||||
.AddSingleton<HumanModelList>();
|
.AddSingleton<HumanModelList>();
|
||||||
|
|
||||||
private static IServiceCollection AddInterop(this IServiceCollection services)
|
private static IServiceCollection AddInterop(this IServiceCollection services)
|
||||||
=> services.AddSingleton<GameEventManager>()
|
=> services.AddSingleton<GameEventManager>()
|
||||||
.AddSingleton<FrameworkManager>()
|
.AddSingleton<FrameworkManager>()
|
||||||
.AddSingleton<CutsceneService>()
|
.AddSingleton<CutsceneService>()
|
||||||
|
.AddSingleton(p =>
|
||||||
|
{
|
||||||
|
var cutsceneService = p.GetRequiredService<CutsceneService>();
|
||||||
|
return new CutsceneResolver(cutsceneService.GetParentIndex);
|
||||||
|
})
|
||||||
.AddSingleton<CharacterUtility>()
|
.AddSingleton<CharacterUtility>()
|
||||||
.AddSingleton<ResourceManagerService>()
|
.AddSingleton<ResourceManagerService>()
|
||||||
.AddSingleton<ResourceService>()
|
.AddSingleton<ResourceService>()
|
||||||
|
|
@ -173,7 +196,8 @@ public static class ServiceManager
|
||||||
.AddSingleton<ResourceWatcher>()
|
.AddSingleton<ResourceWatcher>()
|
||||||
.AddSingleton<ItemSwapTab>()
|
.AddSingleton<ItemSwapTab>()
|
||||||
.AddSingleton<ModMergeTab>()
|
.AddSingleton<ModMergeTab>()
|
||||||
.AddSingleton<ChangedItemDrawer>();
|
.AddSingleton<ChangedItemDrawer>()
|
||||||
|
.AddSingleton(p => new Diagnostics(p));
|
||||||
|
|
||||||
private static IServiceCollection AddModEditor(this IServiceCollection services)
|
private static IServiceCollection AddModEditor(this IServiceCollection services)
|
||||||
=> services.AddSingleton<ModFileCollection>()
|
=> services.AddSingleton<ModFileCollection>()
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
using OtterGui.Tasks;
|
using OtterGui.Tasks;
|
||||||
using Penumbra.Util;
|
|
||||||
|
|
||||||
namespace Penumbra.Services;
|
namespace Penumbra.Services;
|
||||||
|
|
||||||
|
|
@ -12,10 +11,9 @@ public abstract class SyncServiceWrapper<T> : IDisposable
|
||||||
public bool Valid
|
public bool Valid
|
||||||
=> !_isDisposed;
|
=> !_isDisposed;
|
||||||
|
|
||||||
protected SyncServiceWrapper(string name, StartTracker tracker, StartTimeType type, Func<T> factory)
|
protected SyncServiceWrapper(string name, Func<T> factory)
|
||||||
{
|
{
|
||||||
Name = name;
|
Name = name;
|
||||||
using var timer = tracker.Measure(type);
|
|
||||||
Service = factory();
|
Service = factory();
|
||||||
Penumbra.Log.Verbose($"[{Name}] Created.");
|
Penumbra.Log.Verbose($"[{Name}] Created.");
|
||||||
}
|
}
|
||||||
|
|
@ -54,32 +52,6 @@ public abstract class AsyncServiceWrapper<T> : IDisposable
|
||||||
|
|
||||||
private bool _isDisposed;
|
private bool _isDisposed;
|
||||||
|
|
||||||
protected AsyncServiceWrapper(string name, StartTracker tracker, StartTimeType type, Func<T> factory)
|
|
||||||
{
|
|
||||||
Name = name;
|
|
||||||
_task = TrackedTask.Run(() =>
|
|
||||||
{
|
|
||||||
using var timer = tracker.Measure(type);
|
|
||||||
var service = factory();
|
|
||||||
if (_isDisposed)
|
|
||||||
{
|
|
||||||
if (service is IDisposable d)
|
|
||||||
d.Dispose();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Service = service;
|
|
||||||
Penumbra.Log.Verbose($"[{Name}] Created.");
|
|
||||||
_task = null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
_task.ContinueWith((t, x) =>
|
|
||||||
{
|
|
||||||
if (!_isDisposed)
|
|
||||||
FinishedCreation?.Invoke();
|
|
||||||
}, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected AsyncServiceWrapper(string name, Func<T> factory)
|
protected AsyncServiceWrapper(string name, Func<T> factory)
|
||||||
{
|
{
|
||||||
Name = name;
|
Name = name;
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ using Dalamud.Plugin;
|
||||||
using Dalamud.Plugin.Services;
|
using Dalamud.Plugin.Services;
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
using OtterGui.Widgets;
|
using OtterGui.Widgets;
|
||||||
using Penumbra.GameData.Data;
|
using Penumbra.GameData.DataContainers;
|
||||||
using Penumbra.GameData.Files;
|
using Penumbra.GameData.Files;
|
||||||
using Penumbra.UI.AdvancedWindow;
|
using Penumbra.UI.AdvancedWindow;
|
||||||
using Penumbra.Util;
|
using Penumbra.Util;
|
||||||
|
|
@ -71,17 +71,16 @@ public class StainService : IDisposable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly StainData StainData;
|
public readonly DictStains StainData;
|
||||||
public readonly FilterComboColors StainCombo;
|
public readonly FilterComboColors StainCombo;
|
||||||
public readonly StmFile StmFile;
|
public readonly StmFile StmFile;
|
||||||
public readonly StainTemplateCombo TemplateCombo;
|
public readonly StainTemplateCombo TemplateCombo;
|
||||||
|
|
||||||
public StainService(StartTracker timer, DalamudPluginInterface pluginInterface, IDataManager dataManager, IPluginLog dalamudLog)
|
public StainService(DalamudPluginInterface pluginInterface, IDataManager dataManager, IPluginLog dalamudLog)
|
||||||
{
|
{
|
||||||
using var t = timer.Measure(StartTimeType.Stains);
|
StainData = new DictStains(pluginInterface, dalamudLog, dataManager);
|
||||||
StainData = new StainData(pluginInterface, dataManager, dataManager.Language, dalamudLog);
|
|
||||||
StainCombo = new FilterComboColors(140,
|
StainCombo = new FilterComboColors(140,
|
||||||
() => StainData.Data.Prepend(new KeyValuePair<byte, (string Name, uint Dye, bool Gloss)>(0, ("None", 0, false))).ToList(),
|
() => StainData.Value.Prepend(new KeyValuePair<byte, (string Name, uint Dye, bool Gloss)>(0, ("None", 0, false))).ToList(),
|
||||||
Penumbra.Log);
|
Penumbra.Log);
|
||||||
StmFile = new StmFile(dataManager);
|
StmFile = new StmFile(dataManager);
|
||||||
TemplateCombo = new StainTemplateCombo(StainCombo, StmFile);
|
TemplateCombo = new StainTemplateCombo(StainCombo, StmFile);
|
||||||
|
|
|
||||||
|
|
@ -1,34 +0,0 @@
|
||||||
using Dalamud.Game;
|
|
||||||
using Dalamud.Plugin;
|
|
||||||
using Dalamud.Plugin.Services;
|
|
||||||
using Penumbra.GameData;
|
|
||||||
using Penumbra.GameData.Actors;
|
|
||||||
using Penumbra.GameData.Data;
|
|
||||||
using Penumbra.Interop.PathResolving;
|
|
||||||
using Penumbra.Util;
|
|
||||||
|
|
||||||
namespace Penumbra.Services;
|
|
||||||
|
|
||||||
public sealed class IdentifierService : AsyncServiceWrapper<IObjectIdentifier>
|
|
||||||
{
|
|
||||||
public IdentifierService(StartTracker tracker, DalamudPluginInterface pi, IDataManager data, ItemService items, IPluginLog log)
|
|
||||||
: base(nameof(IdentifierService), tracker, StartTimeType.Identifier,
|
|
||||||
() => GameData.GameData.GetIdentifier(pi, data, items.AwaitedService, log))
|
|
||||||
{ }
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class ItemService : AsyncServiceWrapper<ItemData>
|
|
||||||
{
|
|
||||||
public ItemService(StartTracker tracker, DalamudPluginInterface pi, IDataManager gameData, IPluginLog log)
|
|
||||||
: base(nameof(ItemService), tracker, StartTimeType.Items, () => new ItemData(pi, gameData, gameData.Language, log))
|
|
||||||
{ }
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class ActorService : AsyncServiceWrapper<ActorManager>
|
|
||||||
{
|
|
||||||
public ActorService(StartTracker tracker, DalamudPluginInterface pi, IObjectTable objects, IClientState clientState,
|
|
||||||
IFramework framework, IDataManager gameData, IGameGui gui, CutsceneService cutscene, IPluginLog log, IGameInteropProvider interop)
|
|
||||||
: base(nameof(ActorService), tracker, StartTimeType.Actors,
|
|
||||||
() => new ActorManager(pi, objects, clientState, framework, interop, gameData, gui, idx => (short)cutscene.GetParentIndex(idx), log))
|
|
||||||
{ }
|
|
||||||
}
|
|
||||||
|
|
@ -1,8 +1,5 @@
|
||||||
using Dalamud.Interface;
|
|
||||||
using Dalamud.Interface.Internal.Notifications;
|
using Dalamud.Interface.Internal.Notifications;
|
||||||
using Dalamud.Utility;
|
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
using Lumina.Excel.GeneratedSheets;
|
|
||||||
using OtterGui;
|
using OtterGui;
|
||||||
using OtterGui.Classes;
|
using OtterGui.Classes;
|
||||||
using OtterGui.Raii;
|
using OtterGui.Raii;
|
||||||
|
|
@ -11,6 +8,7 @@ using Penumbra.Api.Enums;
|
||||||
using Penumbra.Collections;
|
using Penumbra.Collections;
|
||||||
using Penumbra.Collections.Manager;
|
using Penumbra.Collections.Manager;
|
||||||
using Penumbra.Communication;
|
using Penumbra.Communication;
|
||||||
|
using Penumbra.GameData.Data;
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
using Penumbra.GameData.Structs;
|
using Penumbra.GameData.Structs;
|
||||||
using Penumbra.Meta;
|
using Penumbra.Meta;
|
||||||
|
|
@ -27,16 +25,14 @@ public class ItemSwapTab : IDisposable, ITab
|
||||||
{
|
{
|
||||||
private readonly Configuration _config;
|
private readonly Configuration _config;
|
||||||
private readonly CommunicatorService _communicator;
|
private readonly CommunicatorService _communicator;
|
||||||
private readonly ItemService _itemService;
|
|
||||||
private readonly CollectionManager _collectionManager;
|
private readonly CollectionManager _collectionManager;
|
||||||
private readonly ModManager _modManager;
|
private readonly ModManager _modManager;
|
||||||
private readonly MetaFileManager _metaFileManager;
|
private readonly MetaFileManager _metaFileManager;
|
||||||
|
|
||||||
public ItemSwapTab(CommunicatorService communicator, ItemService itemService, CollectionManager collectionManager,
|
public ItemSwapTab(CommunicatorService communicator, ItemData itemService, CollectionManager collectionManager,
|
||||||
ModManager modManager, IdentifierService identifier, MetaFileManager metaFileManager, Configuration config)
|
ModManager modManager, ObjectIdentification identifier, MetaFileManager metaFileManager, Configuration config)
|
||||||
{
|
{
|
||||||
_communicator = communicator;
|
_communicator = communicator;
|
||||||
_itemService = itemService;
|
|
||||||
_collectionManager = collectionManager;
|
_collectionManager = collectionManager;
|
||||||
_modManager = modManager;
|
_modManager = modManager;
|
||||||
_metaFileManager = metaFileManager;
|
_metaFileManager = metaFileManager;
|
||||||
|
|
@ -46,15 +42,15 @@ public class ItemSwapTab : IDisposable, ITab
|
||||||
_selectors = new Dictionary<SwapType, (ItemSelector Source, ItemSelector Target, string TextFrom, string TextTo)>
|
_selectors = new Dictionary<SwapType, (ItemSelector Source, ItemSelector Target, string TextFrom, string TextTo)>
|
||||||
{
|
{
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
[SwapType.Hat] = (new ItemSelector(_itemService, FullEquipType.Head), new ItemSelector(_itemService, FullEquipType.Head), "Take this Hat", "and put it on this one" ),
|
[SwapType.Hat] = (new ItemSelector(itemService, FullEquipType.Head), new ItemSelector(itemService, FullEquipType.Head), "Take this Hat", "and put it on this one" ),
|
||||||
[SwapType.Top] = (new ItemSelector(_itemService, FullEquipType.Body), new ItemSelector(_itemService, FullEquipType.Body), "Take this Top", "and put it on this one" ),
|
[SwapType.Top] = (new ItemSelector(itemService, FullEquipType.Body), new ItemSelector(itemService, FullEquipType.Body), "Take this Top", "and put it on this one" ),
|
||||||
[SwapType.Gloves] = (new ItemSelector(_itemService, FullEquipType.Hands), new ItemSelector(_itemService, FullEquipType.Hands), "Take these Gloves", "and put them on these" ),
|
[SwapType.Gloves] = (new ItemSelector(itemService, FullEquipType.Hands), new ItemSelector(itemService, FullEquipType.Hands), "Take these Gloves", "and put them on these" ),
|
||||||
[SwapType.Pants] = (new ItemSelector(_itemService, FullEquipType.Legs), new ItemSelector(_itemService, FullEquipType.Legs), "Take these Pants", "and put them on these" ),
|
[SwapType.Pants] = (new ItemSelector(itemService, FullEquipType.Legs), new ItemSelector(itemService, FullEquipType.Legs), "Take these Pants", "and put them on these" ),
|
||||||
[SwapType.Shoes] = (new ItemSelector(_itemService, FullEquipType.Feet), new ItemSelector(_itemService, FullEquipType.Feet), "Take these Shoes", "and put them on these" ),
|
[SwapType.Shoes] = (new ItemSelector(itemService, FullEquipType.Feet), new ItemSelector(itemService, FullEquipType.Feet), "Take these Shoes", "and put them on these" ),
|
||||||
[SwapType.Earrings] = (new ItemSelector(_itemService, FullEquipType.Ears), new ItemSelector(_itemService, FullEquipType.Ears), "Take these Earrings", "and put them on these" ),
|
[SwapType.Earrings] = (new ItemSelector(itemService, FullEquipType.Ears), new ItemSelector(itemService, FullEquipType.Ears), "Take these Earrings", "and put them on these" ),
|
||||||
[SwapType.Necklace] = (new ItemSelector(_itemService, FullEquipType.Neck), new ItemSelector(_itemService, FullEquipType.Neck), "Take this Necklace", "and put it on this one" ),
|
[SwapType.Necklace] = (new ItemSelector(itemService, FullEquipType.Neck), new ItemSelector(itemService, FullEquipType.Neck), "Take this Necklace", "and put it on this one" ),
|
||||||
[SwapType.Bracelet] = (new ItemSelector(_itemService, FullEquipType.Wrists), new ItemSelector(_itemService, FullEquipType.Wrists), "Take these Bracelets", "and put them on these" ),
|
[SwapType.Bracelet] = (new ItemSelector(itemService, FullEquipType.Wrists), new ItemSelector(itemService, FullEquipType.Wrists), "Take these Bracelets", "and put them on these" ),
|
||||||
[SwapType.Ring] = (new ItemSelector(_itemService, FullEquipType.Finger), new ItemSelector(_itemService, FullEquipType.Finger), "Take this Ring", "and put it on this one" ),
|
[SwapType.Ring] = (new ItemSelector(itemService, FullEquipType.Finger), new ItemSelector(itemService, FullEquipType.Finger), "Take this Ring", "and put it on this one" ),
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -131,8 +127,8 @@ public class ItemSwapTab : IDisposable, ITab
|
||||||
|
|
||||||
private class ItemSelector : FilterComboCache<EquipItem>
|
private class ItemSelector : FilterComboCache<EquipItem>
|
||||||
{
|
{
|
||||||
public ItemSelector(ItemService data, FullEquipType type)
|
public ItemSelector(ItemData data, FullEquipType type)
|
||||||
: base(() => data.AwaitedService[type], Penumbra.Log)
|
: base(() => data.ByType[type], Penumbra.Log)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
protected override string ToString(EquipItem obj)
|
protected override string ToString(EquipItem obj)
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ using OtterGui.Classes;
|
||||||
using Penumbra.GameData;
|
using Penumbra.GameData;
|
||||||
using Penumbra.GameData.Data;
|
using Penumbra.GameData.Data;
|
||||||
using Penumbra.GameData.Files;
|
using Penumbra.GameData.Files;
|
||||||
|
using Penumbra.GameData.Interop;
|
||||||
using Penumbra.String;
|
using Penumbra.String;
|
||||||
using static Penumbra.GameData.Files.ShpkFile;
|
using static Penumbra.GameData.Files.ShpkFile;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ using Lumina.Misc;
|
||||||
using OtterGui;
|
using OtterGui;
|
||||||
using Penumbra.GameData.Data;
|
using Penumbra.GameData.Data;
|
||||||
using Penumbra.GameData.Files;
|
using Penumbra.GameData.Files;
|
||||||
|
using Penumbra.GameData.Interop;
|
||||||
|
|
||||||
namespace Penumbra.UI.AdvancedWindow;
|
namespace Penumbra.UI.AdvancedWindow;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ public sealed class CollectionPanel : IDisposable
|
||||||
private readonly CollectionStorage _collections;
|
private readonly CollectionStorage _collections;
|
||||||
private readonly ActiveCollections _active;
|
private readonly ActiveCollections _active;
|
||||||
private readonly CollectionSelector _selector;
|
private readonly CollectionSelector _selector;
|
||||||
private readonly ActorService _actors;
|
private readonly ActorManager _actors;
|
||||||
private readonly ITargetManager _targets;
|
private readonly ITargetManager _targets;
|
||||||
private readonly IndividualAssignmentUi _individualAssignmentUi;
|
private readonly IndividualAssignmentUi _individualAssignmentUi;
|
||||||
private readonly InheritanceUi _inheritanceUi;
|
private readonly InheritanceUi _inheritanceUi;
|
||||||
|
|
@ -37,7 +37,7 @@ public sealed class CollectionPanel : IDisposable
|
||||||
private int _draggedIndividualAssignment = -1;
|
private int _draggedIndividualAssignment = -1;
|
||||||
|
|
||||||
public CollectionPanel(DalamudPluginInterface pi, CommunicatorService communicator, CollectionManager manager,
|
public CollectionPanel(DalamudPluginInterface pi, CommunicatorService communicator, CollectionManager manager,
|
||||||
CollectionSelector selector, ActorService actors, ITargetManager targets, ModStorage mods)
|
CollectionSelector selector, ActorManager actors, ITargetManager targets, ModStorage mods)
|
||||||
{
|
{
|
||||||
_collections = manager.Storage;
|
_collections = manager.Storage;
|
||||||
_active = manager.Active;
|
_active = manager.Active;
|
||||||
|
|
@ -382,11 +382,11 @@ public sealed class CollectionPanel : IDisposable
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawCurrentCharacter(Vector2 width)
|
private void DrawCurrentCharacter(Vector2 width)
|
||||||
=> DrawIndividualButton("Current Character", width, string.Empty, 'c', _actors.AwaitedService.GetCurrentPlayer());
|
=> DrawIndividualButton("Current Character", width, string.Empty, 'c', _actors.GetCurrentPlayer());
|
||||||
|
|
||||||
private void DrawCurrentTarget(Vector2 width)
|
private void DrawCurrentTarget(Vector2 width)
|
||||||
=> DrawIndividualButton("Current Target", width, string.Empty, 't',
|
=> DrawIndividualButton("Current Target", width, string.Empty, 't',
|
||||||
_actors.AwaitedService.FromObject(_targets.Target, false, true, true));
|
_actors.FromObject(_targets.Target, false, true, true));
|
||||||
|
|
||||||
private void DrawNewPlayer(Vector2 width)
|
private void DrawNewPlayer(Vector2 width)
|
||||||
=> DrawIndividualButton("New Player", width, _individualAssignmentUi.PlayerTooltip, 'p',
|
=> DrawIndividualButton("New Player", width, _individualAssignmentUi.PlayerTooltip, 'p',
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,9 @@ using Penumbra.Collections;
|
||||||
using Penumbra.Collections.Manager;
|
using Penumbra.Collections.Manager;
|
||||||
using Penumbra.Communication;
|
using Penumbra.Communication;
|
||||||
using Penumbra.GameData.Actors;
|
using Penumbra.GameData.Actors;
|
||||||
|
using Penumbra.GameData.Enums;
|
||||||
|
using Penumbra.GameData.Gui;
|
||||||
|
using Penumbra.GameData.Structs;
|
||||||
using Penumbra.Services;
|
using Penumbra.Services;
|
||||||
|
|
||||||
namespace Penumbra.UI.CollectionTab;
|
namespace Penumbra.UI.CollectionTab;
|
||||||
|
|
@ -12,7 +15,7 @@ namespace Penumbra.UI.CollectionTab;
|
||||||
public class IndividualAssignmentUi : IDisposable
|
public class IndividualAssignmentUi : IDisposable
|
||||||
{
|
{
|
||||||
private readonly CommunicatorService _communicator;
|
private readonly CommunicatorService _communicator;
|
||||||
private readonly ActorService _actorService;
|
private readonly ActorManager _actors;
|
||||||
private readonly CollectionManager _collectionManager;
|
private readonly CollectionManager _collectionManager;
|
||||||
|
|
||||||
private WorldCombo _worldCombo = null!;
|
private WorldCombo _worldCombo = null!;
|
||||||
|
|
@ -24,16 +27,13 @@ public class IndividualAssignmentUi : IDisposable
|
||||||
|
|
||||||
private bool _ready;
|
private bool _ready;
|
||||||
|
|
||||||
public IndividualAssignmentUi(CommunicatorService communicator, ActorService actors, CollectionManager collectionManager)
|
public IndividualAssignmentUi(CommunicatorService communicator, ActorManager actors, CollectionManager collectionManager)
|
||||||
{
|
{
|
||||||
_communicator = communicator;
|
_communicator = communicator;
|
||||||
_actorService = actors;
|
_actors = actors;
|
||||||
_collectionManager = collectionManager;
|
_collectionManager = collectionManager;
|
||||||
_communicator.CollectionChange.Subscribe(UpdateIdentifiers, CollectionChange.Priority.IndividualAssignmentUi);
|
_communicator.CollectionChange.Subscribe(UpdateIdentifiers, CollectionChange.Priority.IndividualAssignmentUi);
|
||||||
if (_actorService.Valid)
|
_actors.Awaiter.ContinueWith(_ => SetupCombos());
|
||||||
SetupCombos();
|
|
||||||
else
|
|
||||||
_actorService.FinishedCreation += SetupCombos;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public string PlayerTooltip { get; private set; } = NewPlayerTooltipEmpty;
|
public string PlayerTooltip { get; private set; } = NewPlayerTooltipEmpty;
|
||||||
|
|
@ -91,10 +91,10 @@ public class IndividualAssignmentUi : IDisposable
|
||||||
// Input Selections.
|
// Input Selections.
|
||||||
private string _newCharacterName = string.Empty;
|
private string _newCharacterName = string.Empty;
|
||||||
private ObjectKind _newKind = ObjectKind.BattleNpc;
|
private ObjectKind _newKind = ObjectKind.BattleNpc;
|
||||||
private ActorIdentifier[] _playerIdentifiers = Array.Empty<ActorIdentifier>();
|
private ActorIdentifier[] _playerIdentifiers = [];
|
||||||
private ActorIdentifier[] _retainerIdentifiers = Array.Empty<ActorIdentifier>();
|
private ActorIdentifier[] _retainerIdentifiers = [];
|
||||||
private ActorIdentifier[] _npcIdentifiers = Array.Empty<ActorIdentifier>();
|
private ActorIdentifier[] _npcIdentifiers = [];
|
||||||
private ActorIdentifier[] _ownedIdentifiers = Array.Empty<ActorIdentifier>();
|
private ActorIdentifier[] _ownedIdentifiers = [];
|
||||||
|
|
||||||
private const string NewPlayerTooltipEmpty = "Please enter a valid player name and choose an available world or 'Any World'.";
|
private const string NewPlayerTooltipEmpty = "Please enter a valid player name and choose an available world or 'Any World'.";
|
||||||
private const string NewRetainerTooltipEmpty = "Please enter a valid retainer name.";
|
private const string NewRetainerTooltipEmpty = "Please enter a valid retainer name.";
|
||||||
|
|
@ -126,14 +126,13 @@ public class IndividualAssignmentUi : IDisposable
|
||||||
/// <summary> Create combos when ready. </summary>
|
/// <summary> Create combos when ready. </summary>
|
||||||
private void SetupCombos()
|
private void SetupCombos()
|
||||||
{
|
{
|
||||||
_worldCombo = new WorldCombo(_actorService.AwaitedService.Data.Worlds, Penumbra.Log);
|
_worldCombo = new WorldCombo(_actors.Data.Worlds, Penumbra.Log, WorldId.AnyWorld);
|
||||||
_mountCombo = new NpcCombo("##mountCombo", _actorService.AwaitedService.Data.Mounts, Penumbra.Log);
|
_mountCombo = new NpcCombo("##mountCombo", _actors.Data.Mounts, Penumbra.Log);
|
||||||
_companionCombo = new NpcCombo("##companionCombo", _actorService.AwaitedService.Data.Companions, Penumbra.Log);
|
_companionCombo = new NpcCombo("##companionCombo", _actors.Data.Companions, Penumbra.Log);
|
||||||
_ornamentCombo = new NpcCombo("##ornamentCombo", _actorService.AwaitedService.Data.Ornaments, Penumbra.Log);
|
_ornamentCombo = new NpcCombo("##ornamentCombo", _actors.Data.Ornaments, Penumbra.Log);
|
||||||
_bnpcCombo = new NpcCombo("##bnpcCombo", _actorService.AwaitedService.Data.BNpcs, Penumbra.Log);
|
_bnpcCombo = new NpcCombo("##bnpcCombo", _actors.Data.BNpcs, Penumbra.Log);
|
||||||
_enpcCombo = new NpcCombo("##enpcCombo", _actorService.AwaitedService.Data.ENpcs, Penumbra.Log);
|
_enpcCombo = new NpcCombo("##enpcCombo", _actors.Data.ENpcs, Penumbra.Log);
|
||||||
_ready = true;
|
_ready = true;
|
||||||
_actorService.FinishedCreation -= SetupCombos;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateIdentifiers(CollectionType type, ModCollection? _1, ModCollection? _2, string _3)
|
private void UpdateIdentifiers(CollectionType type, ModCollection? _1, ModCollection? _2, string _3)
|
||||||
|
|
@ -146,22 +145,22 @@ public class IndividualAssignmentUi : IDisposable
|
||||||
{
|
{
|
||||||
var combo = GetNpcCombo(_newKind);
|
var combo = GetNpcCombo(_newKind);
|
||||||
PlayerTooltip = _collectionManager.Active.Individuals.CanAdd(IdentifierType.Player, _newCharacterName,
|
PlayerTooltip = _collectionManager.Active.Individuals.CanAdd(IdentifierType.Player, _newCharacterName,
|
||||||
_worldCombo.CurrentSelection.Key, ObjectKind.None,
|
_worldCombo.CurrentSelection.Key, ObjectKind.None, [], out _playerIdentifiers) switch
|
||||||
Array.Empty<uint>(), out _playerIdentifiers) switch
|
|
||||||
{
|
{
|
||||||
_ when _newCharacterName.Length == 0 => NewPlayerTooltipEmpty,
|
_ when _newCharacterName.Length == 0 => NewPlayerTooltipEmpty,
|
||||||
IndividualCollections.AddResult.Invalid => NewPlayerTooltipInvalid,
|
IndividualCollections.AddResult.Invalid => NewPlayerTooltipInvalid,
|
||||||
IndividualCollections.AddResult.AlreadySet => AlreadyAssigned,
|
IndividualCollections.AddResult.AlreadySet => AlreadyAssigned,
|
||||||
_ => string.Empty,
|
_ => string.Empty,
|
||||||
};
|
};
|
||||||
RetainerTooltip = _collectionManager.Active.Individuals.CanAdd(IdentifierType.Retainer, _newCharacterName, 0, ObjectKind.None,
|
RetainerTooltip =
|
||||||
Array.Empty<uint>(), out _retainerIdentifiers) switch
|
_collectionManager.Active.Individuals.CanAdd(IdentifierType.Retainer, _newCharacterName, 0, ObjectKind.None, [],
|
||||||
{
|
out _retainerIdentifiers) switch
|
||||||
_ when _newCharacterName.Length == 0 => NewRetainerTooltipEmpty,
|
{
|
||||||
IndividualCollections.AddResult.Invalid => NewRetainerTooltipInvalid,
|
_ when _newCharacterName.Length == 0 => NewRetainerTooltipEmpty,
|
||||||
IndividualCollections.AddResult.AlreadySet => AlreadyAssigned,
|
IndividualCollections.AddResult.Invalid => NewRetainerTooltipInvalid,
|
||||||
_ => string.Empty,
|
IndividualCollections.AddResult.AlreadySet => AlreadyAssigned,
|
||||||
};
|
_ => string.Empty,
|
||||||
|
};
|
||||||
if (combo.CurrentSelection.Ids != null)
|
if (combo.CurrentSelection.Ids != null)
|
||||||
{
|
{
|
||||||
NpcTooltip = _collectionManager.Active.Individuals.CanAdd(IdentifierType.Npc, string.Empty, ushort.MaxValue, _newKind,
|
NpcTooltip = _collectionManager.Active.Individuals.CanAdd(IdentifierType.Npc, string.Empty, ushort.MaxValue, _newKind,
|
||||||
|
|
@ -184,8 +183,8 @@ public class IndividualAssignmentUi : IDisposable
|
||||||
{
|
{
|
||||||
NpcTooltip = NewNpcTooltipEmpty;
|
NpcTooltip = NewNpcTooltipEmpty;
|
||||||
OwnedTooltip = NewNpcTooltipEmpty;
|
OwnedTooltip = NewNpcTooltipEmpty;
|
||||||
_npcIdentifiers = Array.Empty<ActorIdentifier>();
|
_npcIdentifiers = [];
|
||||||
_ownedIdentifiers = Array.Empty<ActorIdentifier>();
|
_ownedIdentifiers = [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,16 +6,16 @@ using OtterGui.Widgets;
|
||||||
using Penumbra.Api.Enums;
|
using Penumbra.Api.Enums;
|
||||||
using Penumbra.Collections;
|
using Penumbra.Collections;
|
||||||
using Penumbra.GameData.Actors;
|
using Penumbra.GameData.Actors;
|
||||||
|
using Penumbra.GameData.Enums;
|
||||||
using Penumbra.Interop.ResourceLoading;
|
using Penumbra.Interop.ResourceLoading;
|
||||||
using Penumbra.Interop.Structs;
|
using Penumbra.Interop.Structs;
|
||||||
using Penumbra.Services;
|
|
||||||
using Penumbra.String;
|
using Penumbra.String;
|
||||||
using Penumbra.String.Classes;
|
using Penumbra.String.Classes;
|
||||||
using Penumbra.UI.Classes;
|
using Penumbra.UI.Classes;
|
||||||
|
|
||||||
namespace Penumbra.UI.ResourceWatcher;
|
namespace Penumbra.UI.ResourceWatcher;
|
||||||
|
|
||||||
public class ResourceWatcher : IDisposable, ITab
|
public sealed class ResourceWatcher : IDisposable, ITab
|
||||||
{
|
{
|
||||||
public const int DefaultMaxEntries = 1024;
|
public const int DefaultMaxEntries = 1024;
|
||||||
public const RecordType AllRecords = RecordType.Request | RecordType.ResourceLoad | RecordType.FileLoad | RecordType.Destruction;
|
public const RecordType AllRecords = RecordType.Request | RecordType.ResourceLoad | RecordType.FileLoad | RecordType.Destruction;
|
||||||
|
|
@ -24,15 +24,15 @@ public class ResourceWatcher : IDisposable, ITab
|
||||||
private readonly EphemeralConfig _ephemeral;
|
private readonly EphemeralConfig _ephemeral;
|
||||||
private readonly ResourceService _resources;
|
private readonly ResourceService _resources;
|
||||||
private readonly ResourceLoader _loader;
|
private readonly ResourceLoader _loader;
|
||||||
private readonly ActorService _actors;
|
private readonly ActorManager _actors;
|
||||||
private readonly List<Record> _records = new();
|
private readonly List<Record> _records = [];
|
||||||
private readonly ConcurrentQueue<Record> _newRecords = new();
|
private readonly ConcurrentQueue<Record> _newRecords = [];
|
||||||
private readonly ResourceWatcherTable _table;
|
private readonly ResourceWatcherTable _table;
|
||||||
private string _logFilter = string.Empty;
|
private string _logFilter = string.Empty;
|
||||||
private Regex? _logRegex;
|
private Regex? _logRegex;
|
||||||
private int _newMaxEntries;
|
private int _newMaxEntries;
|
||||||
|
|
||||||
public unsafe ResourceWatcher(ActorService actors, Configuration config, ResourceService resources, ResourceLoader loader)
|
public unsafe ResourceWatcher(ActorManager actors, Configuration config, ResourceService resources, ResourceLoader loader)
|
||||||
{
|
{
|
||||||
_actors = actors;
|
_actors = actors;
|
||||||
_config = config;
|
_config = config;
|
||||||
|
|
@ -266,12 +266,12 @@ public class ResourceWatcher : IDisposable, ITab
|
||||||
|
|
||||||
public unsafe string Name(ResolveData resolve, string none = "")
|
public unsafe string Name(ResolveData resolve, string none = "")
|
||||||
{
|
{
|
||||||
if (resolve.AssociatedGameObject == IntPtr.Zero || !_actors.Valid)
|
if (resolve.AssociatedGameObject == IntPtr.Zero || !_actors.Awaiter.IsCompletedSuccessfully)
|
||||||
return none;
|
return none;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var id = _actors.AwaitedService.FromObject((GameObject*)resolve.AssociatedGameObject, out _, false, true, true);
|
var id = _actors.FromObject((GameObject*)resolve.AssociatedGameObject, out _, false, true, true);
|
||||||
if (id.IsValid)
|
if (id.IsValid)
|
||||||
{
|
{
|
||||||
if (id.Type is not (IdentifierType.Player or IdentifierType.Owned))
|
if (id.Type is not (IdentifierType.Player or IdentifierType.Owned))
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ using OtterGui;
|
||||||
using OtterGui.Raii;
|
using OtterGui.Raii;
|
||||||
using OtterGui.Widgets;
|
using OtterGui.Widgets;
|
||||||
using Penumbra.Collections.Manager;
|
using Penumbra.Collections.Manager;
|
||||||
|
using Penumbra.GameData.Actors;
|
||||||
using Penumbra.Mods.Manager;
|
using Penumbra.Mods.Manager;
|
||||||
using Penumbra.Services;
|
using Penumbra.Services;
|
||||||
using Penumbra.UI.Classes;
|
using Penumbra.UI.Classes;
|
||||||
|
|
@ -14,7 +15,7 @@ using Penumbra.UI.CollectionTab;
|
||||||
|
|
||||||
namespace Penumbra.UI.Tabs;
|
namespace Penumbra.UI.Tabs;
|
||||||
|
|
||||||
public class CollectionsTab : IDisposable, ITab
|
public sealed class CollectionsTab : IDisposable, ITab
|
||||||
{
|
{
|
||||||
private readonly EphemeralConfig _config;
|
private readonly EphemeralConfig _config;
|
||||||
private readonly CollectionSelector _selector;
|
private readonly CollectionSelector _selector;
|
||||||
|
|
@ -40,7 +41,7 @@ public class CollectionsTab : IDisposable, ITab
|
||||||
}
|
}
|
||||||
|
|
||||||
public CollectionsTab(DalamudPluginInterface pi, Configuration configuration, CommunicatorService communicator,
|
public CollectionsTab(DalamudPluginInterface pi, Configuration configuration, CommunicatorService communicator,
|
||||||
CollectionManager collectionManager, ModStorage modStorage, ActorService actors, ITargetManager targets, TutorialService tutorial)
|
CollectionManager collectionManager, ModStorage modStorage, ActorManager actors, ITargetManager targets, TutorialService tutorial)
|
||||||
{
|
{
|
||||||
_config = configuration.Ephemeral;
|
_config = configuration.Ephemeral;
|
||||||
_tutorial = tutorial;
|
_tutorial = tutorial;
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ using OtterGui.Widgets;
|
||||||
using Penumbra.Api.Enums;
|
using Penumbra.Api.Enums;
|
||||||
using Penumbra.Mods;
|
using Penumbra.Mods;
|
||||||
using Penumbra.Services;
|
using Penumbra.Services;
|
||||||
|
using Penumbra.UI.Tabs.Debug;
|
||||||
using Watcher = Penumbra.UI.ResourceWatcher.ResourceWatcher;
|
using Watcher = Penumbra.UI.ResourceWatcher.ResourceWatcher;
|
||||||
|
|
||||||
namespace Penumbra.UI.Tabs;
|
namespace Penumbra.UI.Tabs;
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,30 @@
|
||||||
using Dalamud.Interface;
|
using Dalamud.Interface;
|
||||||
using Dalamud.Interface.Utility;
|
using Dalamud.Interface.Utility;
|
||||||
|
using Dalamud.Interface.Utility.Raii;
|
||||||
using Dalamud.Interface.Windowing;
|
using Dalamud.Interface.Windowing;
|
||||||
using Dalamud.Utility;
|
using Dalamud.Utility;
|
||||||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||||
using FFXIVClientStructs.FFXIV.Client.Game.Group;
|
using FFXIVClientStructs.FFXIV.Client.Game.Group;
|
||||||
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
||||||
|
using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel;
|
||||||
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 ImGuiNET;
|
using ImGuiNET;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using OtterGui;
|
using OtterGui;
|
||||||
using OtterGui.Classes;
|
using OtterGui.Classes;
|
||||||
using OtterGui.Widgets;
|
using OtterGui.Widgets;
|
||||||
using Penumbra.Api;
|
using Penumbra.Api;
|
||||||
using Penumbra.Collections.Manager;
|
using Penumbra.Collections.Manager;
|
||||||
using Penumbra.GameData.Actors;
|
using Penumbra.GameData.Actors;
|
||||||
|
using Penumbra.GameData.DataContainers;
|
||||||
|
using Penumbra.GameData.DataContainers.Bases;
|
||||||
using Penumbra.GameData.Files;
|
using Penumbra.GameData.Files;
|
||||||
using Penumbra.Import.Structs;
|
using Penumbra.Import.Structs;
|
||||||
using Penumbra.Import.Textures;
|
using Penumbra.Import.Textures;
|
||||||
using Penumbra.Interop.ResourceLoading;
|
|
||||||
using Penumbra.Interop.PathResolving;
|
using Penumbra.Interop.PathResolving;
|
||||||
|
using Penumbra.Interop.ResourceLoading;
|
||||||
|
using Penumbra.Interop.Services;
|
||||||
using Penumbra.Interop.Structs;
|
using Penumbra.Interop.Structs;
|
||||||
using Penumbra.Mods;
|
using Penumbra.Mods;
|
||||||
using Penumbra.Mods.Manager;
|
using Penumbra.Mods.Manager;
|
||||||
|
|
@ -31,22 +37,39 @@ using CharacterBase = FFXIVClientStructs.FFXIV.Client.Graphics.Scene.CharacterBa
|
||||||
using CharacterUtility = Penumbra.Interop.Services.CharacterUtility;
|
using CharacterUtility = Penumbra.Interop.Services.CharacterUtility;
|
||||||
using ObjectKind = Dalamud.Game.ClientState.Objects.Enums.ObjectKind;
|
using ObjectKind = Dalamud.Game.ClientState.Objects.Enums.ObjectKind;
|
||||||
using ResidentResourceManager = Penumbra.Interop.Services.ResidentResourceManager;
|
using ResidentResourceManager = Penumbra.Interop.Services.ResidentResourceManager;
|
||||||
using Penumbra.Interop.Services;
|
|
||||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel;
|
|
||||||
using ImGuiClip = OtterGui.ImGuiClip;
|
using ImGuiClip = OtterGui.ImGuiClip;
|
||||||
|
|
||||||
namespace Penumbra.UI.Tabs;
|
namespace Penumbra.UI.Tabs.Debug;
|
||||||
|
|
||||||
|
public class Diagnostics(IServiceProvider provider)
|
||||||
|
{
|
||||||
|
public void DrawDiagnostics()
|
||||||
|
{
|
||||||
|
if (!ImGui.CollapsingHeader("Diagnostics"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
using var table = ImRaii.Table("##data", 4, ImGuiTableFlags.RowBg);
|
||||||
|
foreach (var type in typeof(IAsyncDataContainer).Assembly.GetTypes()
|
||||||
|
.Where(t => t is { IsAbstract: false, IsInterface: false } && t.IsAssignableTo(typeof(IAsyncDataContainer))))
|
||||||
|
{
|
||||||
|
var container = (IAsyncDataContainer) provider.GetRequiredService(type);
|
||||||
|
ImGuiUtil.DrawTableColumn(container.Name);
|
||||||
|
ImGuiUtil.DrawTableColumn(container.Time.ToString());
|
||||||
|
ImGuiUtil.DrawTableColumn(Functions.HumanReadableSize(container.Memory));
|
||||||
|
ImGuiUtil.DrawTableColumn(container.TotalCount.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public class DebugTab : Window, ITab
|
public class DebugTab : Window, ITab
|
||||||
{
|
{
|
||||||
private readonly StartTracker _timer;
|
|
||||||
private readonly PerformanceTracker _performance;
|
private readonly PerformanceTracker _performance;
|
||||||
private readonly Configuration _config;
|
private readonly Configuration _config;
|
||||||
private readonly CollectionManager _collectionManager;
|
private readonly CollectionManager _collectionManager;
|
||||||
private readonly ModManager _modManager;
|
private readonly ModManager _modManager;
|
||||||
private readonly ValidityChecker _validityChecker;
|
private readonly ValidityChecker _validityChecker;
|
||||||
private readonly HttpApi _httpApi;
|
private readonly HttpApi _httpApi;
|
||||||
private readonly ActorService _actorService;
|
private readonly ActorManager _actors;
|
||||||
private readonly DalamudServices _dalamud;
|
private readonly DalamudServices _dalamud;
|
||||||
private readonly StainService _stains;
|
private readonly StainService _stains;
|
||||||
private readonly CharacterUtility _characterUtility;
|
private readonly CharacterUtility _characterUtility;
|
||||||
|
|
@ -64,16 +87,17 @@ public class DebugTab : Window, ITab
|
||||||
private readonly FrameworkManager _framework;
|
private readonly FrameworkManager _framework;
|
||||||
private readonly TextureManager _textureManager;
|
private readonly TextureManager _textureManager;
|
||||||
private readonly SkinFixer _skinFixer;
|
private readonly SkinFixer _skinFixer;
|
||||||
private readonly IdentifierService _identifier;
|
|
||||||
private readonly RedrawService _redraws;
|
private readonly RedrawService _redraws;
|
||||||
|
private readonly DictEmotes _emotes;
|
||||||
|
private readonly Diagnostics _diagnostics;
|
||||||
|
|
||||||
public DebugTab(StartTracker timer, PerformanceTracker performance, Configuration config, CollectionManager collectionManager,
|
public DebugTab(PerformanceTracker performance, Configuration config, CollectionManager collectionManager,
|
||||||
ValidityChecker validityChecker, ModManager modManager, HttpApi httpApi, ActorService actorService,
|
ValidityChecker validityChecker, ModManager modManager, HttpApi httpApi, ActorManager actors,
|
||||||
DalamudServices dalamud, StainService stains, CharacterUtility characterUtility, ResidentResourceManager residentResources,
|
DalamudServices dalamud, StainService stains, CharacterUtility characterUtility, ResidentResourceManager residentResources,
|
||||||
ResourceManagerService resourceManager, PenumbraIpcProviders ipc, CollectionResolver collectionResolver,
|
ResourceManagerService resourceManager, PenumbraIpcProviders ipc, CollectionResolver collectionResolver,
|
||||||
DrawObjectState drawObjectState, PathState pathState, SubfileHelper subfileHelper, IdentifiedCollectionCache identifiedCollectionCache,
|
DrawObjectState drawObjectState, PathState pathState, SubfileHelper subfileHelper, IdentifiedCollectionCache identifiedCollectionCache,
|
||||||
CutsceneService cutsceneService, ModImportManager modImporter, ImportPopup importPopup, FrameworkManager framework,
|
CutsceneService cutsceneService, ModImportManager modImporter, ImportPopup importPopup, FrameworkManager framework,
|
||||||
TextureManager textureManager, SkinFixer skinFixer, IdentifierService identifier, RedrawService redraws)
|
TextureManager textureManager, SkinFixer skinFixer, RedrawService redraws, DictEmotes emotes, Diagnostics diagnostics)
|
||||||
: base("Penumbra Debug Window", ImGuiWindowFlags.NoCollapse)
|
: base("Penumbra Debug Window", ImGuiWindowFlags.NoCollapse)
|
||||||
{
|
{
|
||||||
IsOpen = true;
|
IsOpen = true;
|
||||||
|
|
@ -82,14 +106,13 @@ public class DebugTab : Window, ITab
|
||||||
MinimumSize = new Vector2(200, 200),
|
MinimumSize = new Vector2(200, 200),
|
||||||
MaximumSize = new Vector2(2000, 2000),
|
MaximumSize = new Vector2(2000, 2000),
|
||||||
};
|
};
|
||||||
_timer = timer;
|
|
||||||
_performance = performance;
|
_performance = performance;
|
||||||
_config = config;
|
_config = config;
|
||||||
_collectionManager = collectionManager;
|
_collectionManager = collectionManager;
|
||||||
_validityChecker = validityChecker;
|
_validityChecker = validityChecker;
|
||||||
_modManager = modManager;
|
_modManager = modManager;
|
||||||
_httpApi = httpApi;
|
_httpApi = httpApi;
|
||||||
_actorService = actorService;
|
_actors = actors;
|
||||||
_dalamud = dalamud;
|
_dalamud = dalamud;
|
||||||
_stains = stains;
|
_stains = stains;
|
||||||
_characterUtility = characterUtility;
|
_characterUtility = characterUtility;
|
||||||
|
|
@ -107,8 +130,9 @@ public class DebugTab : Window, ITab
|
||||||
_framework = framework;
|
_framework = framework;
|
||||||
_textureManager = textureManager;
|
_textureManager = textureManager;
|
||||||
_skinFixer = skinFixer;
|
_skinFixer = skinFixer;
|
||||||
_identifier = identifier;
|
|
||||||
_redraws = redraws;
|
_redraws = redraws;
|
||||||
|
_emotes = emotes;
|
||||||
|
_diagnostics = diagnostics;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReadOnlySpan<byte> Label
|
public ReadOnlySpan<byte> Label
|
||||||
|
|
@ -130,6 +154,7 @@ public class DebugTab : Window, ITab
|
||||||
return;
|
return;
|
||||||
|
|
||||||
DrawDebugTabGeneral();
|
DrawDebugTabGeneral();
|
||||||
|
_diagnostics.DrawDiagnostics();
|
||||||
DrawPerformanceTab();
|
DrawPerformanceTab();
|
||||||
ImGui.NewLine();
|
ImGui.NewLine();
|
||||||
DrawPathResolverDebug();
|
DrawPathResolverDebug();
|
||||||
|
|
@ -357,7 +382,6 @@ public class DebugTab : Window, ITab
|
||||||
ImGuiUtil.DrawTableColumn(name);
|
ImGuiUtil.DrawTableColumn(name);
|
||||||
ImGui.TableNextColumn();
|
ImGui.TableNextColumn();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -372,10 +396,7 @@ public class DebugTab : Window, ITab
|
||||||
using (var start = TreeNode("Startup Performance", ImGuiTreeNodeFlags.DefaultOpen))
|
using (var start = TreeNode("Startup Performance", ImGuiTreeNodeFlags.DefaultOpen))
|
||||||
{
|
{
|
||||||
if (start)
|
if (start)
|
||||||
{
|
|
||||||
_timer.Draw("##startTimer", TimingExtensions.ToName);
|
|
||||||
ImGui.NewLine();
|
ImGui.NewLine();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_performance.Draw("##performance", "Enable Runtime Performance Tracking", TimingExtensions.ToName);
|
_performance.Draw("##performance", "Enable Runtime Performance Tracking", TimingExtensions.ToName);
|
||||||
|
|
@ -391,22 +412,10 @@ public class DebugTab : Window, ITab
|
||||||
if (!table)
|
if (!table)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
void DrawSpecial(string name, ActorIdentifier id)
|
DrawSpecial("Current Player", _actors.GetCurrentPlayer());
|
||||||
{
|
DrawSpecial("Current Inspect", _actors.GetInspectPlayer());
|
||||||
if (!id.IsValid)
|
DrawSpecial("Current Card", _actors.GetCardPlayer());
|
||||||
return;
|
DrawSpecial("Current Glamour", _actors.GetGlamourPlayer());
|
||||||
|
|
||||||
ImGuiUtil.DrawTableColumn(name);
|
|
||||||
ImGuiUtil.DrawTableColumn(string.Empty);
|
|
||||||
ImGuiUtil.DrawTableColumn(string.Empty);
|
|
||||||
ImGuiUtil.DrawTableColumn(_actorService.AwaitedService.ToString(id));
|
|
||||||
ImGuiUtil.DrawTableColumn(string.Empty);
|
|
||||||
}
|
|
||||||
|
|
||||||
DrawSpecial("Current Player", _actorService.AwaitedService.GetCurrentPlayer());
|
|
||||||
DrawSpecial("Current Inspect", _actorService.AwaitedService.GetInspectPlayer());
|
|
||||||
DrawSpecial("Current Card", _actorService.AwaitedService.GetCardPlayer());
|
|
||||||
DrawSpecial("Current Glamour", _actorService.AwaitedService.GetGlamourPlayer());
|
|
||||||
|
|
||||||
foreach (var obj in _dalamud.Objects)
|
foreach (var obj in _dalamud.Objects)
|
||||||
{
|
{
|
||||||
|
|
@ -415,11 +424,25 @@ public class DebugTab : Window, ITab
|
||||||
ImGuiUtil.DrawTableColumn(obj.Address == nint.Zero
|
ImGuiUtil.DrawTableColumn(obj.Address == nint.Zero
|
||||||
? string.Empty
|
? string.Empty
|
||||||
: $"0x{(nint)((Character*)obj.Address)->GameObject.GetDrawObject():X}");
|
: $"0x{(nint)((Character*)obj.Address)->GameObject.GetDrawObject():X}");
|
||||||
var identifier = _actorService.AwaitedService.FromObject(obj, false, true, false);
|
var identifier = _actors.FromObject(obj, false, true, false);
|
||||||
ImGuiUtil.DrawTableColumn(_actorService.AwaitedService.ToString(identifier));
|
ImGuiUtil.DrawTableColumn(_actors.ToString(identifier));
|
||||||
var id = obj.ObjectKind == ObjectKind.BattleNpc ? $"{identifier.DataId} | {obj.DataId}" : identifier.DataId.ToString();
|
var id = obj.ObjectKind == ObjectKind.BattleNpc ? $"{identifier.DataId} | {obj.DataId}" : identifier.DataId.ToString();
|
||||||
ImGuiUtil.DrawTableColumn(id);
|
ImGuiUtil.DrawTableColumn(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
void DrawSpecial(string name, ActorIdentifier id)
|
||||||
|
{
|
||||||
|
if (!id.IsValid)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ImGuiUtil.DrawTableColumn(name);
|
||||||
|
ImGuiUtil.DrawTableColumn(string.Empty);
|
||||||
|
ImGuiUtil.DrawTableColumn(string.Empty);
|
||||||
|
ImGuiUtil.DrawTableColumn(_actors.ToString(id));
|
||||||
|
ImGuiUtil.DrawTableColumn(string.Empty);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -616,7 +639,7 @@ public class DebugTab : Window, ITab
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var skips = ImGuiClip.GetNecessarySkips(ImGui.GetTextLineHeightWithSpacing());
|
var skips = ImGuiClip.GetNecessarySkips(ImGui.GetTextLineHeightWithSpacing());
|
||||||
var dummy = ImGuiClip.FilteredClippedDraw(_identifier.AwaitedService.Emotes, skips,
|
var dummy = ImGuiClip.FilteredClippedDraw(_emotes, skips,
|
||||||
p => p.Key.Contains(_emoteSearchFile, StringComparison.OrdinalIgnoreCase)
|
p => p.Key.Contains(_emoteSearchFile, StringComparison.OrdinalIgnoreCase)
|
||||||
&& (_emoteSearchName.Length == 0
|
&& (_emoteSearchName.Length == 0
|
||||||
|| p.Value.Any(s => s.Name.ToDalamudString().TextValue.Contains(_emoteSearchName, StringComparison.OrdinalIgnoreCase))),
|
|| p.Value.Any(s => s.Name.ToDalamudString().TextValue.Contains(_emoteSearchName, StringComparison.OrdinalIgnoreCase))),
|
||||||
|
|
@ -2,7 +2,7 @@ using Dalamud.Interface;
|
||||||
using Dalamud.Interface.Windowing;
|
using Dalamud.Interface.Windowing;
|
||||||
using Dalamud.Plugin;
|
using Dalamud.Plugin;
|
||||||
using Penumbra.UI.AdvancedWindow;
|
using Penumbra.UI.AdvancedWindow;
|
||||||
using Penumbra.UI.Tabs;
|
using Penumbra.UI.Tabs.Debug;
|
||||||
|
|
||||||
namespace Penumbra.UI;
|
namespace Penumbra.UI;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,7 @@
|
||||||
global using StartTracker = OtterGui.Classes.StartTimeTracker<Penumbra.Util.StartTimeType>;
|
|
||||||
global using PerformanceTracker = OtterGui.Classes.PerformanceTracker<Penumbra.Util.PerformanceType>;
|
global using PerformanceTracker = OtterGui.Classes.PerformanceTracker<Penumbra.Util.PerformanceType>;
|
||||||
|
|
||||||
namespace Penumbra.Util;
|
namespace Penumbra.Util;
|
||||||
|
|
||||||
public enum StartTimeType
|
|
||||||
{
|
|
||||||
Total,
|
|
||||||
Identifier,
|
|
||||||
Stains,
|
|
||||||
Items,
|
|
||||||
Actors,
|
|
||||||
Backup,
|
|
||||||
Mods,
|
|
||||||
Collections,
|
|
||||||
PathResolver,
|
|
||||||
Interface,
|
|
||||||
Api,
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum PerformanceType
|
public enum PerformanceType
|
||||||
{
|
{
|
||||||
UiMainWindow,
|
UiMainWindow,
|
||||||
|
|
@ -48,23 +32,6 @@ public enum PerformanceType
|
||||||
|
|
||||||
public static class TimingExtensions
|
public static class TimingExtensions
|
||||||
{
|
{
|
||||||
public static string ToName(this StartTimeType type)
|
|
||||||
=> type switch
|
|
||||||
{
|
|
||||||
StartTimeType.Total => "Total Construction",
|
|
||||||
StartTimeType.Identifier => "Identification Data",
|
|
||||||
StartTimeType.Stains => "Stain Data",
|
|
||||||
StartTimeType.Items => "Item Data",
|
|
||||||
StartTimeType.Actors => "Actor Data",
|
|
||||||
StartTimeType.Backup => "Checking Backups",
|
|
||||||
StartTimeType.Mods => "Loading Mods",
|
|
||||||
StartTimeType.Collections => "Loading Collections",
|
|
||||||
StartTimeType.Api => "Setting Up API",
|
|
||||||
StartTimeType.Interface => "Setting Up Interface",
|
|
||||||
StartTimeType.PathResolver => "Setting Up Path Resolver",
|
|
||||||
_ => $"Unknown {(int)type}",
|
|
||||||
};
|
|
||||||
|
|
||||||
public static string ToName(this PerformanceType type)
|
public static string ToName(this PerformanceType type)
|
||||||
=> type switch
|
=> type switch
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,8 @@
|
||||||
"penumbra.gamedata": {
|
"penumbra.gamedata": {
|
||||||
"type": "Project",
|
"type": "Project",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Penumbra.Api": "[1.0.8, )",
|
"OtterGui": "[1.0.0, )",
|
||||||
|
"Penumbra.Api": "[1.0.13, )",
|
||||||
"Penumbra.String": "[1.0.4, )"
|
"Penumbra.String": "[1.0.4, )"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue