mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 18:27:24 +01:00
Merge branch 'mtrl-preview-extension'
This commit is contained in:
commit
2c0650614f
42 changed files with 155 additions and 157 deletions
|
|
@ -1 +1 @@
|
||||||
Subproject commit 7c483764678c6edb5efd55f056aeaecae144d5fe
|
Subproject commit ef403be979bfac5ef805030ce76066151d36f112
|
||||||
|
|
@ -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})"
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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]
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using Penumbra.Mods.Subclasses;
|
using Penumbra.Mods.Subclasses;
|
||||||
using Penumbra.String.Classes;
|
using Penumbra.String.Classes;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
using System.IO.Compression;
|
|
||||||
using OtterGui.Tasks;
|
using OtterGui.Tasks;
|
||||||
using Penumbra.Mods.Manager;
|
using Penumbra.Mods.Manager;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using OtterGui.Classes;
|
using OtterGui.Classes;
|
||||||
using OtterGui.Widgets;
|
using OtterGui.Widgets;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
using System.Globalization;
|
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
using OtterGui.Raii;
|
using OtterGui.Raii;
|
||||||
using OtterGui;
|
using OtterGui;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
using System.Text;
|
|
||||||
using Dalamud.Interface;
|
using Dalamud.Interface;
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
using OtterGui;
|
using OtterGui;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
using OtterGui;
|
using OtterGui;
|
||||||
using OtterGui.Raii;
|
using OtterGui.Raii;
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
using System.IO.Compression;
|
|
||||||
using Lumina.Data.Structs;
|
using Lumina.Data.Structs;
|
||||||
using Lumina.Extensions;
|
using Lumina.Extensions;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue