mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 18:27:24 +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 TempCollectionManager _tempCollections;
|
||||
private TempModManager _tempMods;
|
||||
private ActorService _actors;
|
||||
private ActorManager _actors;
|
||||
private CollectionResolver _collectionResolver;
|
||||
private CutsceneService _cutsceneService;
|
||||
private ModImportManager _modImportManager;
|
||||
|
|
@ -108,7 +108,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
|
||||
public unsafe PenumbraApi(CommunicatorService communicator, ModManager modManager, ResourceLoader resourceLoader,
|
||||
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,
|
||||
ConfigWindow configWindow, TextureManager textureManager, ResourceTreeFactory resourceTreeFactory)
|
||||
{
|
||||
|
|
@ -889,13 +889,10 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
{
|
||||
CheckInitialized();
|
||||
|
||||
if (!_actors.Valid)
|
||||
return PenumbraApiEc.SystemDisposed;
|
||||
|
||||
if (actorIndex < 0 || actorIndex >= _dalamud.Objects.Length)
|
||||
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)
|
||||
return PenumbraApiEc.InvalidArgument;
|
||||
|
||||
|
|
@ -1143,11 +1140,11 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
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;
|
||||
|
||||
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.
|
||||
|
|
@ -1241,12 +1238,9 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
// TODO: replace all usages with ActorIdentifier stuff when incrementing API
|
||||
private ActorIdentifier NameToIdentifier(string name, ushort worldId)
|
||||
{
|
||||
if (!_actors.Valid)
|
||||
return ActorIdentifier.Invalid;
|
||||
|
||||
// Verified to be valid name beforehand.
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -22,10 +22,10 @@ public class CollectionCache : IDisposable
|
|||
private readonly CollectionCacheManager _manager;
|
||||
private readonly ModCollection _collection;
|
||||
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 MetaCache Meta;
|
||||
public readonly Dictionary<IMod, SingleArray<ModConflicts>> _conflicts = new();
|
||||
public readonly Dictionary<IMod, SingleArray<ModConflicts>> ConflictDict = [];
|
||||
|
||||
public int Calculating = -1;
|
||||
|
||||
|
|
@ -33,10 +33,10 @@ public class CollectionCache : IDisposable
|
|||
=> _collection.AnonymizedName;
|
||||
|
||||
public IEnumerable<SingleArray<ModConflicts>> AllConflicts
|
||||
=> _conflicts.Values;
|
||||
=> ConflictDict.Values;
|
||||
|
||||
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;
|
||||
|
||||
|
|
@ -195,7 +195,7 @@ public class CollectionCache : IDisposable
|
|||
$"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)
|
||||
{
|
||||
if (conflict.HasPriority)
|
||||
|
|
@ -206,9 +206,9 @@ public class CollectionCache : IDisposable
|
|||
{
|
||||
var newConflicts = Conflicts(conflict.Mod2).Remove(c => c.Mod2 == mod);
|
||||
if (newConflicts.Count > 0)
|
||||
_conflicts[conflict.Mod2] = newConflicts;
|
||||
ConflictDict[conflict.Mod2] = newConflicts;
|
||||
else
|
||||
_conflicts.Remove(conflict.Mod2);
|
||||
ConflictDict.Remove(conflict.Mod2);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -336,9 +336,9 @@ public class CollectionCache : IDisposable
|
|||
return false;
|
||||
});
|
||||
if (changedConflicts.Count == 0)
|
||||
_conflicts.Remove(mod);
|
||||
ConflictDict.Remove(mod);
|
||||
else
|
||||
_conflicts[mod] = changedConflicts;
|
||||
ConflictDict[mod] = changedConflicts;
|
||||
}
|
||||
|
||||
// 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.
|
||||
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));
|
||||
_conflicts[existingMod] = existingConflicts.Append(new ModConflicts(addedMod, conflictList,
|
||||
ConflictDict[existingMod] = existingConflicts.Append(new ModConflicts(addedMod, conflictList,
|
||||
existingPriority >= addedPriority,
|
||||
existingPriority != addedPriority));
|
||||
}
|
||||
|
|
@ -426,7 +426,7 @@ public class CollectionCache : IDisposable
|
|||
_changedItems.Clear();
|
||||
// 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.
|
||||
var identifier = _manager.MetaFileManager.Identifier.AwaitedService;
|
||||
var identifier = _manager.MetaFileManager.Identifier;
|
||||
var items = new SortedList<string, object?>(512);
|
||||
|
||||
void AddItems(IMod mod)
|
||||
|
|
|
|||
|
|
@ -159,7 +159,7 @@ public class CollectionCacheManager : IDisposable
|
|||
null);
|
||||
cache.ResolvedFiles.Clear();
|
||||
cache.Meta.Reset();
|
||||
cache._conflicts.Clear();
|
||||
cache.ConflictDict.Clear();
|
||||
|
||||
// Add all forced redirects.
|
||||
foreach (var tempMod in _tempMods.ModsForAllCollections
|
||||
|
|
@ -372,7 +372,7 @@ public class CollectionCacheManager : IDisposable
|
|||
{
|
||||
collection._cache!.ResolvedFiles.Clear();
|
||||
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 SaveService _saveService;
|
||||
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)
|
||||
{
|
||||
_storage = storage;
|
||||
|
|
@ -475,7 +475,7 @@ public class ActiveCollections : ISavable, IDisposable
|
|||
{
|
||||
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
|
||||
? "Assignment is redundant due to an identical Any-World assignment existing.\nYou can remove it."
|
||||
: string.Empty;
|
||||
|
|
@ -484,12 +484,12 @@ public class ActiveCollections : ISavable, IDisposable
|
|||
if (id.HomeWorld != ushort.MaxValue)
|
||||
{
|
||||
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)
|
||||
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
|
||||
? "Assignment is redundant due to an identical unowned NPC assignment existing.\nYou can remove it."
|
||||
: string.Empty;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using Dalamud.Game.ClientState.Objects.Enums;
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.String;
|
||||
|
||||
namespace Penumbra.Collections.Manager;
|
||||
|
|
@ -36,7 +37,7 @@ public sealed partial class IndividualCollections : IReadOnlyList<(string Displa
|
|||
return true;
|
||||
|
||||
if (identifier.Retainer is not ActorIdentifier.RetainerType.Mannequin && _config.UseOwnerNameForCharacterCollection)
|
||||
return CheckWorlds(_actorService.AwaitedService.GetCurrentPlayer(), out collection);
|
||||
return CheckWorlds(_actors.GetCurrentPlayer(), out collection);
|
||||
|
||||
break;
|
||||
}
|
||||
|
|
@ -46,7 +47,7 @@ public sealed partial class IndividualCollections : IReadOnlyList<(string Displa
|
|||
return true;
|
||||
|
||||
// Handle generic NPC
|
||||
var npcIdentifier = _actorService.AwaitedService.CreateIndividualUnchecked(IdentifierType.Npc, ByteString.Empty,
|
||||
var npcIdentifier = _actors.CreateIndividualUnchecked(IdentifierType.Npc, ByteString.Empty,
|
||||
ushort.MaxValue,
|
||||
identifier.Kind, identifier.DataId);
|
||||
if (npcIdentifier.IsValid && _individuals.TryGetValue(npcIdentifier, out collection))
|
||||
|
|
@ -56,7 +57,7 @@ public sealed partial class IndividualCollections : IReadOnlyList<(string Displa
|
|||
if (!_config.UseOwnerNameForCharacterCollection)
|
||||
return false;
|
||||
|
||||
identifier = _actorService.AwaitedService.CreateIndividualUnchecked(IdentifierType.Player, identifier.PlayerName,
|
||||
identifier = _actors.CreateIndividualUnchecked(IdentifierType.Player, identifier.PlayerName,
|
||||
identifier.HomeWorld.Id,
|
||||
ObjectKind.None, uint.MaxValue);
|
||||
return CheckWorlds(identifier, out collection);
|
||||
|
|
@ -89,37 +90,37 @@ public sealed partial class IndividualCollections : IReadOnlyList<(string Displa
|
|||
if (identifier.Type != IdentifierType.Special)
|
||||
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);
|
||||
|
||||
if (_actorService.AwaitedService.ResolvePvPBannerPlayer(identifier.Special, out id))
|
||||
if (_actors.ResolvePvPBannerPlayer(identifier.Special, out id))
|
||||
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);
|
||||
|
||||
switch (identifier.Special)
|
||||
{
|
||||
case ScreenActor.CharacterScreen when _config.UseCharacterCollectionInMainWindow:
|
||||
return (_actorService.AwaitedService.GetCurrentPlayer(), SpecialResult.CharacterScreen);
|
||||
return (_actors.GetCurrentPlayer(), SpecialResult.CharacterScreen);
|
||||
case ScreenActor.FittingRoom when _config.UseCharacterCollectionInTryOn:
|
||||
return (_actorService.AwaitedService.GetCurrentPlayer(), SpecialResult.FittingRoom);
|
||||
return (_actors.GetCurrentPlayer(), SpecialResult.FittingRoom);
|
||||
case ScreenActor.DyePreview when _config.UseCharacterCollectionInTryOn:
|
||||
return (_actorService.AwaitedService.GetCurrentPlayer(), SpecialResult.DyePreview);
|
||||
return (_actors.GetCurrentPlayer(), SpecialResult.DyePreview);
|
||||
case ScreenActor.Portrait when _config.UseCharacterCollectionsInCards:
|
||||
return (_actorService.AwaitedService.GetCurrentPlayer(), SpecialResult.Portrait);
|
||||
return (_actors.GetCurrentPlayer(), SpecialResult.Portrait);
|
||||
case ScreenActor.ExamineScreen:
|
||||
{
|
||||
identifier = _actorService.AwaitedService.GetInspectPlayer();
|
||||
identifier = _actors.GetInspectPlayer();
|
||||
if (identifier.IsValid)
|
||||
return (_config.UseCharacterCollectionInInspect ? identifier : ActorIdentifier.Invalid, SpecialResult.Inspect);
|
||||
|
||||
identifier = _actorService.AwaitedService.GetCardPlayer();
|
||||
identifier = _actors.GetCardPlayer();
|
||||
if (identifier.IsValid)
|
||||
return (_config.UseCharacterCollectionInInspect ? identifier : ActorIdentifier.Invalid, SpecialResult.Card);
|
||||
|
||||
return _config.UseCharacterCollectionInTryOn
|
||||
? (_actorService.AwaitedService.GetGlamourPlayer(), SpecialResult.Glamour)
|
||||
? (_actors.GetGlamourPlayer(), SpecialResult.Glamour)
|
||||
: (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)
|
||||
=> 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)
|
||||
=> 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)
|
||||
{
|
||||
|
|
@ -143,7 +144,7 @@ public sealed partial class IndividualCollections : IReadOnlyList<(string Displa
|
|||
if (_individuals.TryGetValue(identifier, out collection))
|
||||
return true;
|
||||
|
||||
identifier = _actorService.AwaitedService.CreateIndividualUnchecked(identifier.Type, identifier.PlayerName, ushort.MaxValue,
|
||||
identifier = _actors.CreateIndividualUnchecked(identifier.Type, identifier.PlayerName, ushort.MaxValue,
|
||||
identifier.Kind,
|
||||
identifier.DataId);
|
||||
if (identifier.IsValid && _individuals.TryGetValue(identifier, out collection))
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ using Dalamud.Interface.Internal.Notifications;
|
|||
using Newtonsoft.Json.Linq;
|
||||
using OtterGui.Classes;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.DataContainers.Bases;
|
||||
using Penumbra.GameData.Structs;
|
||||
using Penumbra.Services;
|
||||
using Penumbra.String;
|
||||
|
||||
|
|
@ -26,23 +28,20 @@ public partial class IndividualCollections
|
|||
|
||||
public bool ReadJObject(SaveService saver, ActiveCollections parent, JArray? obj, CollectionStorage storage)
|
||||
{
|
||||
if (_actorService.Valid)
|
||||
if (_actors.Awaiter.IsCompletedSuccessfully)
|
||||
{
|
||||
var ret = ReadJObjectInternal(obj, storage);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Func()
|
||||
Penumbra.Log.Debug("[Collections] Delayed reading individual assignments until actor service is ready...");
|
||||
_actors.Awaiter.ContinueWith(_ =>
|
||||
{
|
||||
if (ReadJObjectInternal(obj, storage))
|
||||
saver.ImmediateSave(parent);
|
||||
IsLoaded = true;
|
||||
Loaded.Invoke();
|
||||
_actorService.FinishedCreation -= Func;
|
||||
}
|
||||
|
||||
Penumbra.Log.Debug("[Collections] Delayed reading individual assignments until actor service is ready...");
|
||||
_actorService.FinishedCreation += Func;
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -60,7 +59,7 @@ public partial class IndividualCollections
|
|||
{
|
||||
try
|
||||
{
|
||||
var identifier = _actorService.AwaitedService.FromJson(data as JObject);
|
||||
var identifier = _actors.FromJson(data as JObject);
|
||||
var group = GetGroup(identifier);
|
||||
if (group.Length == 0 || group.Any(i => !i.IsValid))
|
||||
{
|
||||
|
|
@ -101,10 +100,10 @@ public partial class IndividualCollections
|
|||
|
||||
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),
|
||||
new KeyValuePair<uint, string>(uint.MaxValue, string.Empty));
|
||||
new KeyValuePair<NpcId, string>(uint.MaxValue, string.Empty));
|
||||
dataId = kvp.Key;
|
||||
return kvp.Value.Length > 0;
|
||||
}
|
||||
|
|
@ -114,22 +113,22 @@ public partial class IndividualCollections
|
|||
var kind = ObjectKind.None;
|
||||
var lowerName = name.ToLowerInvariant();
|
||||
// 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;
|
||||
else if (FindDataId(lowerName, _actorService.AwaitedService.Data.Mounts, out dataId))
|
||||
else if (FindDataId(lowerName, _actors.Data.Mounts, out dataId))
|
||||
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;
|
||||
else if (FindDataId(lowerName, _actorService.AwaitedService.Data.ENpcs, out dataId))
|
||||
else if (FindDataId(lowerName, _actors.Data.ENpcs, out dataId))
|
||||
kind = ObjectKind.EventNpc;
|
||||
|
||||
var identifier = _actorService.AwaitedService.CreateNpc(kind, dataId);
|
||||
var identifier = _actors.CreateNpc(kind, dataId);
|
||||
if (identifier.IsValid)
|
||||
{
|
||||
// If the name corresponds to a valid npc, add it as a group. If this fails, notify users.
|
||||
var group = GetGroup(identifier);
|
||||
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}].");
|
||||
else
|
||||
Penumbra.Messager.NotificationMessage(
|
||||
|
|
@ -137,15 +136,12 @@ public partial class IndividualCollections
|
|||
NotificationType.Error);
|
||||
}
|
||||
// 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]}."));
|
||||
// Try to migrate the player name without logging full names.
|
||||
if (Add($"{name} ({_actorService.AwaitedService.Data.ToWorldName(identifier.HomeWorld)})", new[]
|
||||
{
|
||||
identifier,
|
||||
}, collection))
|
||||
if (Add($"{name} ({_actors.Data.ToWorldName(identifier.HomeWorld)})", [identifier], collection))
|
||||
Penumbra.Log.Information($"Migrated {shortName} ({collection.AnonymizedName}) to Player Identifier.");
|
||||
else
|
||||
Penumbra.Messager.NotificationMessage(
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
using Dalamud.Game.ClientState.Objects.Enums;
|
||||
using OtterGui.Filesystem;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.Services;
|
||||
using Penumbra.GameData.DataContainers.Bases;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
using Penumbra.String;
|
||||
|
||||
namespace Penumbra.Collections.Manager;
|
||||
|
|
@ -11,9 +13,9 @@ public sealed partial class IndividualCollections
|
|||
public record struct IndividualAssignment(string DisplayName, IReadOnlyList<ActorIdentifier> Identifiers, ModCollection Collection);
|
||||
|
||||
private readonly Configuration _config;
|
||||
private readonly ActorService _actorService;
|
||||
private readonly Dictionary<ActorIdentifier, ModCollection> _individuals = new();
|
||||
private readonly List<IndividualAssignment> _assignments = new();
|
||||
private readonly ActorManager _actors;
|
||||
private readonly Dictionary<ActorIdentifier, ModCollection> _individuals = [];
|
||||
private readonly List<IndividualAssignment> _assignments = [];
|
||||
|
||||
public event Action Loaded;
|
||||
public bool IsLoaded { get; private set; }
|
||||
|
|
@ -21,12 +23,12 @@ public sealed partial class IndividualCollections
|
|||
public IReadOnlyList<IndividualAssignment> Assignments
|
||||
=> _assignments;
|
||||
|
||||
public IndividualCollections(ActorService actorService, Configuration config, bool temporary)
|
||||
public IndividualCollections(ActorManager actors, Configuration config, bool temporary)
|
||||
{
|
||||
_config = config;
|
||||
_actorService = actorService;
|
||||
IsLoaded = temporary;
|
||||
Loaded += () => Penumbra.Log.Information($"{_assignments.Count} Individual Assignments loaded after delay.");
|
||||
_config = config;
|
||||
_actors = actors;
|
||||
IsLoaded = temporary;
|
||||
Loaded += () => Penumbra.Log.Information($"{_assignments.Count} Individual Assignments loaded after delay.");
|
||||
}
|
||||
|
||||
public enum AddResult
|
||||
|
|
@ -69,44 +71,34 @@ public sealed partial class IndividualCollections
|
|||
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)
|
||||
{
|
||||
identifiers = Array.Empty<ActorIdentifier>();
|
||||
identifiers = [];
|
||||
|
||||
var manager = _actorService.AwaitedService;
|
||||
switch (type)
|
||||
{
|
||||
case IdentifierType.Player:
|
||||
if (!ByteString.FromString(name, out var playerName))
|
||||
return AddResult.Invalid;
|
||||
|
||||
identifiers = new[]
|
||||
{
|
||||
manager.CreatePlayer(playerName, homeWorld),
|
||||
};
|
||||
identifiers = [_actors.CreatePlayer(playerName, homeWorld)];
|
||||
break;
|
||||
case IdentifierType.Retainer:
|
||||
if (!ByteString.FromString(name, out var retainerName))
|
||||
return AddResult.Invalid;
|
||||
|
||||
identifiers = new[]
|
||||
{
|
||||
manager.CreateRetainer(retainerName, ActorIdentifier.RetainerType.Both),
|
||||
};
|
||||
identifiers = [_actors.CreateRetainer(retainerName, ActorIdentifier.RetainerType.Both)];
|
||||
break;
|
||||
case IdentifierType.Owned:
|
||||
if (!ByteString.FromString(name, out var ownerName))
|
||||
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;
|
||||
case IdentifierType.Npc:
|
||||
identifiers = dataIds
|
||||
.Select(id => manager.CreateIndividual(IdentifierType.Npc, ByteString.Empty, ushort.MaxValue, kind, id)).ToArray();
|
||||
break;
|
||||
default:
|
||||
identifiers = Array.Empty<ActorIdentifier>();
|
||||
.Select(id => _actors.CreateIndividual(IdentifierType.Npc, ByteString.Empty, ushort.MaxValue, kind, id)).ToArray();
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -116,12 +108,22 @@ public sealed partial class IndividualCollections
|
|||
public ActorIdentifier[] GetGroup(ActorIdentifier identifier)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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.EventNpc => manager.Data.ENpcs,
|
||||
|
|
@ -134,25 +136,6 @@ public sealed partial class IndividualCollections
|
|||
.Select(kvp => manager.CreateIndividualUnchecked(identifier.Type, identifier.PlayerName, identifier.HomeWorld.Id,
|
||||
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)
|
||||
|
|
@ -241,12 +224,12 @@ public sealed partial class IndividualCollections
|
|||
{
|
||||
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.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 =>
|
||||
$"{_actorService.AwaitedService.Data.ToName(identifier.Kind, identifier.DataId)} ({identifier.Kind.ToName()})",
|
||||
$"{_actors.Data.ToName(identifier.Kind, identifier.DataId)} ({identifier.Kind.ToName()})",
|
||||
_ => string.Empty,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,10 +14,10 @@ public class TempCollectionManager : IDisposable
|
|||
|
||||
private readonly CommunicatorService _communicator;
|
||||
private readonly CollectionStorage _storage;
|
||||
private readonly ActorService _actors;
|
||||
private readonly ActorManager _actors;
|
||||
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;
|
||||
_actors = actors;
|
||||
|
|
@ -111,7 +111,7 @@ public class TempCollectionManager : IDisposable
|
|||
if (!ByteString.FromString(characterName, out var byteString, false))
|
||||
return false;
|
||||
|
||||
var identifier = _actors.AwaitedService.CreatePlayer(byteString, worldId);
|
||||
var identifier = _actors.CreatePlayer(byteString, worldId);
|
||||
if (!identifier.IsValid)
|
||||
return false;
|
||||
|
||||
|
|
@ -123,7 +123,7 @@ public class TempCollectionManager : IDisposable
|
|||
if (!ByteString.FromString(characterName, out var byteString, 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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ public class CommandHandler : IDisposable
|
|||
|
||||
public CommandHandler(IFramework framework, ICommandManager commandManager, IChatGui chat, RedrawService redrawService,
|
||||
Configuration config,
|
||||
ConfigWindow configWindow, ModManager modManager, CollectionManager collectionManager, ActorService actors, Penumbra penumbra,
|
||||
ConfigWindow configWindow, ModManager modManager, CollectionManager collectionManager, ActorManager actors, Penumbra penumbra,
|
||||
CollectionEditor collectionEditor)
|
||||
{
|
||||
_commandManager = commandManager;
|
||||
|
|
@ -41,7 +41,7 @@ public class CommandHandler : IDisposable
|
|||
_configWindow = configWindow;
|
||||
_modManager = modManager;
|
||||
_collectionManager = collectionManager;
|
||||
_actors = actors.AwaitedService;
|
||||
_actors = actors;
|
||||
_chat = chat;
|
||||
_penumbra = penumbra;
|
||||
_collectionEditor = collectionEditor;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData;
|
||||
using Penumbra.GameData.Data;
|
||||
|
||||
namespace Penumbra.Import.Structs;
|
||||
|
||||
|
|
@ -47,7 +48,7 @@ public partial struct MetaFileInfo
|
|||
_ => false,
|
||||
};
|
||||
|
||||
public MetaFileInfo(IGamePathParser parser, string fileName)
|
||||
public MetaFileInfo(GamePathParser parser, string fileName)
|
||||
{
|
||||
// Set the primary type from the gamePath start.
|
||||
PrimaryType = parser.PathToObjectType(fileName);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using Penumbra.GameData;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.Import.Structs;
|
||||
using Penumbra.Meta;
|
||||
using Penumbra.Meta.Manipulations;
|
||||
|
|
@ -28,7 +29,7 @@ public partial class TexToolsMeta
|
|||
|
||||
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;
|
||||
_keepDefault = keepDefault;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
|||
using Penumbra.Collections;
|
||||
using Penumbra.Collections.Manager;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.GameData.DataContainers;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.Services;
|
||||
using Penumbra.Util;
|
||||
|
|
@ -21,7 +21,7 @@ public unsafe class CollectionResolver
|
|||
|
||||
private readonly IClientState _clientState;
|
||||
private readonly IGameGui _gameGui;
|
||||
private readonly ActorService _actors;
|
||||
private readonly ActorManager _actors;
|
||||
private readonly CutsceneService _cutscenes;
|
||||
|
||||
private readonly Configuration _config;
|
||||
|
|
@ -30,7 +30,7 @@ public unsafe class CollectionResolver
|
|||
private readonly DrawObjectState _drawObjectState;
|
||||
|
||||
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)
|
||||
{
|
||||
_performance = performance;
|
||||
|
|
@ -58,7 +58,7 @@ public unsafe class CollectionResolver
|
|||
return _collectionManager.Active.ByType(CollectionType.Yourself)
|
||||
?? _collectionManager.Active.Default;
|
||||
|
||||
var player = _actors.AwaitedService.GetCurrentPlayer();
|
||||
var player = _actors.GetCurrentPlayer();
|
||||
var _ = false;
|
||||
return CollectionByIdentifier(player)
|
||||
?? CheckYourself(player, gameObject)
|
||||
|
|
@ -147,7 +147,7 @@ public unsafe class CollectionResolver
|
|||
return false;
|
||||
}
|
||||
|
||||
var player = _actors.AwaitedService.GetCurrentPlayer();
|
||||
var player = _actors.GetCurrentPlayer();
|
||||
var notYetReady = false;
|
||||
var collection = (player.IsValid ? CollectionByIdentifier(player) : null)
|
||||
?? _collectionManager.Active.ByType(CollectionType.Yourself)
|
||||
|
|
@ -163,7 +163,7 @@ public unsafe class CollectionResolver
|
|||
/// </summary>
|
||||
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)
|
||||
{
|
||||
(identifier, var type) = _collectionManager.Active.Individuals.ConvertSpecialIdentifier(identifier);
|
||||
|
|
@ -193,7 +193,7 @@ public unsafe class CollectionResolver
|
|||
{
|
||||
if (actor->ObjectIndex == 0
|
||||
|| _cutscenes.GetParentIndex(actor->ObjectIndex) == 0
|
||||
|| identifier.Equals(_actors.AwaitedService.GetCurrentPlayer()))
|
||||
|| identifier.Equals(_actors.GetCurrentPlayer()))
|
||||
return _collectionManager.Active.ByType(CollectionType.Yourself);
|
||||
|
||||
return null;
|
||||
|
|
@ -242,7 +242,7 @@ public unsafe class CollectionResolver
|
|||
if (identifier.Type != IdentifierType.Owned || !_config.UseOwnerNameForCharacterCollection || owner == 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,
|
||||
uint.MaxValue);
|
||||
return CheckYourself(id, owner)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.Interop.Services;
|
||||
|
||||
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>
|
||||
public int GetParentIndex(int idx)
|
||||
=> GetParentIndex((ushort)idx);
|
||||
|
||||
public short GetParentIndex(ushort idx)
|
||||
{
|
||||
if (idx is >= CutsceneStartIdx and < CutsceneEndIdx)
|
||||
return _copiedCharacters[idx - CutsceneStartIdx];
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ using OtterGui;
|
|||
using Penumbra.Api.Enums;
|
||||
using Penumbra.Collections;
|
||||
using Penumbra.GameData;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
using Penumbra.String;
|
||||
|
|
@ -19,7 +20,7 @@ using ModelType = FFXIVClientStructs.FFXIV.Client.Graphics.Scene.CharacterBase.M
|
|||
|
||||
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);
|
||||
|
||||
|
|
@ -28,8 +29,13 @@ internal record GlobalResolveContext(IObjectIdentifier Identifier, ModCollection
|
|||
=> new(this, characterBase, slotIndex, slot, equipment, weaponType);
|
||||
}
|
||||
|
||||
internal partial record ResolveContext(GlobalResolveContext Global, Pointer<CharacterBase> CharacterBase, uint SlotIndex,
|
||||
EquipSlot Slot, CharacterArmor Equipment, WeaponType WeaponType)
|
||||
internal partial record ResolveContext(
|
||||
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);
|
||||
|
||||
|
|
@ -152,6 +158,7 @@ internal partial record ResolveContext(GlobalResolveContext Global, Pointer<Char
|
|||
{
|
||||
if (mdl == null || mdl->ModelResourceHandle == null)
|
||||
return null;
|
||||
|
||||
var mdlResource = mdl->ModelResourceHandle;
|
||||
|
||||
var path = ResolveModelPath();
|
||||
|
|
@ -224,6 +231,7 @@ internal partial record ResolveContext(GlobalResolveContext Global, Pointer<Char
|
|||
shpkNode.Name = "Shader Package";
|
||||
node.Children.Add(shpkNode);
|
||||
}
|
||||
|
||||
var shpkFile = Global.WithUiData && shpkNode != null ? Global.TreeBuildCache.ReadShaderPackage(shpkNode.FullPath) : 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}";
|
||||
}
|
||||
|
||||
|
|
@ -310,13 +318,13 @@ internal partial record ResolveContext(GlobalResolveContext Global, Pointer<Char
|
|||
return node;
|
||||
}
|
||||
|
||||
internal ResourceNode.UiData GuessModelUIData(Utf8GamePath gamePath)
|
||||
internal ResourceNode.UiData GuessModelUiData(Utf8GamePath gamePath)
|
||||
{
|
||||
var path = gamePath.ToString().Split('/', StringSplitOptions.RemoveEmptyEntries);
|
||||
// Weapons intentionally left out.
|
||||
var isEquipment = SafeGet(path, 0) == "chara" && SafeGet(path, 1) is "accessory" or "equipment";
|
||||
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
|
||||
{
|
||||
|
|
@ -324,11 +332,11 @@ internal partial record ResolveContext(GlobalResolveContext Global, Pointer<Char
|
|||
EquipSlot.LFinger => "L: ",
|
||||
_ => string.Empty,
|
||||
}
|
||||
+ item.Name.ToString();
|
||||
+ item.Name;
|
||||
return new ResourceNode.UiData(name, ChangedItemDrawer.GetCategoryIcon(item.Name, item));
|
||||
}
|
||||
|
||||
var dataFromPath = GuessUIDataFromPath(gamePath);
|
||||
var dataFromPath = GuessUiDataFromPath(gamePath);
|
||||
if (dataFromPath.Name != null)
|
||||
return dataFromPath;
|
||||
|
||||
|
|
@ -337,7 +345,7 @@ internal partial record ResolveContext(GlobalResolveContext Global, Pointer<Char
|
|||
: 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()))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -3,24 +3,25 @@ using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
|||
using Penumbra.Api.Enums;
|
||||
using Penumbra.Collections;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.Interop.PathResolving;
|
||||
using Penumbra.Services;
|
||||
using Penumbra.String.Classes;
|
||||
|
||||
namespace Penumbra.Interop.ResourceTree;
|
||||
|
||||
public class ResourceTreeFactory
|
||||
{
|
||||
private readonly IDataManager _gameData;
|
||||
private readonly IObjectTable _objects;
|
||||
private readonly CollectionResolver _collectionResolver;
|
||||
private readonly IdentifierService _identifier;
|
||||
private readonly Configuration _config;
|
||||
private readonly ActorService _actors;
|
||||
private readonly PathState _pathState;
|
||||
private readonly IDataManager _gameData;
|
||||
private readonly IObjectTable _objects;
|
||||
private readonly CollectionResolver _collectionResolver;
|
||||
private readonly ObjectIdentification _identifier;
|
||||
private readonly Configuration _config;
|
||||
private readonly ActorManager _actors;
|
||||
private readonly PathState _pathState;
|
||||
|
||||
public ResourceTreeFactory(IDataManager gameData, IObjectTable objects, CollectionResolver resolver, IdentifierService identifier,
|
||||
Configuration config, ActorService actors, PathState pathState)
|
||||
public ResourceTreeFactory(IDataManager gameData, IObjectTable objects, CollectionResolver resolver, ObjectIdentification identifier,
|
||||
Configuration config, ActorManager actors, PathState pathState)
|
||||
{
|
||||
_gameData = gameData;
|
||||
_objects = objects;
|
||||
|
|
@ -88,12 +89,13 @@ public class ResourceTreeFactory
|
|||
var networked = character.ObjectId != Dalamud.Game.ClientState.Objects.Types.GameObject.InvalidGameObjectId;
|
||||
var tree = new ResourceTree(name, character.ObjectIndex, (nint)gameObjStruct, (nint)drawObjStruct, localPlayerRelated, related,
|
||||
networked, collectionResolveData.ModCollection.Name);
|
||||
var globalContext = new GlobalResolveContext(_identifier.AwaitedService, collectionResolveData.ModCollection,
|
||||
var globalContext = new GlobalResolveContext(_identifier, collectionResolveData.ModCollection,
|
||||
cache, (flags & Flags.WithUiData) != 0);
|
||||
using (var _ = _pathState.EnterInternalResolve())
|
||||
{
|
||||
tree.LoadResources(globalContext);
|
||||
}
|
||||
|
||||
tree.FlatNodes.UnionWith(globalContext.Nodes.Values);
|
||||
tree.ProcessPostfix((node, _) => tree.FlatNodes.Add(node));
|
||||
|
||||
|
|
@ -161,9 +163,9 @@ public class ResourceTreeFactory
|
|||
var gamePath = node.PossibleGamePaths[0];
|
||||
node.SetUiData(node.Type switch
|
||||
{
|
||||
ResourceType.Imc => node.ResolveContext!.GuessModelUIData(gamePath).PrependName("IMC: "),
|
||||
ResourceType.Mdl => node.ResolveContext!.GuessModelUIData(gamePath),
|
||||
_ => node.ResolveContext!.GuessUIDataFromPath(gamePath),
|
||||
ResourceType.Imc => node.ResolveContext!.GuessModelUiData(gamePath).PrependName("IMC: "),
|
||||
ResourceType.Mdl => node.ResolveContext!.GuessModelUiData(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,
|
||||
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)
|
||||
{
|
||||
case IdentifierType.Player: return (identifier.PlayerName.ToString(), true);
|
||||
|
|
|
|||
|
|
@ -1,36 +1,26 @@
|
|||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Files;
|
||||
using Penumbra.GameData.Structs;
|
||||
using Penumbra.Services;
|
||||
using Penumbra.String;
|
||||
using Penumbra.String.Classes;
|
||||
|
||||
namespace Penumbra.Interop.ResourceTree;
|
||||
|
||||
internal readonly struct TreeBuildCache
|
||||
internal readonly struct TreeBuildCache(IObjectTable objects, IDataManager dataManager, ActorManager actors)
|
||||
{
|
||||
private readonly IDataManager _dataManager;
|
||||
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;
|
||||
}
|
||||
private readonly Dictionary<FullPath, ShpkFile?> _shaderPackages = [];
|
||||
|
||||
public unsafe bool IsLocalPlayerRelated(Character character)
|
||||
{
|
||||
var player = _objects[0];
|
||||
var player = objects[0];
|
||||
if (player == null)
|
||||
return false;
|
||||
|
||||
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;
|
||||
return actualIndex switch
|
||||
{
|
||||
|
|
@ -41,38 +31,38 @@ internal readonly struct TreeBuildCache
|
|||
}
|
||||
|
||||
public IEnumerable<Character> GetCharacters()
|
||||
=> _objects.OfType<Character>();
|
||||
=> objects.OfType<Character>();
|
||||
|
||||
public IEnumerable<Character> GetLocalPlayerRelatedCharacters()
|
||||
{
|
||||
var player = _objects[0];
|
||||
var player = objects[0];
|
||||
if (player == null)
|
||||
yield break;
|
||||
|
||||
yield return (Character)player;
|
||||
|
||||
var minion = _objects[1];
|
||||
var minion = objects[1];
|
||||
if (minion != null)
|
||||
yield return (Character)minion;
|
||||
|
||||
var playerId = player.ObjectId;
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
continue;
|
||||
|
||||
var parent = _actors.AwaitedService.ToCutsceneParent(i);
|
||||
var parent = actors.ToCutsceneParent(i);
|
||||
if (parent < 0)
|
||||
continue;
|
||||
|
||||
if (parent is 0 or 1 || _objects[parent]?.OwnerId == playerId)
|
||||
if (parent is 0 or 1 || objects[parent]?.OwnerId == playerId)
|
||||
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)
|
||||
{
|
||||
character = _objects[idx] as Character;
|
||||
character = objects[idx] as Character;
|
||||
if (character == null)
|
||||
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)
|
||||
return false;
|
||||
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>
|
||||
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)
|
||||
where T : class
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ using FFXIVClientStructs.Interop;
|
|||
using Penumbra.Api;
|
||||
using Penumbra.Api.Enums;
|
||||
using Penumbra.GameData;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.Interop.Structs;
|
||||
using Character = FFXIVClientStructs.FFXIV.Client.Game.Character.Character;
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ using OtterGui.Compression;
|
|||
using Penumbra.Collections;
|
||||
using Penumbra.Collections.Manager;
|
||||
using Penumbra.GameData;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.Import;
|
||||
using Penumbra.Interop.Services;
|
||||
using Penumbra.Interop.Structs;
|
||||
|
|
@ -24,11 +25,11 @@ public unsafe class MetaFileManager
|
|||
internal readonly IDataManager GameData;
|
||||
internal readonly ActiveCollectionData ActiveCollections;
|
||||
internal readonly ValidityChecker ValidityChecker;
|
||||
internal readonly IdentifierService Identifier;
|
||||
internal readonly ObjectIdentification Identifier;
|
||||
internal readonly FileCompactor Compactor;
|
||||
|
||||
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)
|
||||
{
|
||||
CharacterUtility = characterUtility;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using Penumbra.Api.Enums;
|
||||
using Penumbra.GameData;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Files;
|
||||
|
|
@ -41,7 +40,7 @@ public static class EquipmentSwap
|
|||
: 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,
|
||||
EquipSlot slotFrom, EquipItem itemFrom, EquipSlot slotTo, EquipItem itemTo)
|
||||
{
|
||||
|
|
@ -99,7 +98,7 @@ public static class EquipmentSwap
|
|||
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,
|
||||
EquipItem itemTo, bool rFinger = true, bool lFinger = true)
|
||||
{
|
||||
|
|
@ -247,7 +246,7 @@ public static class EquipmentSwap
|
|||
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)
|
||||
{
|
||||
var entry = new ImcManipulation(slotFrom, variantFrom.Id, idFrom, default);
|
||||
|
|
@ -256,11 +255,8 @@ public static class EquipmentSwap
|
|||
Variant[] variants;
|
||||
if (idFrom == idTo)
|
||||
{
|
||||
items = identifier.Identify(idFrom, variantFrom, slotFrom).ToArray();
|
||||
variants = new[]
|
||||
{
|
||||
variantFrom,
|
||||
};
|
||||
items = identifier.Identify(idFrom, 0, variantFrom, slotFrom).ToArray();
|
||||
variants = [variantFrom];
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
using Lumina.Excel.GeneratedSheets;
|
||||
using Penumbra.Collections;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
using Penumbra.Meta.Manipulations;
|
||||
|
|
@ -7,17 +7,16 @@ using Penumbra.String.Classes;
|
|||
using Penumbra.Meta;
|
||||
using Penumbra.Mods.Manager;
|
||||
using Penumbra.Mods.Subclasses;
|
||||
using Penumbra.Services;
|
||||
|
||||
namespace Penumbra.Mods.ItemSwap;
|
||||
|
||||
public class ItemSwapContainer
|
||||
{
|
||||
private readonly MetaFileManager _manager;
|
||||
private readonly IdentifierService _identifier;
|
||||
private readonly MetaFileManager _manager;
|
||||
private readonly ObjectIdentification _identifier;
|
||||
|
||||
private Dictionary<Utf8GamePath, FullPath> _modRedirections = new();
|
||||
private HashSet<MetaManipulation> _modManipulations = new();
|
||||
private Dictionary<Utf8GamePath, FullPath> _modRedirections = [];
|
||||
private HashSet<MetaManipulation> _modManipulations = [];
|
||||
|
||||
public IReadOnlyDictionary<Utf8GamePath, FullPath> ModRedirections
|
||||
=> _modRedirections;
|
||||
|
|
@ -25,7 +24,7 @@ public class ItemSwapContainer
|
|||
public IReadOnlySet<MetaManipulation> ModManipulations
|
||||
=> _modManipulations;
|
||||
|
||||
public readonly List<Swap> Swaps = new();
|
||||
public readonly List<Swap> Swaps = [];
|
||||
|
||||
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;
|
||||
_identifier = identifier;
|
||||
|
|
@ -130,7 +129,7 @@ public class ItemSwapContainer
|
|||
{
|
||||
Swaps.Clear();
|
||||
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);
|
||||
Loaded = true;
|
||||
return ret;
|
||||
|
|
@ -140,7 +139,7 @@ public class ItemSwapContainer
|
|||
{
|
||||
Swaps.Clear();
|
||||
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);
|
||||
Loaded = true;
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using Penumbra.Communication;
|
||||
using Penumbra.GameData;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.Meta.Manipulations;
|
||||
|
|
@ -9,11 +8,12 @@ namespace Penumbra.Mods.Manager;
|
|||
|
||||
public class ModCacheManager : IDisposable
|
||||
{
|
||||
private readonly CommunicatorService _communicator;
|
||||
private readonly IdentifierService _identifier;
|
||||
private readonly ModStorage _modManager;
|
||||
private readonly CommunicatorService _communicator;
|
||||
private readonly ObjectIdentification _identifier;
|
||||
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;
|
||||
_identifier = identifier;
|
||||
|
|
@ -23,8 +23,7 @@ public class ModCacheManager : IDisposable
|
|||
_communicator.ModPathChanged.Subscribe(OnModPathChange, ModPathChanged.Priority.ModCacheManager);
|
||||
_communicator.ModDataChanged.Subscribe(OnModDataChange, ModDataChanged.Priority.ModCacheManager);
|
||||
_communicator.ModDiscoveryFinished.Subscribe(OnModDiscoveryFinished, ModDiscoveryFinished.Priority.ModCacheManager);
|
||||
if (!identifier.Valid)
|
||||
identifier.FinishedCreation += OnIdentifierCreation;
|
||||
identifier.Awaiter.ContinueWith(_ => OnIdentifierCreation());
|
||||
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>
|
||||
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)
|
||||
{
|
||||
|
|
@ -155,10 +154,7 @@ public class ModCacheManager : IDisposable
|
|||
=> Parallel.ForEach(_modManager, Refresh);
|
||||
|
||||
private void OnIdentifierCreation()
|
||||
{
|
||||
Parallel.ForEach(_modManager, UpdateChangedItems);
|
||||
_identifier.FinishedCreation -= OnIdentifierCreation;
|
||||
}
|
||||
=> Parallel.ForEach(_modManager, UpdateChangedItems);
|
||||
|
||||
private static void UpdateFileCount(Mod mod)
|
||||
=> mod.TotalFileCount = mod.AllSubMods.Sum(s => s.Files.Count);
|
||||
|
|
@ -177,18 +173,23 @@ public class ModCacheManager : IDisposable
|
|||
|
||||
private void UpdateChangedItems(Mod mod)
|
||||
{
|
||||
if (_updatingItems)
|
||||
return;
|
||||
|
||||
_updatingItems = true;
|
||||
var changedItems = (SortedList<string, object?>)mod.ChangedItems;
|
||||
changedItems.Clear();
|
||||
if (!_identifier.Valid)
|
||||
if (!_identifier.Awaiter.IsCompletedSuccessfully)
|
||||
return;
|
||||
|
||||
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))
|
||||
ComputeChangedItems(_identifier.AwaitedService, changedItems, manip);
|
||||
ComputeChangedItems(_identifier, changedItems, manip);
|
||||
|
||||
mod.LowerChangedItemsString = string.Join("\0", mod.ChangedItems.Keys.Select(k => k.ToLowerInvariant()));
|
||||
_updatingItems = false;
|
||||
}
|
||||
|
||||
private static void UpdateCounts(Mod mod)
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ using OtterGui;
|
|||
using OtterGui.Classes;
|
||||
using OtterGui.Filesystem;
|
||||
using Penumbra.Api.Enums;
|
||||
using Penumbra.GameData;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.Import;
|
||||
using Penumbra.Import.Structs;
|
||||
using Penumbra.Meta;
|
||||
|
|
@ -17,7 +17,7 @@ using Penumbra.String.Classes;
|
|||
namespace Penumbra.Mods;
|
||||
|
||||
public partial class ModCreator(SaveService _saveService, Configuration config, ModDataEditor _dataEditor, MetaFileManager _metaFileManager,
|
||||
IGamePathParser _gamePathParser)
|
||||
GamePathParser _gamePathParser)
|
||||
{
|
||||
public readonly Configuration Config = config;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using Dalamud.Plugin;
|
||||
using Dalamud.Plugin.Services;
|
||||
using ImGuiNET;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
|
@ -6,7 +7,6 @@ using OtterGui;
|
|||
using OtterGui.Log;
|
||||
using Penumbra.Api;
|
||||
using Penumbra.Api.Enums;
|
||||
using Penumbra.Util;
|
||||
using Penumbra.Collections;
|
||||
using Penumbra.Collections.Cache;
|
||||
using Penumbra.Interop.ResourceLoading;
|
||||
|
|
@ -19,6 +19,7 @@ using Penumbra.UI.Tabs;
|
|||
using ChangedItemClick = Penumbra.Communication.ChangedItemClick;
|
||||
using ChangedItemHover = Penumbra.Communication.ChangedItemHover;
|
||||
using OtterGui.Tasks;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.Interop.Structs;
|
||||
using Penumbra.UI;
|
||||
|
|
@ -31,7 +32,7 @@ public class Penumbra : IDalamudPlugin
|
|||
public string Name
|
||||
=> "Penumbra";
|
||||
|
||||
public static readonly Logger Log = new();
|
||||
public static readonly Logger Log = new();
|
||||
public static MessageService Messager { get; private set; } = null!;
|
||||
|
||||
private readonly ValidityChecker _validityChecker;
|
||||
|
|
@ -53,10 +54,8 @@ public class Penumbra : IDalamudPlugin
|
|||
{
|
||||
try
|
||||
{
|
||||
var startTimer = new StartTracker();
|
||||
using var timer = startTimer.Measure(StartTimeType.Total);
|
||||
_services = ServiceManager.CreateProvider(this, pluginInterface, Log, startTimer);
|
||||
Messager = _services.GetRequiredService<MessageService>();
|
||||
_services = ServiceManager.CreateProvider(this, pluginInterface, Log);
|
||||
Messager = _services.GetRequiredService<MessageService>();
|
||||
_validityChecker = _services.GetRequiredService<ValidityChecker>();
|
||||
var startup = _services.GetRequiredService<DalamudServices>().GetDalamudConfig(DalamudServices.WaitingForPluginsOption, out bool s)
|
||||
? s.ToString()
|
||||
|
|
@ -74,14 +73,11 @@ public class Penumbra : IDalamudPlugin
|
|||
_tempCollections = _services.GetRequiredService<TempCollectionManager>();
|
||||
_redrawService = _services.GetRequiredService<RedrawService>();
|
||||
_communicatorService = _services.GetRequiredService<CommunicatorService>();
|
||||
_services.GetRequiredService<ResourceService>(); // Initialize because not required anywhere else.
|
||||
_services.GetRequiredService<ModCacheManager>(); // 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<ModelResourceHandleUtility>(); // Initialize because not required anywhere else.
|
||||
_collectionManager.Caches.CreateNecessaryCaches();
|
||||
using (var t = _services.GetRequiredService<StartTracker>().Measure(StartTimeType.PathResolver))
|
||||
{
|
||||
_services.GetRequiredService<PathResolver>();
|
||||
}
|
||||
_services.GetRequiredService<PathResolver>();
|
||||
|
||||
_services.GetRequiredService<SkinFixer>();
|
||||
|
||||
|
|
@ -108,8 +104,7 @@ public class Penumbra : IDalamudPlugin
|
|||
|
||||
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>();
|
||||
_communicatorService.ChangedItemHover.Subscribe(it =>
|
||||
{
|
||||
|
|
@ -128,8 +123,7 @@ public class Penumbra : IDalamudPlugin
|
|||
{
|
||||
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>());
|
||||
_services.GetRequiredService<CommandHandler>();
|
||||
if (!_disposed)
|
||||
|
|
|
|||
|
|
@ -1,15 +1,13 @@
|
|||
using Newtonsoft.Json.Linq;
|
||||
using OtterGui.Classes;
|
||||
using OtterGui.Log;
|
||||
using Penumbra.Util;
|
||||
|
||||
namespace Penumbra.Services;
|
||||
|
||||
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);
|
||||
Backup.CreateAutomaticBackup(logger, new DirectoryInfo(fileNames.ConfigDirectory), files);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,10 @@ using Penumbra.Api;
|
|||
using Penumbra.Collections.Cache;
|
||||
using Penumbra.Collections.Manager;
|
||||
using Penumbra.GameData;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.GameData.DataContainers;
|
||||
using Penumbra.GameData.DataContainers.Bases;
|
||||
using Penumbra.Import.Textures;
|
||||
using Penumbra.Interop.PathResolving;
|
||||
using Penumbra.Interop.ResourceLoading;
|
||||
|
|
@ -24,17 +27,17 @@ using Penumbra.UI.Classes;
|
|||
using Penumbra.UI.ModsTab;
|
||||
using Penumbra.UI.ResourceWatcher;
|
||||
using Penumbra.UI.Tabs;
|
||||
using Penumbra.UI.Tabs.Debug;
|
||||
using ResidentResourceManager = Penumbra.Interop.Services.ResidentResourceManager;
|
||||
|
||||
namespace Penumbra.Services;
|
||||
|
||||
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()
|
||||
.AddSingleton(log)
|
||||
.AddSingleton(startTimer)
|
||||
.AddSingleton(penumbra)
|
||||
.AddDalamud(pi)
|
||||
.AddMeta()
|
||||
|
|
@ -47,7 +50,9 @@ public static class ServiceManager
|
|||
.AddResolvers()
|
||||
.AddInterface()
|
||||
.AddModEditor()
|
||||
.AddApi();
|
||||
.AddApi()
|
||||
.AddDataContainers()
|
||||
.AddAsyncServices();
|
||||
|
||||
return services.BuildServiceProvider(new ServiceProviderOptions { ValidateOnBuild = true });
|
||||
}
|
||||
|
|
@ -59,6 +64,22 @@ public static class ServiceManager
|
|||
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)
|
||||
=> services.AddSingleton<ValidityChecker>()
|
||||
.AddSingleton<PerformanceTracker>()
|
||||
|
|
@ -71,17 +92,19 @@ public static class ServiceManager
|
|||
|
||||
|
||||
private static IServiceCollection AddGameData(this IServiceCollection services)
|
||||
=> services.AddSingleton<IGamePathParser, GamePathParser>()
|
||||
.AddSingleton<IdentifierService>()
|
||||
=> services.AddSingleton<GamePathParser>()
|
||||
.AddSingleton<StainService>()
|
||||
.AddSingleton<ItemService>()
|
||||
.AddSingleton<ActorService>()
|
||||
.AddSingleton<HumanModelList>();
|
||||
|
||||
private static IServiceCollection AddInterop(this IServiceCollection services)
|
||||
=> services.AddSingleton<GameEventManager>()
|
||||
.AddSingleton<FrameworkManager>()
|
||||
.AddSingleton<CutsceneService>()
|
||||
.AddSingleton(p =>
|
||||
{
|
||||
var cutsceneService = p.GetRequiredService<CutsceneService>();
|
||||
return new CutsceneResolver(cutsceneService.GetParentIndex);
|
||||
})
|
||||
.AddSingleton<CharacterUtility>()
|
||||
.AddSingleton<ResourceManagerService>()
|
||||
.AddSingleton<ResourceService>()
|
||||
|
|
@ -173,7 +196,8 @@ public static class ServiceManager
|
|||
.AddSingleton<ResourceWatcher>()
|
||||
.AddSingleton<ItemSwapTab>()
|
||||
.AddSingleton<ModMergeTab>()
|
||||
.AddSingleton<ChangedItemDrawer>();
|
||||
.AddSingleton<ChangedItemDrawer>()
|
||||
.AddSingleton(p => new Diagnostics(p));
|
||||
|
||||
private static IServiceCollection AddModEditor(this IServiceCollection services)
|
||||
=> services.AddSingleton<ModFileCollection>()
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using OtterGui.Tasks;
|
||||
using Penumbra.Util;
|
||||
|
||||
namespace Penumbra.Services;
|
||||
|
||||
|
|
@ -12,10 +11,9 @@ public abstract class SyncServiceWrapper<T> : IDisposable
|
|||
public bool Valid
|
||||
=> !_isDisposed;
|
||||
|
||||
protected SyncServiceWrapper(string name, StartTracker tracker, StartTimeType type, Func<T> factory)
|
||||
protected SyncServiceWrapper(string name, Func<T> factory)
|
||||
{
|
||||
Name = name;
|
||||
using var timer = tracker.Measure(type);
|
||||
Service = factory();
|
||||
Penumbra.Log.Verbose($"[{Name}] Created.");
|
||||
}
|
||||
|
|
@ -54,32 +52,6 @@ public abstract class AsyncServiceWrapper<T> : IDisposable
|
|||
|
||||
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)
|
||||
{
|
||||
Name = name;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ using Dalamud.Plugin;
|
|||
using Dalamud.Plugin.Services;
|
||||
using ImGuiNET;
|
||||
using OtterGui.Widgets;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.GameData.DataContainers;
|
||||
using Penumbra.GameData.Files;
|
||||
using Penumbra.UI.AdvancedWindow;
|
||||
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 StmFile StmFile;
|
||||
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 StainData(pluginInterface, dataManager, dataManager.Language, dalamudLog);
|
||||
StainData = new DictStains(pluginInterface, dalamudLog, dataManager);
|
||||
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);
|
||||
StmFile = new StmFile(dataManager);
|
||||
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.Utility;
|
||||
using ImGuiNET;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using OtterGui;
|
||||
using OtterGui.Classes;
|
||||
using OtterGui.Raii;
|
||||
|
|
@ -11,6 +8,7 @@ using Penumbra.Api.Enums;
|
|||
using Penumbra.Collections;
|
||||
using Penumbra.Collections.Manager;
|
||||
using Penumbra.Communication;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
using Penumbra.Meta;
|
||||
|
|
@ -27,16 +25,14 @@ public class ItemSwapTab : IDisposable, ITab
|
|||
{
|
||||
private readonly Configuration _config;
|
||||
private readonly CommunicatorService _communicator;
|
||||
private readonly ItemService _itemService;
|
||||
private readonly CollectionManager _collectionManager;
|
||||
private readonly ModManager _modManager;
|
||||
private readonly MetaFileManager _metaFileManager;
|
||||
|
||||
public ItemSwapTab(CommunicatorService communicator, ItemService itemService, CollectionManager collectionManager,
|
||||
ModManager modManager, IdentifierService identifier, MetaFileManager metaFileManager, Configuration config)
|
||||
public ItemSwapTab(CommunicatorService communicator, ItemData itemService, CollectionManager collectionManager,
|
||||
ModManager modManager, ObjectIdentification identifier, MetaFileManager metaFileManager, Configuration config)
|
||||
{
|
||||
_communicator = communicator;
|
||||
_itemService = itemService;
|
||||
_collectionManager = collectionManager;
|
||||
_modManager = modManager;
|
||||
_metaFileManager = metaFileManager;
|
||||
|
|
@ -46,15 +42,15 @@ public class ItemSwapTab : IDisposable, ITab
|
|||
_selectors = new Dictionary<SwapType, (ItemSelector Source, ItemSelector Target, string TextFrom, string TextTo)>
|
||||
{
|
||||
// @formatter:off
|
||||
[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.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.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.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.Ring] = (new ItemSelector(_itemService, FullEquipType.Finger), new ItemSelector(_itemService, FullEquipType.Finger), "Take this Ring", "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.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.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.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.Ring] = (new ItemSelector(itemService, FullEquipType.Finger), new ItemSelector(itemService, FullEquipType.Finger), "Take this Ring", "and put it on this one" ),
|
||||
// @formatter:on
|
||||
};
|
||||
|
||||
|
|
@ -131,8 +127,8 @@ public class ItemSwapTab : IDisposable, ITab
|
|||
|
||||
private class ItemSelector : FilterComboCache<EquipItem>
|
||||
{
|
||||
public ItemSelector(ItemService data, FullEquipType type)
|
||||
: base(() => data.AwaitedService[type], Penumbra.Log)
|
||||
public ItemSelector(ItemData data, FullEquipType type)
|
||||
: base(() => data.ByType[type], Penumbra.Log)
|
||||
{ }
|
||||
|
||||
protected override string ToString(EquipItem obj)
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ using OtterGui.Classes;
|
|||
using Penumbra.GameData;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.GameData.Files;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Penumbra.String;
|
||||
using static Penumbra.GameData.Files.ShpkFile;
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ using Lumina.Misc;
|
|||
using OtterGui;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.GameData.Files;
|
||||
using Penumbra.GameData.Interop;
|
||||
|
||||
namespace Penumbra.UI.AdvancedWindow;
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ public sealed class CollectionPanel : IDisposable
|
|||
private readonly CollectionStorage _collections;
|
||||
private readonly ActiveCollections _active;
|
||||
private readonly CollectionSelector _selector;
|
||||
private readonly ActorService _actors;
|
||||
private readonly ActorManager _actors;
|
||||
private readonly ITargetManager _targets;
|
||||
private readonly IndividualAssignmentUi _individualAssignmentUi;
|
||||
private readonly InheritanceUi _inheritanceUi;
|
||||
|
|
@ -37,7 +37,7 @@ public sealed class CollectionPanel : IDisposable
|
|||
private int _draggedIndividualAssignment = -1;
|
||||
|
||||
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;
|
||||
_active = manager.Active;
|
||||
|
|
@ -382,11 +382,11 @@ public sealed class CollectionPanel : IDisposable
|
|||
}
|
||||
|
||||
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)
|
||||
=> 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)
|
||||
=> DrawIndividualButton("New Player", width, _individualAssignmentUi.PlayerTooltip, 'p',
|
||||
|
|
|
|||
|
|
@ -5,6 +5,9 @@ using Penumbra.Collections;
|
|||
using Penumbra.Collections.Manager;
|
||||
using Penumbra.Communication;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Gui;
|
||||
using Penumbra.GameData.Structs;
|
||||
using Penumbra.Services;
|
||||
|
||||
namespace Penumbra.UI.CollectionTab;
|
||||
|
|
@ -12,7 +15,7 @@ namespace Penumbra.UI.CollectionTab;
|
|||
public class IndividualAssignmentUi : IDisposable
|
||||
{
|
||||
private readonly CommunicatorService _communicator;
|
||||
private readonly ActorService _actorService;
|
||||
private readonly ActorManager _actors;
|
||||
private readonly CollectionManager _collectionManager;
|
||||
|
||||
private WorldCombo _worldCombo = null!;
|
||||
|
|
@ -24,16 +27,13 @@ public class IndividualAssignmentUi : IDisposable
|
|||
|
||||
private bool _ready;
|
||||
|
||||
public IndividualAssignmentUi(CommunicatorService communicator, ActorService actors, CollectionManager collectionManager)
|
||||
public IndividualAssignmentUi(CommunicatorService communicator, ActorManager actors, CollectionManager collectionManager)
|
||||
{
|
||||
_communicator = communicator;
|
||||
_actorService = actors;
|
||||
_actors = actors;
|
||||
_collectionManager = collectionManager;
|
||||
_communicator.CollectionChange.Subscribe(UpdateIdentifiers, CollectionChange.Priority.IndividualAssignmentUi);
|
||||
if (_actorService.Valid)
|
||||
SetupCombos();
|
||||
else
|
||||
_actorService.FinishedCreation += SetupCombos;
|
||||
_actors.Awaiter.ContinueWith(_ => SetupCombos());
|
||||
}
|
||||
|
||||
public string PlayerTooltip { get; private set; } = NewPlayerTooltipEmpty;
|
||||
|
|
@ -91,10 +91,10 @@ public class IndividualAssignmentUi : IDisposable
|
|||
// Input Selections.
|
||||
private string _newCharacterName = string.Empty;
|
||||
private ObjectKind _newKind = ObjectKind.BattleNpc;
|
||||
private ActorIdentifier[] _playerIdentifiers = Array.Empty<ActorIdentifier>();
|
||||
private ActorIdentifier[] _retainerIdentifiers = Array.Empty<ActorIdentifier>();
|
||||
private ActorIdentifier[] _npcIdentifiers = Array.Empty<ActorIdentifier>();
|
||||
private ActorIdentifier[] _ownedIdentifiers = Array.Empty<ActorIdentifier>();
|
||||
private ActorIdentifier[] _playerIdentifiers = [];
|
||||
private ActorIdentifier[] _retainerIdentifiers = [];
|
||||
private ActorIdentifier[] _npcIdentifiers = [];
|
||||
private ActorIdentifier[] _ownedIdentifiers = [];
|
||||
|
||||
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.";
|
||||
|
|
@ -126,14 +126,13 @@ public class IndividualAssignmentUi : IDisposable
|
|||
/// <summary> Create combos when ready. </summary>
|
||||
private void SetupCombos()
|
||||
{
|
||||
_worldCombo = new WorldCombo(_actorService.AwaitedService.Data.Worlds, Penumbra.Log);
|
||||
_mountCombo = new NpcCombo("##mountCombo", _actorService.AwaitedService.Data.Mounts, Penumbra.Log);
|
||||
_companionCombo = new NpcCombo("##companionCombo", _actorService.AwaitedService.Data.Companions, Penumbra.Log);
|
||||
_ornamentCombo = new NpcCombo("##ornamentCombo", _actorService.AwaitedService.Data.Ornaments, Penumbra.Log);
|
||||
_bnpcCombo = new NpcCombo("##bnpcCombo", _actorService.AwaitedService.Data.BNpcs, Penumbra.Log);
|
||||
_enpcCombo = new NpcCombo("##enpcCombo", _actorService.AwaitedService.Data.ENpcs, Penumbra.Log);
|
||||
_ready = true;
|
||||
_actorService.FinishedCreation -= SetupCombos;
|
||||
_worldCombo = new WorldCombo(_actors.Data.Worlds, Penumbra.Log, WorldId.AnyWorld);
|
||||
_mountCombo = new NpcCombo("##mountCombo", _actors.Data.Mounts, Penumbra.Log);
|
||||
_companionCombo = new NpcCombo("##companionCombo", _actors.Data.Companions, Penumbra.Log);
|
||||
_ornamentCombo = new NpcCombo("##ornamentCombo", _actors.Data.Ornaments, Penumbra.Log);
|
||||
_bnpcCombo = new NpcCombo("##bnpcCombo", _actors.Data.BNpcs, Penumbra.Log);
|
||||
_enpcCombo = new NpcCombo("##enpcCombo", _actors.Data.ENpcs, Penumbra.Log);
|
||||
_ready = true;
|
||||
}
|
||||
|
||||
private void UpdateIdentifiers(CollectionType type, ModCollection? _1, ModCollection? _2, string _3)
|
||||
|
|
@ -146,22 +145,22 @@ public class IndividualAssignmentUi : IDisposable
|
|||
{
|
||||
var combo = GetNpcCombo(_newKind);
|
||||
PlayerTooltip = _collectionManager.Active.Individuals.CanAdd(IdentifierType.Player, _newCharacterName,
|
||||
_worldCombo.CurrentSelection.Key, ObjectKind.None,
|
||||
Array.Empty<uint>(), out _playerIdentifiers) switch
|
||||
_worldCombo.CurrentSelection.Key, ObjectKind.None, [], out _playerIdentifiers) switch
|
||||
{
|
||||
_ when _newCharacterName.Length == 0 => NewPlayerTooltipEmpty,
|
||||
IndividualCollections.AddResult.Invalid => NewPlayerTooltipInvalid,
|
||||
IndividualCollections.AddResult.AlreadySet => AlreadyAssigned,
|
||||
_ => string.Empty,
|
||||
};
|
||||
RetainerTooltip = _collectionManager.Active.Individuals.CanAdd(IdentifierType.Retainer, _newCharacterName, 0, ObjectKind.None,
|
||||
Array.Empty<uint>(), out _retainerIdentifiers) switch
|
||||
{
|
||||
_ when _newCharacterName.Length == 0 => NewRetainerTooltipEmpty,
|
||||
IndividualCollections.AddResult.Invalid => NewRetainerTooltipInvalid,
|
||||
IndividualCollections.AddResult.AlreadySet => AlreadyAssigned,
|
||||
_ => string.Empty,
|
||||
};
|
||||
RetainerTooltip =
|
||||
_collectionManager.Active.Individuals.CanAdd(IdentifierType.Retainer, _newCharacterName, 0, ObjectKind.None, [],
|
||||
out _retainerIdentifiers) switch
|
||||
{
|
||||
_ when _newCharacterName.Length == 0 => NewRetainerTooltipEmpty,
|
||||
IndividualCollections.AddResult.Invalid => NewRetainerTooltipInvalid,
|
||||
IndividualCollections.AddResult.AlreadySet => AlreadyAssigned,
|
||||
_ => string.Empty,
|
||||
};
|
||||
if (combo.CurrentSelection.Ids != null)
|
||||
{
|
||||
NpcTooltip = _collectionManager.Active.Individuals.CanAdd(IdentifierType.Npc, string.Empty, ushort.MaxValue, _newKind,
|
||||
|
|
@ -184,8 +183,8 @@ public class IndividualAssignmentUi : IDisposable
|
|||
{
|
||||
NpcTooltip = NewNpcTooltipEmpty;
|
||||
OwnedTooltip = NewNpcTooltipEmpty;
|
||||
_npcIdentifiers = Array.Empty<ActorIdentifier>();
|
||||
_ownedIdentifiers = Array.Empty<ActorIdentifier>();
|
||||
_npcIdentifiers = [];
|
||||
_ownedIdentifiers = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,16 +6,16 @@ using OtterGui.Widgets;
|
|||
using Penumbra.Api.Enums;
|
||||
using Penumbra.Collections;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.Interop.ResourceLoading;
|
||||
using Penumbra.Interop.Structs;
|
||||
using Penumbra.Services;
|
||||
using Penumbra.String;
|
||||
using Penumbra.String.Classes;
|
||||
using Penumbra.UI.Classes;
|
||||
|
||||
namespace Penumbra.UI.ResourceWatcher;
|
||||
|
||||
public class ResourceWatcher : IDisposable, ITab
|
||||
public sealed class ResourceWatcher : IDisposable, ITab
|
||||
{
|
||||
public const int DefaultMaxEntries = 1024;
|
||||
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 ResourceService _resources;
|
||||
private readonly ResourceLoader _loader;
|
||||
private readonly ActorService _actors;
|
||||
private readonly List<Record> _records = new();
|
||||
private readonly ConcurrentQueue<Record> _newRecords = new();
|
||||
private readonly ActorManager _actors;
|
||||
private readonly List<Record> _records = [];
|
||||
private readonly ConcurrentQueue<Record> _newRecords = [];
|
||||
private readonly ResourceWatcherTable _table;
|
||||
private string _logFilter = string.Empty;
|
||||
private Regex? _logRegex;
|
||||
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;
|
||||
_config = config;
|
||||
|
|
@ -266,12 +266,12 @@ public class ResourceWatcher : IDisposable, ITab
|
|||
|
||||
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;
|
||||
|
||||
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.Type is not (IdentifierType.Player or IdentifierType.Owned))
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ using OtterGui;
|
|||
using OtterGui.Raii;
|
||||
using OtterGui.Widgets;
|
||||
using Penumbra.Collections.Manager;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.Mods.Manager;
|
||||
using Penumbra.Services;
|
||||
using Penumbra.UI.Classes;
|
||||
|
|
@ -14,7 +15,7 @@ using Penumbra.UI.CollectionTab;
|
|||
|
||||
namespace Penumbra.UI.Tabs;
|
||||
|
||||
public class CollectionsTab : IDisposable, ITab
|
||||
public sealed class CollectionsTab : IDisposable, ITab
|
||||
{
|
||||
private readonly EphemeralConfig _config;
|
||||
private readonly CollectionSelector _selector;
|
||||
|
|
@ -40,7 +41,7 @@ public class CollectionsTab : IDisposable, ITab
|
|||
}
|
||||
|
||||
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;
|
||||
_tutorial = tutorial;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ using OtterGui.Widgets;
|
|||
using Penumbra.Api.Enums;
|
||||
using Penumbra.Mods;
|
||||
using Penumbra.Services;
|
||||
using Penumbra.UI.Tabs.Debug;
|
||||
using Watcher = Penumbra.UI.ResourceWatcher.ResourceWatcher;
|
||||
|
||||
namespace Penumbra.UI.Tabs;
|
||||
|
|
|
|||
|
|
@ -1,24 +1,30 @@
|
|||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.Utility;
|
||||
using Dalamud.Interface.Utility.Raii;
|
||||
using Dalamud.Interface.Windowing;
|
||||
using Dalamud.Utility;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Group;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel;
|
||||
using FFXIVClientStructs.FFXIV.Client.System.Resource;
|
||||
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
|
||||
using ImGuiNET;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using OtterGui;
|
||||
using OtterGui.Classes;
|
||||
using OtterGui.Widgets;
|
||||
using Penumbra.Api;
|
||||
using Penumbra.Collections.Manager;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.DataContainers;
|
||||
using Penumbra.GameData.DataContainers.Bases;
|
||||
using Penumbra.GameData.Files;
|
||||
using Penumbra.Import.Structs;
|
||||
using Penumbra.Import.Textures;
|
||||
using Penumbra.Interop.ResourceLoading;
|
||||
using Penumbra.Interop.PathResolving;
|
||||
using Penumbra.Interop.ResourceLoading;
|
||||
using Penumbra.Interop.Services;
|
||||
using Penumbra.Interop.Structs;
|
||||
using Penumbra.Mods;
|
||||
using Penumbra.Mods.Manager;
|
||||
|
|
@ -31,22 +37,39 @@ using CharacterBase = FFXIVClientStructs.FFXIV.Client.Graphics.Scene.CharacterBa
|
|||
using CharacterUtility = Penumbra.Interop.Services.CharacterUtility;
|
||||
using ObjectKind = Dalamud.Game.ClientState.Objects.Enums.ObjectKind;
|
||||
using ResidentResourceManager = Penumbra.Interop.Services.ResidentResourceManager;
|
||||
using Penumbra.Interop.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel;
|
||||
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
|
||||
{
|
||||
private readonly StartTracker _timer;
|
||||
private readonly PerformanceTracker _performance;
|
||||
private readonly Configuration _config;
|
||||
private readonly CollectionManager _collectionManager;
|
||||
private readonly ModManager _modManager;
|
||||
private readonly ValidityChecker _validityChecker;
|
||||
private readonly HttpApi _httpApi;
|
||||
private readonly ActorService _actorService;
|
||||
private readonly ActorManager _actors;
|
||||
private readonly DalamudServices _dalamud;
|
||||
private readonly StainService _stains;
|
||||
private readonly CharacterUtility _characterUtility;
|
||||
|
|
@ -64,16 +87,17 @@ public class DebugTab : Window, ITab
|
|||
private readonly FrameworkManager _framework;
|
||||
private readonly TextureManager _textureManager;
|
||||
private readonly SkinFixer _skinFixer;
|
||||
private readonly IdentifierService _identifier;
|
||||
private readonly RedrawService _redraws;
|
||||
private readonly DictEmotes _emotes;
|
||||
private readonly Diagnostics _diagnostics;
|
||||
|
||||
public DebugTab(StartTracker timer, PerformanceTracker performance, Configuration config, CollectionManager collectionManager,
|
||||
ValidityChecker validityChecker, ModManager modManager, HttpApi httpApi, ActorService actorService,
|
||||
public DebugTab(PerformanceTracker performance, Configuration config, CollectionManager collectionManager,
|
||||
ValidityChecker validityChecker, ModManager modManager, HttpApi httpApi, ActorManager actors,
|
||||
DalamudServices dalamud, StainService stains, CharacterUtility characterUtility, ResidentResourceManager residentResources,
|
||||
ResourceManagerService resourceManager, PenumbraIpcProviders ipc, CollectionResolver collectionResolver,
|
||||
DrawObjectState drawObjectState, PathState pathState, SubfileHelper subfileHelper, IdentifiedCollectionCache identifiedCollectionCache,
|
||||
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)
|
||||
{
|
||||
IsOpen = true;
|
||||
|
|
@ -82,14 +106,13 @@ public class DebugTab : Window, ITab
|
|||
MinimumSize = new Vector2(200, 200),
|
||||
MaximumSize = new Vector2(2000, 2000),
|
||||
};
|
||||
_timer = timer;
|
||||
_performance = performance;
|
||||
_config = config;
|
||||
_collectionManager = collectionManager;
|
||||
_validityChecker = validityChecker;
|
||||
_modManager = modManager;
|
||||
_httpApi = httpApi;
|
||||
_actorService = actorService;
|
||||
_actors = actors;
|
||||
_dalamud = dalamud;
|
||||
_stains = stains;
|
||||
_characterUtility = characterUtility;
|
||||
|
|
@ -107,8 +130,9 @@ public class DebugTab : Window, ITab
|
|||
_framework = framework;
|
||||
_textureManager = textureManager;
|
||||
_skinFixer = skinFixer;
|
||||
_identifier = identifier;
|
||||
_redraws = redraws;
|
||||
_emotes = emotes;
|
||||
_diagnostics = diagnostics;
|
||||
}
|
||||
|
||||
public ReadOnlySpan<byte> Label
|
||||
|
|
@ -130,6 +154,7 @@ public class DebugTab : Window, ITab
|
|||
return;
|
||||
|
||||
DrawDebugTabGeneral();
|
||||
_diagnostics.DrawDiagnostics();
|
||||
DrawPerformanceTab();
|
||||
ImGui.NewLine();
|
||||
DrawPathResolverDebug();
|
||||
|
|
@ -357,7 +382,6 @@ public class DebugTab : Window, ITab
|
|||
ImGuiUtil.DrawTableColumn(name);
|
||||
ImGui.TableNextColumn();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -372,10 +396,7 @@ public class DebugTab : Window, ITab
|
|||
using (var start = TreeNode("Startup Performance", ImGuiTreeNodeFlags.DefaultOpen))
|
||||
{
|
||||
if (start)
|
||||
{
|
||||
_timer.Draw("##startTimer", TimingExtensions.ToName);
|
||||
ImGui.NewLine();
|
||||
}
|
||||
}
|
||||
|
||||
_performance.Draw("##performance", "Enable Runtime Performance Tracking", TimingExtensions.ToName);
|
||||
|
|
@ -391,22 +412,10 @@ public class DebugTab : Window, ITab
|
|||
if (!table)
|
||||
return;
|
||||
|
||||
void DrawSpecial(string name, ActorIdentifier id)
|
||||
{
|
||||
if (!id.IsValid)
|
||||
return;
|
||||
|
||||
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());
|
||||
DrawSpecial("Current Player", _actors.GetCurrentPlayer());
|
||||
DrawSpecial("Current Inspect", _actors.GetInspectPlayer());
|
||||
DrawSpecial("Current Card", _actors.GetCardPlayer());
|
||||
DrawSpecial("Current Glamour", _actors.GetGlamourPlayer());
|
||||
|
||||
foreach (var obj in _dalamud.Objects)
|
||||
{
|
||||
|
|
@ -415,11 +424,25 @@ public class DebugTab : Window, ITab
|
|||
ImGuiUtil.DrawTableColumn(obj.Address == nint.Zero
|
||||
? string.Empty
|
||||
: $"0x{(nint)((Character*)obj.Address)->GameObject.GetDrawObject():X}");
|
||||
var identifier = _actorService.AwaitedService.FromObject(obj, false, true, false);
|
||||
ImGuiUtil.DrawTableColumn(_actorService.AwaitedService.ToString(identifier));
|
||||
var identifier = _actors.FromObject(obj, false, true, false);
|
||||
ImGuiUtil.DrawTableColumn(_actors.ToString(identifier));
|
||||
var id = obj.ObjectKind == ObjectKind.BattleNpc ? $"{identifier.DataId} | {obj.DataId}" : identifier.DataId.ToString();
|
||||
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>
|
||||
|
|
@ -616,7 +639,7 @@ public class DebugTab : Window, ITab
|
|||
return;
|
||||
|
||||
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)
|
||||
&& (_emoteSearchName.Length == 0
|
||||
|| 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.Plugin;
|
||||
using Penumbra.UI.AdvancedWindow;
|
||||
using Penumbra.UI.Tabs;
|
||||
using Penumbra.UI.Tabs.Debug;
|
||||
|
||||
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>;
|
||||
|
||||
namespace Penumbra.Util;
|
||||
|
||||
public enum StartTimeType
|
||||
{
|
||||
Total,
|
||||
Identifier,
|
||||
Stains,
|
||||
Items,
|
||||
Actors,
|
||||
Backup,
|
||||
Mods,
|
||||
Collections,
|
||||
PathResolver,
|
||||
Interface,
|
||||
Api,
|
||||
}
|
||||
|
||||
public enum PerformanceType
|
||||
{
|
||||
UiMainWindow,
|
||||
|
|
@ -48,23 +32,6 @@ public enum PerformanceType
|
|||
|
||||
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)
|
||||
=> type switch
|
||||
{
|
||||
|
|
|
|||
|
|
@ -81,7 +81,8 @@
|
|||
"penumbra.gamedata": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Penumbra.Api": "[1.0.8, )",
|
||||
"OtterGui": "[1.0.0, )",
|
||||
"Penumbra.Api": "[1.0.13, )",
|
||||
"Penumbra.String": "[1.0.4, )"
|
||||
}
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue