This commit is contained in:
Liza 2023-10-05 17:32:42 +02:00
parent 48697d7c1e
commit b9f16fa619
Signed by: liza
GPG Key ID: 7199F8D727D55F67
9 changed files with 129 additions and 138 deletions

View File

@ -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();

View 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));
}
}
}

View File

@ -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);
}
}
}

View File

@ -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));
}
}
}
}

View File

@ -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)

View File

@ -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;

View File

@ -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>

View File

@ -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>();
}

View File

@ -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",