mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 10:17:22 +01:00
Current state.
This commit is contained in:
parent
c54141be54
commit
e3a1ae6938
20 changed files with 104 additions and 43 deletions
2
OtterGui
2
OtterGui
|
|
@ -1 +1 @@
|
|||
Subproject commit 3e6b085749741f35dd6732c33d0720c6a51ebb97
|
||||
Subproject commit 8ba88eff15326bb28ed5e6157f5252c114d40b5f
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit e39a04c83b67246580492677414888357b5ebed8
|
||||
Subproject commit fb81a0b55d3c68f2b26357fac3049c79fb0c22fb
|
||||
|
|
@ -33,25 +33,27 @@ public sealed unsafe class ApricotListenerSoundPlayCaller : FastHook<ApricotList
|
|||
private nint Detour(nint a1, nint unused, float timeOffset)
|
||||
{
|
||||
// Short-circuiting and sanity checks done by game.
|
||||
var playTime = a1 == nint.Zero ? -1 : *(float*)(a1 + 0x250);
|
||||
var playTime = a1 == nint.Zero ? -1 : *(float*)(a1 + VolatileOffsets.ApricotListenerSoundPlayCaller.PlayTimeOffset);
|
||||
if (playTime < 0)
|
||||
return Task.Result.Original(a1, unused, timeOffset);
|
||||
|
||||
var someIntermediate = *(nint*)(a1 + 0x1F8);
|
||||
var flags = someIntermediate == nint.Zero ? (ushort)0 : *(ushort*)(someIntermediate + 0x49C);
|
||||
if (((flags >> 13) & 1) == 0)
|
||||
var someIntermediate = *(nint*)(a1 + VolatileOffsets.ApricotListenerSoundPlayCaller.SomeIntermediate);
|
||||
var flags = someIntermediate == nint.Zero
|
||||
? (ushort)0
|
||||
: *(ushort*)(someIntermediate + VolatileOffsets.ApricotListenerSoundPlayCaller.Flags);
|
||||
if (((flags >> VolatileOffsets.ApricotListenerSoundPlayCaller.BitShift) & 1) == 0)
|
||||
return Task.Result.Original(a1, unused, timeOffset);
|
||||
|
||||
Penumbra.Log.Excessive(
|
||||
$"[Apricot Listener Sound Play Caller] Invoked on 0x{a1:X} with {unused}, {timeOffset}.");
|
||||
// Fetch the IInstanceListenner (sixth argument to inlined call of SoundPlay)
|
||||
var apricotIInstanceListenner = *(nint*)(someIntermediate + 0x270);
|
||||
var apricotIInstanceListenner = *(nint*)(someIntermediate + VolatileOffsets.ApricotListenerSoundPlayCaller.IInstanceListenner);
|
||||
if (apricotIInstanceListenner == nint.Zero)
|
||||
return Task.Result.Original(a1, unused, timeOffset);
|
||||
|
||||
// In some cases we can obtain the associated caster via vfunc 1.
|
||||
var newData = ResolveData.Invalid;
|
||||
var gameObject = (*(delegate* unmanaged<nint, GameObject*>**)apricotIInstanceListenner)[1](apricotIInstanceListenner);
|
||||
var gameObject = (*(delegate* unmanaged<nint, GameObject*>**)apricotIInstanceListenner)[VolatileOffsets.ApricotListenerSoundPlayCaller.CasterVFunc](apricotIInstanceListenner);
|
||||
if (gameObject != null)
|
||||
{
|
||||
newData = _collectionResolver.IdentifyCollection(gameObject, true);
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ public sealed unsafe class SomePapLoad : FastHook<SomePapLoad.Delegate>
|
|||
private void Detour(nint a1, int a2, nint a3, int a4)
|
||||
{
|
||||
Penumbra.Log.Excessive($"[Some PAP Load] Invoked on 0x{a1:X} with {a2}, {a3}, {a4}.");
|
||||
var timelinePtr = a1 + Offsets.TimeLinePtr;
|
||||
var timelinePtr = a1 + VolatileOffsets.AnimationState.TimeLinePtr;
|
||||
if (timelinePtr != nint.Zero)
|
||||
{
|
||||
var actorIdx = (int)(*(*(ulong**)timelinePtr + 1) >> 3);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
||||
using OtterGui.Services;
|
||||
using Penumbra.Interop.PathResolving;
|
||||
using Character = FFXIVClientStructs.FFXIV.Client.Game.Character.Character;
|
||||
|
||||
namespace Penumbra.Interop.Hooks.Meta;
|
||||
|
||||
|
|
@ -13,19 +13,20 @@ public sealed unsafe class CalculateHeight : FastHook<CalculateHeight.Delegate>
|
|||
public CalculateHeight(HookManager hooks, CollectionResolver collectionResolver, MetaState metaState)
|
||||
{
|
||||
_collectionResolver = collectionResolver;
|
||||
_metaState = metaState;
|
||||
Task = hooks.CreateHook<Delegate>("Calculate Height", (nint)Character.MemberFunctionPointers.CalculateHeight, Detour, !HookOverrides.Instance.Meta.CalculateHeight);
|
||||
_metaState = metaState;
|
||||
Task = hooks.CreateHook<Delegate>("Calculate Height", (nint)HeightContainer.MemberFunctionPointers.CalculateHeight, Detour,
|
||||
!HookOverrides.Instance.Meta.CalculateHeight);
|
||||
}
|
||||
|
||||
public delegate ulong Delegate(Character* character);
|
||||
public delegate ulong Delegate(HeightContainer* character);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
private ulong Detour(Character* character)
|
||||
private ulong Detour(HeightContainer* container)
|
||||
{
|
||||
var collection = _collectionResolver.IdentifyCollection((GameObject*)character, true);
|
||||
var collection = _collectionResolver.IdentifyCollection((GameObject*)container->OwnerObject, true);
|
||||
_metaState.RspCollection.Push(collection);
|
||||
var ret = Task.Result.Original.Invoke(character);
|
||||
Penumbra.Log.Excessive($"[Calculate Height] Invoked on {(nint)character:X} -> {ret}.");
|
||||
var ret = Task.Result.Original.Invoke(container);
|
||||
Penumbra.Log.Excessive($"[Calculate Height] Invoked on {(nint)container:X} -> {ret}.");
|
||||
_metaState.RspCollection.Pop();
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ public sealed unsafe class UpdateModel : FastHook<UpdateModel.Delegate>
|
|||
{
|
||||
// Shortcut because this is called all the time.
|
||||
// Same thing is checked at the beginning of the original function.
|
||||
if (*(int*)((nint)drawObject + Offsets.UpdateModelSkip) == 0)
|
||||
if (*(int*)((nint)drawObject + VolatileOffsets.UpdateModel.ShortCircuit) == 0)
|
||||
return;
|
||||
|
||||
Penumbra.Log.Excessive($"[Update Model] Invoked on {(nint)drawObject:X}.");
|
||||
|
|
|
|||
|
|
@ -401,7 +401,6 @@ public sealed unsafe class ShaderReplacementFixer : IDisposable, IRequiredServic
|
|||
private void ModelRendererUnkFuncDetour(CSModelRenderer* modelRenderer, ModelRendererStructs.UnkPayload* unkPayload, uint unk2, uint unk3,
|
||||
uint unk4, uint unk5)
|
||||
{
|
||||
// If we don't have any on-screen instances of modded iris.shpk or others, we don't need the slow path at all.
|
||||
if (!Enabled || GetTotalMaterialCountForModelRendererUnk() == 0)
|
||||
{
|
||||
_modelRendererUnkFuncHook.Original(modelRenderer, unkPayload, unk2, unk3, unk4, unk5);
|
||||
|
|
|
|||
|
|
@ -240,7 +240,7 @@ public sealed unsafe class CollectionResolver(
|
|||
}
|
||||
|
||||
// Only handle human models.
|
||||
if (!IsModelHuman((uint)actor.AsCharacter->CharacterData.ModelCharaId))
|
||||
if (!IsModelHuman((uint)actor.AsCharacter->ModelCharaId))
|
||||
return null;
|
||||
|
||||
if (actor.Customize->Data[0] == 0)
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ public class ResourceTree
|
|||
Unsafe.AsPointer(ref character->DrawData.EquipmentModelIds[0]), 10),
|
||||
_ => [],
|
||||
};
|
||||
ModelId = character->CharacterData.ModelCharaId;
|
||||
ModelId = character->ModelCharaId;
|
||||
CustomizeData = character->DrawData.CustomizeData;
|
||||
RaceCode = human != null ? (GenderRace)human->RaceSexId : GenderRace.Unknown;
|
||||
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ public unsafe class FontReloader : IService
|
|||
return;
|
||||
|
||||
_atkModule = &atkModule->AtkModule;
|
||||
_reloadFontsFunc = ((delegate* unmanaged<AtkModule*, bool, bool, void>*)_atkModule->VirtualTable)[Offsets.ReloadFontsVfunc];
|
||||
_reloadFontsFunc = ((delegate* unmanaged<AtkModule*, bool, bool, void>*)_atkModule->VirtualTable)[VolatileOffsets.FontReloader.ReloadFontsVFunc];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,10 +38,10 @@ public unsafe partial class RedrawService : IService
|
|||
|
||||
// VFuncs that disable and enable draw, used only for GPose actors.
|
||||
private static void DisableDraw(IGameObject actor)
|
||||
=> ((delegate* unmanaged<nint, void >**)actor.Address)[0][Offsets.DisableDrawVfunc](actor.Address);
|
||||
=> ((delegate* unmanaged<nint, void >**)actor.Address)[0][VolatileOffsets.RedrawService.DisableDrawVFunc](actor.Address);
|
||||
|
||||
private static void EnableDraw(IGameObject actor)
|
||||
=> ((delegate* unmanaged<nint, void >**)actor.Address)[0][Offsets.EnableDrawVfunc](actor.Address);
|
||||
=> ((delegate* unmanaged<nint, void >**)actor.Address)[0][VolatileOffsets.RedrawService.EnableDrawVFunc](actor.Address);
|
||||
|
||||
// Check whether we currently are in GPose.
|
||||
// Also clear the name list.
|
||||
|
|
|
|||
35
Penumbra/Interop/VolatileOffsets.cs
Normal file
35
Penumbra/Interop/VolatileOffsets.cs
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
namespace Penumbra.Interop;
|
||||
|
||||
public static class VolatileOffsets
|
||||
{
|
||||
public static class ApricotListenerSoundPlayCaller
|
||||
{
|
||||
public const int PlayTimeOffset = 0x254;
|
||||
public const int SomeIntermediate = 0x1F8;
|
||||
public const int Flags = 0x4A4;
|
||||
public const int IInstanceListenner = 0x270;
|
||||
public const int BitShift = 13;
|
||||
public const int CasterVFunc = 1;
|
||||
}
|
||||
|
||||
public static class AnimationState
|
||||
{
|
||||
public const int TimeLinePtr = 0x50;
|
||||
}
|
||||
|
||||
public static class UpdateModel
|
||||
{
|
||||
public const int ShortCircuit = 0xA2C;
|
||||
}
|
||||
|
||||
public static class FontReloader
|
||||
{
|
||||
public const int ReloadFontsVFunc = 43;
|
||||
}
|
||||
|
||||
public static class RedrawService
|
||||
{
|
||||
public const int EnableDrawVFunc = 12;
|
||||
public const int DisableDrawVFunc = 13;
|
||||
}
|
||||
}
|
||||
|
|
@ -138,7 +138,7 @@ public sealed class ImcModGroupEditor(CommunicatorService communicator, SaveServ
|
|||
|
||||
protected override bool MoveOption(ImcModGroup group, int optionIdxFrom, int optionIdxTo)
|
||||
{
|
||||
if (!group.OptionData.Move(optionIdxFrom, optionIdxTo))
|
||||
if (!group.OptionData.Move(ref optionIdxFrom, ref optionIdxTo))
|
||||
return false;
|
||||
|
||||
group.DefaultSettings = group.DefaultSettings.MoveBit(optionIdxFrom, optionIdxTo);
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ public class ModGroupEditor(
|
|||
{
|
||||
var mod = group.Mod;
|
||||
var idxFrom = group.GetIndex();
|
||||
if (!mod.Groups.Move(idxFrom, groupIdxTo))
|
||||
if (!mod.Groups.Move(ref idxFrom, ref groupIdxTo))
|
||||
return;
|
||||
|
||||
saveService.SaveAllOptionGroups(mod, false, config.ReplaceNonAsciiOnImport);
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ public sealed class MultiModGroupEditor(CommunicatorService communicator, SaveSe
|
|||
|
||||
protected override bool MoveOption(MultiModGroup group, int optionIdxFrom, int optionIdxTo)
|
||||
{
|
||||
if (!group.OptionData.Move(optionIdxFrom, optionIdxTo))
|
||||
if (!group.OptionData.Move(ref optionIdxFrom, ref optionIdxTo))
|
||||
return false;
|
||||
|
||||
group.DefaultSettings = group.DefaultSettings.MoveBit(optionIdxFrom, optionIdxTo);
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ public sealed class SingleModGroupEditor(CommunicatorService communicator, SaveS
|
|||
|
||||
protected override bool MoveOption(SingleModGroup group, int optionIdxFrom, int optionIdxTo)
|
||||
{
|
||||
if (!group.OptionData.Move(optionIdxFrom, optionIdxTo))
|
||||
if (!group.OptionData.Move(ref optionIdxFrom, ref optionIdxTo))
|
||||
return false;
|
||||
|
||||
group.DefaultSettings = group.DefaultSettings.MoveSingle(optionIdxFrom, optionIdxTo);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
using Dalamud.Plugin;
|
||||
using ImGuiNET;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using OtterGui;
|
||||
using OtterGui.Log;
|
||||
using OtterGui.Services;
|
||||
|
|
@ -20,6 +19,7 @@ using OtterGui.Tasks;
|
|||
using Penumbra.UI;
|
||||
using ResidentResourceManager = Penumbra.Interop.Services.ResidentResourceManager;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Lumina.Excel.Sheets;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.Interop.Hooks;
|
||||
using Penumbra.Interop.Hooks.ResourceLoading;
|
||||
|
|
@ -111,7 +111,7 @@ public class Penumbra : IDalamudPlugin
|
|||
private void SetupApi()
|
||||
{
|
||||
_services.GetService<IpcProviders>();
|
||||
var itemSheet = _services.GetService<IDataManager>().GetExcelSheet<Item>()!;
|
||||
var itemSheet = _services.GetService<IDataManager>().GetExcelSheet<Item>();
|
||||
_communicatorService.ChangedItemHover.Subscribe(it =>
|
||||
{
|
||||
if (it is IdentifiedItem { Item.Id.IsItem: true })
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ using Dalamud.Game.Text.SeStringHandling.Payloads;
|
|||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.ImGuiNotification;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using Lumina.Excel.Sheets;
|
||||
using OtterGui.Log;
|
||||
using OtterGui.Services;
|
||||
using Penumbra.Mods.Manager;
|
||||
|
|
@ -16,7 +16,7 @@ namespace Penumbra.Services;
|
|||
public class MessageService(Logger log, IUiBuilder builder, IChatGui chat, INotificationManager notificationManager)
|
||||
: OtterGui.Classes.MessageService(log, builder, chat, notificationManager), IService
|
||||
{
|
||||
public void LinkItem(Item item)
|
||||
public void LinkItem(in Item item)
|
||||
{
|
||||
// @formatter:off
|
||||
var payloadList = new List<Payload>
|
||||
|
|
@ -29,7 +29,7 @@ public class MessageService(Logger log, IUiBuilder builder, IChatGui chat, INoti
|
|||
new TextPayload($"{(char)SeIconChar.LinkMarker}"),
|
||||
new UIForegroundPayload(0),
|
||||
new UIGlowPayload(0),
|
||||
new TextPayload(item.Name),
|
||||
new TextPayload(item.Name.ExtractText()),
|
||||
new RawPayload([0x02, 0x27, 0x07, 0xCF, 0x01, 0x01, 0x01, 0xFF, 0x01, 0x03]),
|
||||
new RawPayload([0x02, 0x13, 0x02, 0xEC, 0x03]),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -54,6 +54,9 @@ public class Diagnostics(ServiceManager provider) : IUiService
|
|||
return;
|
||||
|
||||
using var table = ImRaii.Table("##data", 4, ImGuiTableFlags.RowBg);
|
||||
if (!table)
|
||||
return;
|
||||
|
||||
foreach (var type in typeof(ActorManager).Assembly.GetTypes()
|
||||
.Where(t => t is { IsAbstract: false, IsInterface: false } && t.IsAssignableTo(typeof(IAsyncDataContainer))))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -34,28 +34,49 @@ public class HookOverrideDrawer(IDalamudPluginInterface pluginInterface) : IUiSe
|
|||
Penumbra.Log.Error($"Could not delete hook override file at {path}:\n{ex}");
|
||||
}
|
||||
|
||||
bool? allVisible = null;
|
||||
ImGui.SameLine();
|
||||
if (ImUtf8.Button("Disable All Visible Hooks"u8))
|
||||
allVisible = true;
|
||||
ImGui.SameLine();
|
||||
if (ImUtf8.Button("Enable All VisibleHooks"u8))
|
||||
allVisible = false;
|
||||
|
||||
bool? all = null;
|
||||
ImGui.SameLine();
|
||||
if (ImUtf8.Button("Disable All Hooks"u8))
|
||||
if (ImUtf8.Button("Disable All Hooks"))
|
||||
all = true;
|
||||
ImGui.SameLine();
|
||||
if (ImUtf8.Button("Enable All Hooks"u8))
|
||||
if (ImUtf8.Button("Enable All Hooks"))
|
||||
all = false;
|
||||
|
||||
foreach (var propertyField in typeof(HookOverrides).GetFields().Where(f => f is { IsStatic: false, FieldType.IsValueType: true }))
|
||||
{
|
||||
using var tree = ImUtf8.TreeNode(propertyField.Name);
|
||||
if (!tree)
|
||||
continue;
|
||||
|
||||
var property = propertyField.GetValue(_overrides);
|
||||
foreach (var valueField in propertyField.FieldType.GetFields())
|
||||
{
|
||||
var value = valueField.GetValue(property) as bool? ?? false;
|
||||
if (ImUtf8.Checkbox($"Disable {valueField.Name}", ref value) || all.HasValue)
|
||||
if (all.HasValue)
|
||||
{
|
||||
valueField.SetValue(property, all ?? value);
|
||||
propertyField.SetValue(_overrides, property);
|
||||
var property = propertyField.GetValue(_overrides);
|
||||
foreach (var valueField in propertyField.FieldType.GetFields())
|
||||
{
|
||||
valueField.SetValue(property, all.Value);
|
||||
propertyField.SetValue(_overrides, property);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
allVisible ??= all;
|
||||
var property = propertyField.GetValue(_overrides);
|
||||
foreach (var valueField in propertyField.FieldType.GetFields())
|
||||
{
|
||||
var value = valueField.GetValue(property) as bool? ?? false;
|
||||
if (ImUtf8.Checkbox($"Disable {valueField.Name}", ref value) || allVisible.HasValue)
|
||||
{
|
||||
valueField.SetValue(property, allVisible ?? value);
|
||||
propertyField.SetValue(_overrides, property);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue