Merge branch 'mtrl-preview-extension'

This commit is contained in:
Ottermandias 2023-09-21 02:16:22 +02:00
commit 2c0650614f
42 changed files with 155 additions and 157 deletions

@ -1 +1 @@
Subproject commit 7c483764678c6edb5efd55f056aeaecae144d5fe Subproject commit ef403be979bfac5ef805030ce76066151d36f112

View file

@ -4,7 +4,6 @@ using ImGuiNET;
using OtterGui; using OtterGui;
using OtterGui.Raii; using OtterGui.Raii;
using Penumbra.Mods; using Penumbra.Mods;
using System.Globalization;
using Dalamud.Utility; using Dalamud.Utility;
using Penumbra.Api.Enums; using Penumbra.Api.Enums;
using Penumbra.Api.Helpers; using Penumbra.Api.Helpers;
@ -17,7 +16,7 @@ using Penumbra.UI;
using Penumbra.Collections.Manager; using Penumbra.Collections.Manager;
using Dalamud.Plugin.Services; using Dalamud.Plugin.Services;
using Penumbra.GameData.Enums; using Penumbra.GameData.Enums;
using System.Diagnostics; using Penumbra.GameData.Structs;
namespace Penumbra.Api; namespace Penumbra.Api;
@ -1450,7 +1449,7 @@ public class IpcTester : IDisposable
_lastCallDuration = _stopwatch.Elapsed; _lastCallDuration = _stopwatch.Elapsed;
_lastGameObjectResourcePaths = gameObjects _lastGameObjectResourcePaths = gameObjects
.Select(GameObjectToString) .Select(i => GameObjectToString(i))
.Zip(resourcePaths) .Zip(resourcePaths)
.ToArray(); .ToArray();
@ -1482,7 +1481,7 @@ public class IpcTester : IDisposable
_lastCallDuration = _stopwatch.Elapsed; _lastCallDuration = _stopwatch.Elapsed;
_lastGameObjectResourcesOfType = gameObjects _lastGameObjectResourcesOfType = gameObjects
.Select(GameObjectToString) .Select(i => GameObjectToString(i))
.Zip(resourcesOfType) .Zip(resourcesOfType)
.ToArray(); .ToArray();
@ -1630,9 +1629,9 @@ public class IpcTester : IDisposable
.SelectWhere(index => (ushort.TryParse(index.Trim(), out var i), i)) .SelectWhere(index => (ushort.TryParse(index.Trim(), out var i), i))
.ToArray(); .ToArray();
private unsafe string GameObjectToString(ushort gameObjectIndex) private unsafe string GameObjectToString(ObjectIndex gameObjectIndex)
{ {
var gameObject = _objects[gameObjectIndex]; var gameObject = _objects[gameObjectIndex.Index];
return gameObject != null return gameObject != null
? $"[{gameObjectIndex}] {gameObject.Name} ({gameObject.ObjectKind})" ? $"[{gameObjectIndex}] {gameObject.Name} ({gameObject.ObjectKind})"

View file

@ -7,7 +7,6 @@ using Penumbra.Interop.PathResolving;
using Penumbra.Interop.Structs; using Penumbra.Interop.Structs;
using Penumbra.Meta.Manipulations; using Penumbra.Meta.Manipulations;
using Penumbra.Mods; using Penumbra.Mods;
using System.Diagnostics.CodeAnalysis;
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene; using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
using OtterGui.Compression; using OtterGui.Compression;
using Penumbra.Api.Enums; using Penumbra.Api.Enums;

View file

@ -1,4 +1,3 @@
using System.Diagnostics.CodeAnalysis;
using Penumbra.Meta; using Penumbra.Meta;
using Penumbra.Meta.Files; using Penumbra.Meta.Files;
using Penumbra.Meta.Manipulations; using Penumbra.Meta.Manipulations;

View file

@ -1,4 +1,3 @@
using System.Diagnostics.CodeAnalysis;
using Penumbra.GameData.Enums; using Penumbra.GameData.Enums;
using Penumbra.Interop.Services; using Penumbra.Interop.Services;
using Penumbra.Interop.Structs; using Penumbra.Interop.Structs;

View file

@ -1,4 +1,3 @@
using System.Diagnostics.CodeAnalysis;
using Dalamud.Interface.Internal.Notifications; using Dalamud.Interface.Internal.Notifications;
using OtterGui; using OtterGui;
using OtterGui.Filesystem; using OtterGui.Filesystem;

View file

@ -1,4 +1,3 @@
using System.Diagnostics.CodeAnalysis;
using Dalamud.Game.ClientState.Objects.Enums; using Dalamud.Game.ClientState.Objects.Enums;
using Dalamud.Game.ClientState.Objects.Types; using Dalamud.Game.ClientState.Objects.Types;
using Penumbra.GameData.Actors; using Penumbra.GameData.Actors;

View file

@ -1,4 +1,3 @@
using System.Diagnostics.CodeAnalysis;
using Dalamud.Game.ClientState.Objects.Enums; using Dalamud.Game.ClientState.Objects.Enums;
using OtterGui.Filesystem; using OtterGui.Filesystem;
using Penumbra.GameData.Actors; using Penumbra.GameData.Actors;

View file

@ -1,4 +1,3 @@
using System.Diagnostics.CodeAnalysis;
using Penumbra.Api; using Penumbra.Api;
using Penumbra.Communication; using Penumbra.Communication;
using Penumbra.GameData.Actors; using Penumbra.GameData.Actors;

View file

@ -1,7 +1,6 @@
using OtterGui.Classes; using OtterGui.Classes;
using Penumbra.GameData.Enums; using Penumbra.GameData.Enums;
using Penumbra.Mods; using Penumbra.Mods;
using System.Diagnostics.CodeAnalysis;
using Penumbra.Interop.Structs; using Penumbra.Interop.Structs;
using Penumbra.Meta.Files; using Penumbra.Meta.Files;
using Penumbra.Meta.Manipulations; using Penumbra.Meta.Manipulations;

View file

@ -5,12 +5,17 @@ global using System.Collections;
global using System.Collections.Concurrent; global using System.Collections.Concurrent;
global using System.Collections.Generic; global using System.Collections.Generic;
global using System.Diagnostics; global using System.Diagnostics;
global using System.Diagnostics.CodeAnalysis;
global using System.Globalization;
global using System.IO; global using System.IO;
global using System.IO.Compression;
global using System.Linq; global using System.Linq;
global using System.Numerics; global using System.Numerics;
global using System.Reflection; global using System.Reflection;
global using System.Runtime.CompilerServices; global using System.Runtime.CompilerServices;
global using System.Runtime.InteropServices; global using System.Runtime.InteropServices;
global using System.Security.Cryptography; global using System.Security.Cryptography;
global using System.Text;
global using System.Text.RegularExpressions;
global using System.Threading; global using System.Threading;
global using System.Threading.Tasks; global using System.Threading.Tasks;

View file

@ -1,5 +1,4 @@
using Penumbra.GameData.Enums; using Penumbra.GameData.Enums;
using System.Text.RegularExpressions;
using Penumbra.GameData; using Penumbra.GameData;
namespace Penumbra.Import.Structs; namespace Penumbra.Import.Structs;

View file

@ -1,8 +1,6 @@
using System.Text;
using Newtonsoft.Json; using Newtonsoft.Json;
using OtterGui.Compression; using OtterGui.Compression;
using Penumbra.Import.Structs; using Penumbra.Import.Structs;
using Penumbra.Mods;
using Penumbra.Mods.Editor; using Penumbra.Mods.Editor;
using Penumbra.Mods.Manager; using Penumbra.Mods.Manager;
using FileMode = System.IO.FileMode; using FileMode = System.IO.FileMode;

View file

@ -7,9 +7,9 @@ using Penumbra.Mods;
using SharpCompress.Archives; using SharpCompress.Archives;
using SharpCompress.Archives.Rar; using SharpCompress.Archives.Rar;
using SharpCompress.Archives.SevenZip; using SharpCompress.Archives.SevenZip;
using SharpCompress.Archives.Zip;
using SharpCompress.Common; using SharpCompress.Common;
using SharpCompress.Readers; using SharpCompress.Readers;
using ZipArchive = SharpCompress.Archives.Zip.ZipArchive;
namespace Penumbra.Import; namespace Penumbra.Import;

View file

@ -4,7 +4,7 @@ using Penumbra.Import.Structs;
using Penumbra.Mods; using Penumbra.Mods;
using Penumbra.Mods.Subclasses; using Penumbra.Mods.Subclasses;
using Penumbra.Util; using Penumbra.Util;
using SharpCompress.Archives.Zip; using ZipArchive = SharpCompress.Archives.Zip.ZipArchive;
namespace Penumbra.Import; namespace Penumbra.Import;

View file

@ -1,4 +1,3 @@
using System.Text;
using Penumbra.GameData.Enums; using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs; using Penumbra.GameData.Structs;
using Penumbra.Meta; using Penumbra.Meta;

View file

@ -1,4 +1,3 @@
using System.Text;
using Penumbra.GameData; using Penumbra.GameData;
using Penumbra.Import.Structs; using Penumbra.Import.Structs;
using Penumbra.Meta; using Penumbra.Meta;

View file

@ -2,6 +2,7 @@ using Dalamud.Plugin.Services;
using FFXIVClientStructs.FFXIV.Client.Game.Character; using FFXIVClientStructs.FFXIV.Client.Game.Character;
using FFXIVClientStructs.FFXIV.Client.Graphics.Render; using FFXIVClientStructs.FFXIV.Client.Graphics.Render;
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene; using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
using Penumbra.GameData.Structs;
using Penumbra.Interop.ResourceTree; using Penumbra.Interop.ResourceTree;
using Penumbra.String; using Penumbra.String;
@ -9,41 +10,20 @@ namespace Penumbra.Interop.MaterialPreview;
public enum DrawObjectType public enum DrawObjectType
{ {
PlayerCharacter, Character,
PlayerMainhand, Mainhand,
PlayerOffhand, Offhand,
PlayerVfx, Vfx,
MinionCharacter,
MinionUnk1,
MinionUnk2,
MinionUnk3,
}; };
public readonly record struct MaterialInfo(DrawObjectType Type, int ModelSlot, int MaterialSlot) public readonly record struct MaterialInfo(ObjectIndex ObjectIndex, DrawObjectType Type, int ModelSlot, int MaterialSlot)
{ {
public nint GetCharacter(IObjectTable objects) public nint GetCharacter(IObjectTable objects)
=> GetCharacter(Type, objects); => objects.GetObjectAddress(ObjectIndex.Index);
public static nint GetCharacter(DrawObjectType type, IObjectTable objects)
=> type switch
{
DrawObjectType.PlayerCharacter => objects.GetObjectAddress(0),
DrawObjectType.PlayerMainhand => objects.GetObjectAddress(0),
DrawObjectType.PlayerOffhand => objects.GetObjectAddress(0),
DrawObjectType.PlayerVfx => objects.GetObjectAddress(0),
DrawObjectType.MinionCharacter => objects.GetObjectAddress(1),
DrawObjectType.MinionUnk1 => objects.GetObjectAddress(1),
DrawObjectType.MinionUnk2 => objects.GetObjectAddress(1),
DrawObjectType.MinionUnk3 => objects.GetObjectAddress(1),
_ => nint.Zero,
};
public nint GetDrawObject(nint address) public nint GetDrawObject(nint address)
=> GetDrawObject(Type, address); => GetDrawObject(Type, address);
public static nint GetDrawObject(DrawObjectType type, IObjectTable objects)
=> GetDrawObject(type, GetCharacter(type, objects));
public static unsafe nint GetDrawObject(DrawObjectType type, nint address) public static unsafe nint GetDrawObject(DrawObjectType type, nint address)
{ {
var gameObject = (Character*)address; var gameObject = (Character*)address;
@ -52,18 +32,17 @@ public readonly record struct MaterialInfo(DrawObjectType Type, int ModelSlot, i
return type switch return type switch
{ {
DrawObjectType.PlayerCharacter => (nint)gameObject->GameObject.GetDrawObject(), DrawObjectType.Character => (nint)gameObject->GameObject.GetDrawObject(),
DrawObjectType.PlayerMainhand => *((nint*)&gameObject->DrawData.MainHand + 1), DrawObjectType.Mainhand => *((nint*)&gameObject->DrawData.MainHand + 1),
DrawObjectType.PlayerOffhand => *((nint*)&gameObject->DrawData.OffHand + 1), DrawObjectType.Offhand => *((nint*)&gameObject->DrawData.OffHand + 1),
DrawObjectType.PlayerVfx => *((nint*)&gameObject->DrawData.UnkF0 + 1), DrawObjectType.Vfx => *((nint*)&gameObject->DrawData.UnkF0 + 1),
DrawObjectType.MinionCharacter => (nint)gameObject->GameObject.GetDrawObject(), _ => nint.Zero,
DrawObjectType.MinionUnk1 => *((nint*)&gameObject->DrawData.MainHand + 1),
DrawObjectType.MinionUnk2 => *((nint*)&gameObject->DrawData.OffHand + 1),
DrawObjectType.MinionUnk3 => *((nint*)&gameObject->DrawData.UnkF0 + 1),
_ => nint.Zero,
}; };
} }
public unsafe Material* GetDrawObjectMaterial(IObjectTable objects)
=> GetDrawObjectMaterial((CharacterBase*)GetDrawObject(GetCharacter(objects)));
public unsafe Material* GetDrawObjectMaterial(CharacterBase* drawObject) public unsafe Material* GetDrawObjectMaterial(CharacterBase* drawObject)
{ {
if (drawObject == null) if (drawObject == null)
@ -82,33 +61,42 @@ public readonly record struct MaterialInfo(DrawObjectType Type, int ModelSlot, i
return model->Materials[MaterialSlot]; return model->Materials[MaterialSlot];
} }
public static unsafe List<MaterialInfo> FindMaterials(IObjectTable objects, string materialPath) public static unsafe List<MaterialInfo> FindMaterials(IEnumerable<nint> gameObjects, string materialPath)
{ {
var needle = ByteString.FromString(materialPath.Replace('\\', '/'), out var m, true) ? m : ByteString.Empty; var needle = ByteString.FromString(materialPath.Replace('\\', '/'), out var m, true) ? m : ByteString.Empty;
var result = new List<MaterialInfo>(Enum.GetValues<DrawObjectType>().Length); var result = new List<MaterialInfo>(Enum.GetValues<DrawObjectType>().Length);
foreach (var type in Enum.GetValues<DrawObjectType>()) foreach (var objectPtr in gameObjects)
{ {
var drawObject = (CharacterBase*)GetDrawObject(type, objects); var gameObject = (Character*)objectPtr;
if (drawObject == null) if (gameObject == null)
continue; continue;
for (var i = 0; i < drawObject->SlotCount; ++i) var index = (ObjectIndex) gameObject->GameObject.ObjectIndex;
foreach (var type in Enum.GetValues<DrawObjectType>())
{ {
var model = drawObject->Models[i]; var drawObject = (CharacterBase*)GetDrawObject(type, objectPtr);
if (model == null) if (drawObject == null)
continue; continue;
for (var j = 0; j < model->MaterialCount; ++j) for (var i = 0; i < drawObject->SlotCount; ++i)
{ {
var material = model->Materials[j]; var model = drawObject->Models[i];
if (material == null) if (model == null)
continue; continue;
var mtrlHandle = material->MaterialResourceHandle; for (var j = 0; j < model->MaterialCount; ++j)
var path = ResolveContext.GetResourceHandlePath((Structs.ResourceHandle*)mtrlHandle); {
if (path == needle) var material = model->Materials[j];
result.Add(new MaterialInfo(type, i, j)); if (material == null)
continue;
var mtrlHandle = material->MaterialResourceHandle;
var path = ResolveContext.GetResourceHandlePath((Structs.ResourceHandle*)mtrlHandle);
if (path == needle)
result.Add(new MaterialInfo(index, type, i, j));
}
} }
} }
} }

View file

@ -1,4 +1,3 @@
using System.Diagnostics.CodeAnalysis;
using FFXIVClientStructs.FFXIV.Client.System.Resource; using FFXIVClientStructs.FFXIV.Client.System.Resource;
using Penumbra.Api.Enums; using Penumbra.Api.Enums;
using Penumbra.Collections; using Penumbra.Collections;

View file

@ -1,4 +1,3 @@
using System.Text;
using Dalamud.Hooking; using Dalamud.Hooking;
using Penumbra.String; using Penumbra.String;
using Penumbra.String.Classes; using Penumbra.String.Classes;

View file

@ -30,21 +30,20 @@ public class ResourceTreeFactory
_actors = actors; _actors = actors;
} }
private TreeBuildCache CreateTreeBuildCache(bool withCharacters) private TreeBuildCache CreateTreeBuildCache()
=> new(_objects, _gameData, _actors, withCharacters); => new(_objects, _gameData, _actors);
public IEnumerable<Dalamud.Game.ClientState.Objects.Types.Character> GetLocalPlayerRelatedCharacters() public IEnumerable<Dalamud.Game.ClientState.Objects.Types.Character> GetLocalPlayerRelatedCharacters()
{ {
var cache = CreateTreeBuildCache(true); var cache = CreateTreeBuildCache();
return cache.GetLocalPlayerRelatedCharacters();
return cache.Characters.Where(cache.IsLocalPlayerRelated);
} }
public IEnumerable<(Dalamud.Game.ClientState.Objects.Types.Character Character, ResourceTree ResourceTree)> FromObjectTable( public IEnumerable<(Dalamud.Game.ClientState.Objects.Types.Character Character, ResourceTree ResourceTree)> FromObjectTable(
Flags flags) Flags flags)
{ {
var cache = CreateTreeBuildCache(true); var cache = CreateTreeBuildCache();
var characters = (flags & Flags.LocalPlayerRelatedOnly) != 0 ? cache.Characters.Where(cache.IsLocalPlayerRelated) : cache.Characters; var characters = (flags & Flags.LocalPlayerRelatedOnly) != 0 ? cache.GetLocalPlayerRelatedCharacters() : cache.GetCharacters();
foreach (var character in characters) foreach (var character in characters)
{ {
@ -57,7 +56,7 @@ public class ResourceTreeFactory
public IEnumerable<(Dalamud.Game.ClientState.Objects.Types.Character Character, ResourceTree ResourceTree)> FromCharacters( public IEnumerable<(Dalamud.Game.ClientState.Objects.Types.Character Character, ResourceTree ResourceTree)> FromCharacters(
IEnumerable<Dalamud.Game.ClientState.Objects.Types.Character> characters, Flags flags) IEnumerable<Dalamud.Game.ClientState.Objects.Types.Character> characters, Flags flags)
{ {
var cache = CreateTreeBuildCache((flags & Flags.WithOwnership) != 0); var cache = CreateTreeBuildCache();
foreach (var character in characters) foreach (var character in characters)
{ {
var tree = FromCharacter(character, cache, flags); var tree = FromCharacter(character, cache, flags);
@ -67,7 +66,7 @@ public class ResourceTreeFactory
} }
public ResourceTree? FromCharacter(Dalamud.Game.ClientState.Objects.Types.Character character, Flags flags) public ResourceTree? FromCharacter(Dalamud.Game.ClientState.Objects.Types.Character character, Flags flags)
=> FromCharacter(character, CreateTreeBuildCache((flags & Flags.WithOwnership) != 0), flags); => FromCharacter(character, CreateTreeBuildCache(), flags);
private unsafe ResourceTree? FromCharacter(Dalamud.Game.ClientState.Objects.Types.Character character, TreeBuildCache cache, Flags flags) private unsafe ResourceTree? FromCharacter(Dalamud.Game.ClientState.Objects.Types.Character character, TreeBuildCache cache, Flags flags)
{ {
@ -136,7 +135,7 @@ public class ResourceTreeFactory
if (filteredList.Count > 0) if (filteredList.Count > 0)
resolvedList = filteredList; resolvedList = filteredList;
} }
if (resolvedList.Count != 1) if (resolvedList.Count != 1)
{ {
Penumbra.Log.Debug( Penumbra.Log.Debug(
@ -216,27 +215,22 @@ public class ResourceTreeFactory
private unsafe (string Name, bool PlayerRelated) GetCharacterName(Dalamud.Game.ClientState.Objects.Types.Character character, private unsafe (string Name, bool PlayerRelated) GetCharacterName(Dalamud.Game.ClientState.Objects.Types.Character character,
TreeBuildCache cache) TreeBuildCache cache)
{ {
var identifier = _actors.AwaitedService.FromObject((GameObject*)character.Address, out var owner, true, false, false); var identifier = _actors.AwaitedService.FromObject((GameObject*)character.Address, out var owner, true, false, false);
string name;
bool playerRelated;
switch (identifier.Type) switch (identifier.Type)
{ {
case IdentifierType.Player: case IdentifierType.Player: return (identifier.PlayerName.ToString(), true);
name = identifier.PlayerName.ToString(); case IdentifierType.Owned:
playerRelated = true; var ownerChara = _objects.CreateObjectReference((nint)owner) as Dalamud.Game.ClientState.Objects.Types.Character;
break; if (ownerChara != null)
case IdentifierType.Owned when cache.CharactersById.TryGetValue(owner->ObjectID, out var ownerChara): {
var ownerName = GetCharacterName(ownerChara, cache); var ownerName = GetCharacterName(ownerChara, cache);
name = $"[{ownerName.Name}] {character.Name} ({identifier.Kind.ToName()})"; return ($"[{ownerName.Name}] {character.Name} ({identifier.Kind.ToName()})", ownerName.PlayerRelated);
playerRelated = ownerName.PlayerRelated; }
break;
default:
name = $"{character.Name} ({identifier.Kind.ToName()})";
playerRelated = false;
break; break;
} }
return (name, playerRelated); return ($"{character.Name} ({identifier.Kind.ToName()})", false);
} }
[Flags] [Flags]

View file

@ -1,55 +1,103 @@
using Dalamud.Game.ClientState.Objects.Types; using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Plugin.Services; using Dalamud.Plugin.Services;
using Penumbra.GameData.Actors;
using Penumbra.GameData.Files; using Penumbra.GameData.Files;
using Penumbra.Interop.Services; using Penumbra.GameData.Structs;
using Penumbra.Services; using Penumbra.Services;
using Penumbra.String;
using Penumbra.String.Classes; using Penumbra.String.Classes;
namespace Penumbra.Interop.ResourceTree; namespace Penumbra.Interop.ResourceTree;
internal class TreeBuildCache internal readonly struct TreeBuildCache
{ {
private readonly IDataManager _dataManager; private readonly IDataManager _dataManager;
private readonly ActorService _actors; private readonly ActorService _actors;
private readonly Dictionary<FullPath, ShpkFile?> _shaderPackages = new(); private readonly Dictionary<FullPath, ShpkFile?> _shaderPackages = new();
private readonly uint _localPlayerId; private readonly IObjectTable _objects;
public readonly List<Character> Characters;
public readonly Dictionary<uint, Character> CharactersById;
public TreeBuildCache(IObjectTable objects, IDataManager dataManager, ActorService actors, bool withCharacters) public TreeBuildCache(IObjectTable objects, IDataManager dataManager, ActorService actors)
{ {
_dataManager = dataManager; _dataManager = dataManager;
_actors = actors; _objects = objects;
_localPlayerId = objects[0]?.ObjectId ?? GameObject.InvalidGameObjectId; _actors = actors;
if (withCharacters)
{
Characters = objects.OfType<Character>().Where(ch => ch.IsValid()).ToList();
CharactersById = Characters
.Where(c => c.ObjectId != GameObject.InvalidGameObjectId)
.GroupBy(c => c.ObjectId)
.ToDictionary(c => c.Key, c => c.First());
}
else
{
Characters = new();
CharactersById = new();
}
} }
public unsafe bool IsLocalPlayerRelated(Character character) public unsafe bool IsLocalPlayerRelated(Character character)
{ {
if (_localPlayerId == GameObject.InvalidGameObjectId) var player = _objects[0];
if (player == null)
return false; return false;
// Index 0 is the local player, index 1 is the mount/minion/accessory. var gameObject = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)character.Address;
if (character.ObjectIndex < 2 || character.ObjectIndex == RedrawService.GPosePlayerIdx) var parent = _actors.AwaitedService.ToCutsceneParent(gameObject->ObjectIndex);
return true; var actualIndex = parent >= 0 ? (ushort)parent : gameObject->ObjectIndex;
return actualIndex switch
{
< 2 => true,
< (int)ScreenActor.CutsceneStart => gameObject->OwnerID == player.ObjectId,
_ => false,
};
}
if (!_actors.AwaitedService.FromObject(character, out var owner, true, false, false).IsValid) public IEnumerable<Character> GetCharacters()
=> _objects.OfType<Character>();
public IEnumerable<Character> GetLocalPlayerRelatedCharacters()
{
var player = _objects[0];
if (player == null)
yield break;
yield return (Character)player;
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)
yield return owned;
}
for (var i = ObjectIndex.CutsceneStart.Index; i < ObjectIndex.CharacterScreen.Index; ++i)
{
var character = _objects[i] as Character;
if (character == null)
continue;
var parent = _actors.AwaitedService.ToCutsceneParent(i);
if (parent < 0)
continue;
if (parent is 0 or 1 || _objects[parent]?.OwnerId == playerId)
yield return character;
}
}
private unsafe ByteString GetPlayerName(GameObject player)
{
var gameObject = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)player.Address;
return new ByteString(gameObject->Name);
}
private unsafe bool GetOwnedId(ByteString playerName, uint playerId, int idx, [NotNullWhen(true)] out Character? character)
{
character = _objects[idx] as Character;
if (character == null)
return false; return false;
// Check for SMN/SCH pet, chocobo and other owned NPCs. var actorId = _actors.AwaitedService.FromObject(character, out var owner, true, true, true);
return owner != null && owner->ObjectID == _localPlayerId; if (!actorId.IsValid)
return false;
if (owner != null && owner->OwnerID != playerId)
return false;
if (actorId.Type is not IdentifierType.Player || !actorId.PlayerName.Equals(playerName))
return false;
return true;
} }
/// <summary> Try to read a shpk file from the given path and cache it on success. </summary> /// <summary> Try to read a shpk file from the given path and cache it on success. </summary>

View file

@ -1,4 +1,3 @@
using System.Diagnostics.CodeAnalysis;
using Penumbra.Mods.Subclasses; using Penumbra.Mods.Subclasses;
using Penumbra.String.Classes; using Penumbra.String.Classes;

View file

@ -1,5 +1,3 @@
using System.Text;
using System.Text.RegularExpressions;
using OtterGui; using OtterGui;
using OtterGui.Compression; using OtterGui.Compression;
using Penumbra.GameData.Enums; using Penumbra.GameData.Enums;

View file

@ -1,4 +1,3 @@
using System.IO.Compression;
using OtterGui.Tasks; using OtterGui.Tasks;
using Penumbra.Mods.Manager; using Penumbra.Mods.Manager;

View file

@ -1,5 +1,3 @@
using System.Diagnostics.CodeAnalysis;
using System.Text.RegularExpressions;
using Penumbra.Api.Enums; using Penumbra.Api.Enums;
using Penumbra.GameData.Data; using Penumbra.GameData.Data;
using Penumbra.GameData.Enums; using Penumbra.GameData.Enums;

View file

@ -1,5 +1,3 @@
using System.Diagnostics.CodeAnalysis;
using System.Text.RegularExpressions;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using OtterGui.Classes; using OtterGui.Classes;
using OtterGui.Filesystem; using OtterGui.Filesystem;

View file

@ -1,4 +1,3 @@
using System.Diagnostics.CodeAnalysis;
using Dalamud.Interface.Internal.Notifications; using Dalamud.Interface.Internal.Notifications;
using Penumbra.Import; using Penumbra.Import;
using Penumbra.Mods.Editor; using Penumbra.Mods.Editor;

View file

@ -1,4 +1,3 @@
using System.Text.RegularExpressions;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using OtterGui; using OtterGui;

View file

@ -1,4 +1,3 @@
using System.Diagnostics.CodeAnalysis;
using OtterGui.Classes; using OtterGui.Classes;
using OtterGui.Widgets; using OtterGui.Widgets;

View file

@ -1,5 +1,3 @@
using System.Text;
using System.Text.RegularExpressions;
using Dalamud.Interface.Internal.Notifications; using Dalamud.Interface.Internal.Notifications;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;

View file

@ -1,4 +1,3 @@
using System.Text;
using Dalamud.Plugin; using Dalamud.Plugin;
using ImGuiNET; using ImGuiNET;
using Lumina.Excel.GeneratedSheets; using Lumina.Excel.GeneratedSheets;

View file

@ -1,4 +1,3 @@
using System.Globalization;
using ImGuiNET; using ImGuiNET;
using OtterGui.Raii; using OtterGui.Raii;
using OtterGui; using OtterGui;

View file

@ -454,13 +454,12 @@ public partial class ModEditWindow
{ {
UnbindFromMaterialInstances(); UnbindFromMaterialInstances();
var instances = MaterialInfo.FindMaterials(_edit._dalamud.Objects, FilePath); var instances = MaterialInfo.FindMaterials(_edit._resourceTreeFactory.GetLocalPlayerRelatedCharacters().Select(ch => ch.Address), FilePath);
var foundMaterials = new HashSet<nint>(); var foundMaterials = new HashSet<nint>();
foreach (var materialInfo in instances) foreach (var materialInfo in instances)
{ {
var drawObject = (CharacterBase*)MaterialInfo.GetDrawObject(materialInfo.Type, _edit._dalamud.Objects); var material = materialInfo.GetDrawObjectMaterial(_edit._dalamud.Objects);
var material = materialInfo.GetDrawObjectMaterial(drawObject);
if (foundMaterials.Contains((nint)material)) if (foundMaterials.Contains((nint)material))
continue; continue;

View file

@ -1,4 +1,3 @@
using System.Text;
using Dalamud.Interface; using Dalamud.Interface;
using ImGuiNET; using ImGuiNET;
using OtterGui; using OtterGui;

View file

@ -3,7 +3,6 @@ using OtterGui;
using OtterGui.Raii; using OtterGui.Raii;
using Penumbra.GameData.Files; using Penumbra.GameData.Files;
using Penumbra.String.Classes; using Penumbra.String.Classes;
using System.Globalization;
namespace Penumbra.UI.AdvancedWindow; namespace Penumbra.UI.AdvancedWindow;

View file

@ -14,6 +14,7 @@ namespace Penumbra.UI.AdvancedWindow;
public partial class ModEditWindow public partial class ModEditWindow
{ {
private readonly ResourceTreeFactory _resourceTreeFactory;
private readonly ResourceTreeViewer _quickImportViewer; private readonly ResourceTreeViewer _quickImportViewer;
private readonly Dictionary<FullPath, IWritable?> _quickImportWritables = new(); private readonly Dictionary<FullPath, IWritable?> _quickImportWritables = new();
private readonly Dictionary<(Utf8GamePath, IWritable?), QuickImportAction> _quickImportActions = new(); private readonly Dictionary<(Utf8GamePath, IWritable?), QuickImportAction> _quickImportActions = new();

View file

@ -1,4 +1,3 @@
using System.Text;
using Dalamud.Interface.Internal.Notifications; using Dalamud.Interface.Internal.Notifications;
using Dalamud.Interface; using Dalamud.Interface;
using ImGuiNET; using ImGuiNET;

View file

@ -1,4 +1,3 @@
using System.Diagnostics.CodeAnalysis;
using ImGuiNET; using ImGuiNET;
using OtterGui; using OtterGui;
using OtterGui.Raii; using OtterGui.Raii;

View file

@ -1,4 +1,3 @@
using System.Text;
using Dalamud.Interface; using Dalamud.Interface;
using Dalamud.Interface.Components; using Dalamud.Interface.Components;
using Dalamud.Interface.DragDrop; using Dalamud.Interface.DragDrop;
@ -576,9 +575,10 @@ public partial class ModEditWindow : Window, IDisposable
_shaderPackageTab = new FileEditor<ShpkTab>(this, gameData, config, _editor.Compactor, _fileDialog, "Shaders", ".shpk", _shaderPackageTab = new FileEditor<ShpkTab>(this, gameData, config, _editor.Compactor, _fileDialog, "Shaders", ".shpk",
() => _editor.Files.Shpk, DrawShaderPackagePanel, () => _mod?.ModPath.FullName ?? string.Empty, () => _editor.Files.Shpk, DrawShaderPackagePanel, () => _mod?.ModPath.FullName ?? string.Empty,
(bytes, _, _) => new ShpkTab(_fileDialog, bytes)); (bytes, _, _) => new ShpkTab(_fileDialog, bytes));
_center = new CombinedTexture(_left, _right); _center = new CombinedTexture(_left, _right);
_textureSelectCombo = new TextureDrawer.PathSelectCombo(textures, editor); _textureSelectCombo = new TextureDrawer.PathSelectCombo(textures, editor);
_quickImportViewer = _resourceTreeFactory = resourceTreeFactory;
_quickImportViewer =
new ResourceTreeViewer(_config, resourceTreeFactory, changedItemDrawer, 2, OnQuickImportRefresh, DrawQuickImportActions); new ResourceTreeViewer(_config, resourceTreeFactory, changedItemDrawer, 2, OnQuickImportRefresh, DrawQuickImportActions);
_communicator.ModPathChanged.Subscribe(OnModPathChanged, ModPathChanged.Priority.ModEditWindow); _communicator.ModPathChanged.Subscribe(OnModPathChanged, ModPathChanged.Priority.ModEditWindow);
} }

View file

@ -1,4 +1,3 @@
using System.Text.RegularExpressions;
using FFXIVClientStructs.FFXIV.Client.Game.Object; using FFXIVClientStructs.FFXIV.Client.Game.Object;
using FFXIVClientStructs.FFXIV.Client.System.Resource; using FFXIVClientStructs.FFXIV.Client.System.Resource;
using ImGuiNET; using ImGuiNET;

View file

@ -1,4 +1,3 @@
using System.IO.Compression;
using Lumina.Data.Structs; using Lumina.Data.Structs;
using Lumina.Extensions; using Lumina.Extensions;