API 9
This commit is contained in:
parent
48697d7c1e
commit
5bc751e31b
@ -6,6 +6,7 @@ using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Dalamud.Hooking;
|
||||
using Dalamud.Memory;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Dalamud.Utility.Signatures;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
@ -35,13 +36,13 @@ namespace RetainerTrack.Handlers
|
||||
|
||||
#pragma warning restore CS0649
|
||||
|
||||
public GameHooks(ILogger<GameHooks> logger, PersistenceContext persistenceContext)
|
||||
public GameHooks(ILogger<GameHooks> logger, PersistenceContext persistenceContext, IGameInteropProvider gameInteropProvider)
|
||||
{
|
||||
_logger = logger;
|
||||
_persistenceContext = persistenceContext;
|
||||
|
||||
_logger.LogDebug("Initializing game hooks");
|
||||
SignatureHelper.Initialise(this);
|
||||
gameInteropProvider.InitializeFromAttributes(this);
|
||||
CharacterNameResultHook.Enable();
|
||||
SocialListResultHook.Enable();
|
||||
|
||||
|
79
RetainerTrack/Handlers/MarketBoardOfferingsHandler.cs
Normal file
79
RetainerTrack/Handlers/MarketBoardOfferingsHandler.cs
Normal file
@ -0,0 +1,79 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Dalamud.Game.Network.Structures;
|
||||
using Dalamud.Hooking;
|
||||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.UI;
|
||||
using FFXIVClientStructs.FFXIV.Client.UI.Info;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace RetainerTrack.Handlers
|
||||
{
|
||||
internal sealed class MarketBoardOfferingsHandler : IDisposable
|
||||
{
|
||||
private unsafe delegate void* MarketBoardOfferings(InfoProxyItemSearch* a1, nint packetData);
|
||||
|
||||
private readonly ILogger<MarketBoardOfferingsHandler> _logger;
|
||||
private readonly IClientState _clientState;
|
||||
private readonly PersistenceContext _persistenceContext;
|
||||
private readonly Hook<MarketBoardOfferings> _marketBoardOfferingsHook;
|
||||
|
||||
public unsafe MarketBoardOfferingsHandler(
|
||||
ILogger<MarketBoardOfferingsHandler> logger,
|
||||
IClientState clientState,
|
||||
IGameGui gameGui,
|
||||
IGameInteropProvider gameInteropProvider,
|
||||
PersistenceContext persistenceContext)
|
||||
{
|
||||
_logger = logger;
|
||||
_clientState = clientState;
|
||||
_persistenceContext = persistenceContext;
|
||||
|
||||
_logger.LogDebug("Setting up offerings hook");
|
||||
var uiModule = (UIModule*)gameGui.GetUIModule();
|
||||
var infoModule = uiModule->GetInfoModule();
|
||||
var proxy = infoModule->GetInfoProxyById(11);
|
||||
_marketBoardOfferingsHook =
|
||||
gameInteropProvider.HookFromAddress<MarketBoardOfferings>((nint)proxy->vtbl[12],
|
||||
MarketBoardOfferingsDetour);
|
||||
_marketBoardOfferingsHook.Enable();
|
||||
_logger.LogDebug("Offerings hook enabled successfully");
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_marketBoardOfferingsHook.Dispose();
|
||||
}
|
||||
|
||||
// adapted from https://github.com/tesu/PennyPincher/commit/0f9b3963fd4a6e9b87f585ee491d4de59a93f7a3
|
||||
private unsafe void* MarketBoardOfferingsDetour(InfoProxyItemSearch* a1, nint packetData)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (packetData != nint.Zero)
|
||||
{
|
||||
ParseOfferings(packetData);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, "Could not parse marketboard offerings.");
|
||||
}
|
||||
|
||||
return _marketBoardOfferingsHook.Original(a1, packetData);
|
||||
}
|
||||
|
||||
private void ParseOfferings(nint dataPtr)
|
||||
{
|
||||
ushort worldId = (ushort?)_clientState.LocalPlayer?.CurrentWorld.Id ?? 0;
|
||||
if (worldId == 0)
|
||||
{
|
||||
_logger.LogInformation("Skipping market board handler, current world unknown");
|
||||
return;
|
||||
}
|
||||
|
||||
var listings = MarketBoardCurrentOfferings.Read(dataPtr);
|
||||
Task.Run(() => _persistenceContext.HandleMarketBoardPage(listings, worldId));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,8 @@
|
||||
using System;
|
||||
using Dalamud.Game;
|
||||
using Dalamud.Game.Gui;
|
||||
using Dalamud.Game.Addon.Lifecycle;
|
||||
using Dalamud.Game.Addon.Lifecycle.AddonArgTypes;
|
||||
using Dalamud.Hooking;
|
||||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.UI;
|
||||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||
using Microsoft.Extensions.Logging;
|
||||
@ -10,55 +11,33 @@ namespace RetainerTrack.Handlers
|
||||
{
|
||||
internal sealed unsafe class MarketBoardUiHandler : IDisposable
|
||||
{
|
||||
private const string AddonName = "ItemSearchResult";
|
||||
|
||||
private readonly ILogger<MarketBoardUiHandler> _logger;
|
||||
private readonly Framework _framework;
|
||||
private readonly GameGui _gameGui;
|
||||
private readonly PersistenceContext _persistenceContext;
|
||||
|
||||
private Hook<Draw>? _drawHook;
|
||||
|
||||
private delegate void Draw(AtkUnitBase* addon);
|
||||
private readonly IAddonLifecycle _addonLifecycle;
|
||||
|
||||
public MarketBoardUiHandler(
|
||||
ILogger<MarketBoardUiHandler> logger,
|
||||
Framework framework,
|
||||
GameGui gameGui,
|
||||
PersistenceContext persistenceContext)
|
||||
PersistenceContext persistenceContext,
|
||||
IAddonLifecycle addonLifecycle)
|
||||
{
|
||||
_logger = logger;
|
||||
_framework = framework;
|
||||
_gameGui = gameGui;
|
||||
_persistenceContext = persistenceContext;
|
||||
_addonLifecycle = addonLifecycle;
|
||||
|
||||
_framework.Update += FrameworkUpdate;
|
||||
_addonLifecycle.RegisterListener(AddonEvent.PreDraw, AddonName, PreDraw);
|
||||
}
|
||||
|
||||
private AddonItemSearchResult* ItemSearchResult => (AddonItemSearchResult*)_gameGui.GetAddonByName("ItemSearchResult");
|
||||
|
||||
private void FrameworkUpdate(Framework framework)
|
||||
private void PreDraw(AddonEvent type, AddonArgs args)
|
||||
{
|
||||
var addon = ItemSearchResult;
|
||||
if (addon == null)
|
||||
return;
|
||||
|
||||
_drawHook ??= Hook<Draw>.FromAddress(
|
||||
new nint(addon->AtkUnitBase.AtkEventListener.vfunc[42]),
|
||||
AddonDraw);
|
||||
_drawHook.Enable();
|
||||
_framework.Update -= FrameworkUpdate;
|
||||
UpdateRetainerNames((AddonItemSearchResult*)args.Addon);
|
||||
}
|
||||
|
||||
private void AddonDraw(AtkUnitBase* addon)
|
||||
{
|
||||
UpdateRetainerNames();
|
||||
_drawHook!.Original(addon);
|
||||
}
|
||||
|
||||
private void UpdateRetainerNames()
|
||||
private void UpdateRetainerNames(AddonItemSearchResult* addon)
|
||||
{
|
||||
try
|
||||
{
|
||||
var addon = ItemSearchResult;
|
||||
if (addon == null || !addon->AtkUnitBase.IsVisible)
|
||||
return;
|
||||
|
||||
@ -95,8 +74,7 @@ namespace RetainerTrack.Handlers
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_drawHook?.Dispose();
|
||||
_framework.Update -= FrameworkUpdate;
|
||||
_addonLifecycle.UnregisterListener(AddonEvent.PreDraw, AddonName, PreDraw);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,61 +0,0 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Dalamud.Data;
|
||||
using Dalamud.Game.ClientState;
|
||||
using Dalamud.Game.Network;
|
||||
using Dalamud.Game.Network.Structures;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Framework = FFXIVClientStructs.FFXIV.Client.System.Framework.Framework;
|
||||
|
||||
namespace RetainerTrack.Handlers
|
||||
{
|
||||
internal sealed class NetworkHandler : IDisposable
|
||||
{
|
||||
private readonly ILogger<NetworkHandler> _logger;
|
||||
private readonly GameNetwork _gameNetwork;
|
||||
private readonly DataManager _dataManager;
|
||||
private readonly ClientState _clientState;
|
||||
private readonly PersistenceContext _persistenceContext;
|
||||
|
||||
public NetworkHandler(
|
||||
ILogger<NetworkHandler> logger,
|
||||
GameNetwork gameNetwork,
|
||||
DataManager dataManager,
|
||||
ClientState clientState,
|
||||
PersistenceContext persistenceContext)
|
||||
{
|
||||
_logger = logger;
|
||||
_gameNetwork = gameNetwork;
|
||||
_dataManager = dataManager;
|
||||
_clientState = clientState;
|
||||
_persistenceContext = persistenceContext;
|
||||
|
||||
_gameNetwork.NetworkMessage += NetworkMessage;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_gameNetwork.NetworkMessage -= NetworkMessage;
|
||||
}
|
||||
|
||||
private void NetworkMessage(nint dataPtr, ushort opcode, uint sourceActorId, uint targetActorId,
|
||||
NetworkMessageDirection direction)
|
||||
{
|
||||
if (direction != NetworkMessageDirection.ZoneDown || !_dataManager.IsDataReady)
|
||||
return;
|
||||
|
||||
if (opcode == _dataManager.ServerOpCodes["MarketBoardOfferings"])
|
||||
{
|
||||
ushort worldId = (ushort?)_clientState.LocalPlayer?.CurrentWorld.Id ?? 0;
|
||||
if (worldId == 0)
|
||||
{
|
||||
_logger.LogInformation("Skipping market board handler, current world unknown");
|
||||
return;
|
||||
}
|
||||
|
||||
var listings = MarketBoardCurrentOfferings.Read(dataPtr);
|
||||
Task.Run(() => _persistenceContext.HandleMarketBoardPage(listings, worldId));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,22 +1,21 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Dalamud.Game;
|
||||
using Dalamud.Game.ClientState;
|
||||
using Dalamud.Memory;
|
||||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Group;
|
||||
|
||||
namespace RetainerTrack.Handlers
|
||||
{
|
||||
internal sealed class PartyHandler : IDisposable
|
||||
{
|
||||
private readonly Framework _framework;
|
||||
private readonly ClientState _clientState;
|
||||
private readonly IFramework _framework;
|
||||
private readonly IClientState _clientState;
|
||||
private readonly PersistenceContext _persistenceContext;
|
||||
|
||||
private long _lastUpdate = 0;
|
||||
|
||||
public PartyHandler(Framework framework, ClientState clientState, PersistenceContext persistenceContext)
|
||||
public PartyHandler(IFramework framework, IClientState clientState, PersistenceContext persistenceContext)
|
||||
{
|
||||
_framework = framework;
|
||||
_clientState = clientState;
|
||||
@ -25,7 +24,7 @@ namespace RetainerTrack.Handlers
|
||||
_framework.Update += FrameworkUpdate;
|
||||
}
|
||||
|
||||
private unsafe void FrameworkUpdate(Framework _)
|
||||
private unsafe void FrameworkUpdate(IFramework _)
|
||||
{
|
||||
long now = Environment.TickCount64;
|
||||
if (!_clientState.IsLoggedIn || _clientState.IsPvPExcludingDen || now - _lastUpdate < 180_000)
|
||||
|
@ -2,8 +2,8 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Dalamud.Game.ClientState;
|
||||
using Dalamud.Game.Network.Structures;
|
||||
using Dalamud.Plugin.Services;
|
||||
using LiteDB;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using RetainerTrack.Database;
|
||||
@ -13,12 +13,12 @@ namespace RetainerTrack.Handlers
|
||||
internal sealed class PersistenceContext
|
||||
{
|
||||
private readonly ILogger<PersistenceContext> _logger;
|
||||
private readonly ClientState _clientState;
|
||||
private readonly IClientState _clientState;
|
||||
private readonly LiteDatabase _liteDatabase;
|
||||
private readonly ConcurrentDictionary<uint, ConcurrentDictionary<string, ulong>> _worldRetainerCache = new();
|
||||
private readonly ConcurrentDictionary<ulong, string> _playerNameCache = new();
|
||||
|
||||
public PersistenceContext(ILogger<PersistenceContext> logger, ClientState clientState,
|
||||
public PersistenceContext(ILogger<PersistenceContext> logger, IClientState clientState,
|
||||
LiteDatabase liteDatabase)
|
||||
{
|
||||
_logger = logger;
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0-windows</TargetFramework>
|
||||
<Version>1.0</Version>
|
||||
<Version>2.0</Version>
|
||||
<LangVersion>11.0</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
@ -25,9 +25,9 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Dalamud.Extensions.MicrosoftLogging" Version="1.0.0" />
|
||||
<PackageReference Include="DalamudPackager" Version="2.1.10" />
|
||||
<PackageReference Include="LiteDB" Version="5.0.15" />
|
||||
<PackageReference Include="Dalamud.Extensions.MicrosoftLogging" Version="2.0.0" />
|
||||
<PackageReference Include="DalamudPackager" Version="2.1.12" />
|
||||
<PackageReference Include="LiteDB" Version="5.0.17" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
|
@ -1,11 +1,7 @@
|
||||
using System.IO;
|
||||
using Dalamud.Data;
|
||||
using Dalamud.Extensions.MicrosoftLogging;
|
||||
using Dalamud.Game;
|
||||
using Dalamud.Game.ClientState;
|
||||
using Dalamud.Game.Gui;
|
||||
using Dalamud.Game.Network;
|
||||
using Dalamud.Plugin;
|
||||
using Dalamud.Plugin.Services;
|
||||
using LiteDB;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
@ -19,27 +15,26 @@ namespace RetainerTrack
|
||||
{
|
||||
private readonly ServiceProvider? _serviceProvider;
|
||||
|
||||
public string Name => "RetainerTrack";
|
||||
|
||||
public RetainerTrackPlugin(
|
||||
DalamudPluginInterface pluginInterface,
|
||||
GameNetwork gameNetwork,
|
||||
DataManager dataManager,
|
||||
Framework framework,
|
||||
ClientState clientState,
|
||||
GameGui gameGui)
|
||||
IFramework framework,
|
||||
IClientState clientState,
|
||||
IGameGui gameGui,
|
||||
IGameInteropProvider gameInteropProvider,
|
||||
IAddonLifecycle addonLifecycle,
|
||||
IPluginLog pluginLog)
|
||||
{
|
||||
ServiceCollection serviceCollection = new();
|
||||
serviceCollection.AddLogging(builder => builder.SetMinimumLevel(LogLevel.Trace)
|
||||
.ClearProviders()
|
||||
.AddDalamudLogger(this));
|
||||
.AddDalamudLogger(pluginLog));
|
||||
serviceCollection.AddSingleton<IDalamudPlugin>(this);
|
||||
serviceCollection.AddSingleton(pluginInterface);
|
||||
serviceCollection.AddSingleton(gameNetwork);
|
||||
serviceCollection.AddSingleton(dataManager);
|
||||
serviceCollection.AddSingleton(framework);
|
||||
serviceCollection.AddSingleton(clientState);
|
||||
serviceCollection.AddSingleton(gameGui);
|
||||
serviceCollection.AddSingleton(gameInteropProvider);
|
||||
serviceCollection.AddSingleton(addonLifecycle);
|
||||
|
||||
serviceCollection.AddSingleton<LiteDatabase>(_ =>
|
||||
new LiteDatabase(new ConnectionString
|
||||
@ -50,7 +45,7 @@ namespace RetainerTrack
|
||||
}));
|
||||
|
||||
serviceCollection.AddSingleton<PersistenceContext>();
|
||||
serviceCollection.AddSingleton<NetworkHandler>();
|
||||
serviceCollection.AddSingleton<MarketBoardOfferingsHandler>();
|
||||
serviceCollection.AddSingleton<PartyHandler>();
|
||||
serviceCollection.AddSingleton<MarketBoardUiHandler>();
|
||||
serviceCollection.AddSingleton<GameHooks>();
|
||||
@ -64,7 +59,7 @@ namespace RetainerTrack
|
||||
.EnsureIndex(x => x.Id);
|
||||
|
||||
_serviceProvider.GetRequiredService<PartyHandler>();
|
||||
_serviceProvider.GetRequiredService<NetworkHandler>();
|
||||
_serviceProvider.GetRequiredService<MarketBoardOfferingsHandler>();
|
||||
_serviceProvider.GetRequiredService<MarketBoardUiHandler>();
|
||||
_serviceProvider.GetRequiredService<GameHooks>();
|
||||
}
|
||||
|
@ -4,24 +4,24 @@
|
||||
"net7.0-windows7.0": {
|
||||
"Dalamud.Extensions.MicrosoftLogging": {
|
||||
"type": "Direct",
|
||||
"requested": "[1.0.0, )",
|
||||
"resolved": "1.0.0",
|
||||
"contentHash": "nPjMrT9n9GJ+TYF1lyVhlvhmFyN4ajMX2ccclgyMc8MNpOGZwxrJ4VEtrUUk7UkuX2wAhtnNsjrcf5sER3/CbA==",
|
||||
"requested": "[2.0.0, )",
|
||||
"resolved": "2.0.0",
|
||||
"contentHash": "qp2idn5GuPouUxHHFytMrorbhlcupsgPdO87HjxlBfTY+JID+qoTfPmA5V6HBP1a4DuXGPbk4JtoO/hMmnQrtw==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Logging": "7.0.0"
|
||||
}
|
||||
},
|
||||
"DalamudPackager": {
|
||||
"type": "Direct",
|
||||
"requested": "[2.1.10, )",
|
||||
"resolved": "2.1.10",
|
||||
"contentHash": "S6NrvvOnLgT4GDdgwuKVJjbFo+8ZEj+JsEYk9ojjOR/MMfv1dIFpT8aRJQfI24rtDcw1uF+GnSSMN4WW1yt7fw=="
|
||||
"requested": "[2.1.12, )",
|
||||
"resolved": "2.1.12",
|
||||
"contentHash": "Sc0PVxvgg4NQjcI8n10/VfUQBAS4O+Fw2pZrAqBdRMbthYGeogzu5+xmIGCGmsEZ/ukMOBuAqiNiB5qA3MRalg=="
|
||||
},
|
||||
"LiteDB": {
|
||||
"type": "Direct",
|
||||
"requested": "[5.0.15, )",
|
||||
"resolved": "5.0.15",
|
||||
"contentHash": "nucyfCOGSATH553BxplxExP3BOqEwmHt0B57426EIaQjD3CC1Odb52VVCGgTxyYaD2oe3B/cJk8jDo6XiBJqPg=="
|
||||
"requested": "[5.0.17, )",
|
||||
"resolved": "5.0.17",
|
||||
"contentHash": "cKPvkdlzIts3ZKu/BzoIc/Y71e4VFKlij4LyioPFATZMot+wB7EAm1FFbZSJez6coJmQUoIg/3yHE1MMU+zOdg=="
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection": {
|
||||
"type": "Direct",
|
||||
|
Loading…
Reference in New Issue
Block a user