🎉 Initial Version
This commit is contained in:
parent
38347015b2
commit
acec50fd3d
8
RetainerTrack/Database/Player.cs
Normal file
8
RetainerTrack/Database/Player.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
namespace RetainerTrack.Database
|
||||||
|
{
|
||||||
|
internal sealed class Player
|
||||||
|
{
|
||||||
|
public ulong Id { get; set; }
|
||||||
|
public string? Name { get; set; }
|
||||||
|
}
|
||||||
|
}
|
10
RetainerTrack/Database/Retainer.cs
Normal file
10
RetainerTrack/Database/Retainer.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
namespace RetainerTrack.Database
|
||||||
|
{
|
||||||
|
internal sealed class Retainer
|
||||||
|
{
|
||||||
|
public ulong Id { get; set; }
|
||||||
|
public string? Name { get; set; }
|
||||||
|
public ushort WorldId { get; set; }
|
||||||
|
public ulong OwnerContentId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
23
RetainerTrack/Handlers/ContentIdToName.cs
Normal file
23
RetainerTrack/Handlers/ContentIdToName.cs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace RetainerTrack.Handlers
|
||||||
|
{
|
||||||
|
internal sealed class ContentIdToName
|
||||||
|
{
|
||||||
|
public ulong ContentId { get; init; }
|
||||||
|
public string PlayerName { get; init; } = string.Empty;
|
||||||
|
|
||||||
|
public static unsafe ContentIdToName Read(nint dataPtr)
|
||||||
|
{
|
||||||
|
using UnmanagedMemoryStream input = new UnmanagedMemoryStream((byte*)dataPtr.ToPointer(), 40);
|
||||||
|
using BinaryReader binaryReader = new BinaryReader(input);
|
||||||
|
|
||||||
|
return new ContentIdToName
|
||||||
|
{
|
||||||
|
ContentId = binaryReader.ReadUInt64(),
|
||||||
|
PlayerName = Encoding.UTF8.GetString(binaryReader.ReadBytes(32)).TrimEnd(char.MinValue)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
101
RetainerTrack/Handlers/MarketBoardUIHandler.cs
Normal file
101
RetainerTrack/Handlers/MarketBoardUIHandler.cs
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
using System;
|
||||||
|
using Dalamud.Game;
|
||||||
|
using Dalamud.Game.Gui;
|
||||||
|
using Dalamud.Hooking;
|
||||||
|
using FFXIVClientStructs.FFXIV.Client.UI;
|
||||||
|
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
namespace RetainerTrack.Handlers
|
||||||
|
{
|
||||||
|
internal sealed unsafe class MarketBoardUiHandler : IDisposable
|
||||||
|
{
|
||||||
|
private readonly ILogger<MarketBoardUiHandler> _logger;
|
||||||
|
private readonly Framework _framework;
|
||||||
|
private readonly GameGui _gameGui;
|
||||||
|
private readonly PersistenceContext _persistenceContext;
|
||||||
|
|
||||||
|
private AddonItemSearchResult* _itemSearchResultAddon;
|
||||||
|
private Hook<Draw>? _drawHook;
|
||||||
|
|
||||||
|
private delegate void Draw(AtkUnitBase* addon);
|
||||||
|
|
||||||
|
public MarketBoardUiHandler(
|
||||||
|
ILogger<MarketBoardUiHandler> logger,
|
||||||
|
Framework framework,
|
||||||
|
GameGui gameGui,
|
||||||
|
PersistenceContext persistenceContext)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
_framework = framework;
|
||||||
|
_gameGui = gameGui;
|
||||||
|
_persistenceContext = persistenceContext;
|
||||||
|
;
|
||||||
|
|
||||||
|
_framework.Update += FrameworkUpdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FrameworkUpdate(Framework framework)
|
||||||
|
{
|
||||||
|
_itemSearchResultAddon = (AddonItemSearchResult*)_gameGui.GetAddonByName("ItemSearchResult");
|
||||||
|
if (_itemSearchResultAddon == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_drawHook ??= Hook<Draw>.FromAddress(
|
||||||
|
new nint(_itemSearchResultAddon->AtkUnitBase.AtkEventListener.vfunc[42]),
|
||||||
|
AddonDraw);
|
||||||
|
_drawHook.Enable();
|
||||||
|
_framework.Update -= FrameworkUpdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddonDraw(AtkUnitBase* addon)
|
||||||
|
{
|
||||||
|
UpdateRetainerNames();
|
||||||
|
_drawHook!.Original(addon);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateRetainerNames()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (_itemSearchResultAddon == null || !_itemSearchResultAddon->AtkUnitBase.IsVisible)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var results = _itemSearchResultAddon->Results;
|
||||||
|
if (results == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int length = results->ListLength;
|
||||||
|
if (length == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (int i = 0; i < length; ++i)
|
||||||
|
{
|
||||||
|
var listItem = results->ItemRendererList[i].AtkComponentListItemRenderer;
|
||||||
|
var uldManager = listItem->AtkComponentButton.AtkComponentBase.UldManager;
|
||||||
|
if (uldManager.NodeListCount < 14)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var retainerNameNode = (AtkTextNode*)uldManager.NodeList[5];
|
||||||
|
string retainerName = retainerNameNode->NodeText.ToString();
|
||||||
|
if (!retainerName.Contains('('))
|
||||||
|
{
|
||||||
|
string playerName = _persistenceContext.GetCharacterNameOnCurrentWorld(retainerName);
|
||||||
|
if (!string.IsNullOrEmpty(playerName))
|
||||||
|
retainerNameNode->SetText($"{playerName} ({retainerName})");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.LogInformation(e, "Market board draw failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_drawHook?.Dispose();
|
||||||
|
_framework.Update -= FrameworkUpdate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
78
RetainerTrack/Handlers/NetworkHandler.cs
Normal file
78
RetainerTrack/Handlers/NetworkHandler.cs
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
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;
|
||||||
|
|
||||||
|
private readonly ushort? _contentIdMappingOpCode;
|
||||||
|
|
||||||
|
public unsafe NetworkHandler(
|
||||||
|
ILogger<NetworkHandler> logger,
|
||||||
|
GameNetwork gameNetwork,
|
||||||
|
DataManager dataManager,
|
||||||
|
ClientState clientState,
|
||||||
|
PersistenceContext persistenceContext)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
_gameNetwork = gameNetwork;
|
||||||
|
_dataManager = dataManager;
|
||||||
|
_clientState = clientState;
|
||||||
|
_persistenceContext = persistenceContext;
|
||||||
|
|
||||||
|
if (Framework.Instance()->GameVersion.Base == "2023.02.03.0000.0000")
|
||||||
|
_contentIdMappingOpCode = 0x01C4;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Not tracking content id mappings, unsupported game version {Version}",
|
||||||
|
Framework.Instance()->GameVersion.Base);
|
||||||
|
}
|
||||||
|
|
||||||
|
_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));
|
||||||
|
}
|
||||||
|
else if (opcode == _contentIdMappingOpCode)
|
||||||
|
{
|
||||||
|
var mapping = ContentIdToName.Read(dataPtr);
|
||||||
|
_logger.LogTrace("Content id {ContentId} belongs to player '{Name}'", mapping.ContentId,
|
||||||
|
!string.IsNullOrEmpty(mapping.PlayerName) ? mapping.PlayerName : "<unknown>");
|
||||||
|
Task.Run(() => _persistenceContext.HandleContentIdMapping(mapping));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
66
RetainerTrack/Handlers/PartyHandler.cs
Normal file
66
RetainerTrack/Handlers/PartyHandler.cs
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Dalamud.Game;
|
||||||
|
using Dalamud.Game.ClientState;
|
||||||
|
using Dalamud.Memory;
|
||||||
|
using FFXIVClientStructs.FFXIV.Client.Game.Group;
|
||||||
|
|
||||||
|
namespace RetainerTrack.Handlers
|
||||||
|
{
|
||||||
|
internal sealed class PartyHandler : IDisposable
|
||||||
|
{
|
||||||
|
private readonly Framework _framework;
|
||||||
|
private readonly ClientState _clientState;
|
||||||
|
private readonly PersistenceContext _persistenceContext;
|
||||||
|
|
||||||
|
private long _lastUpdate = 0;
|
||||||
|
|
||||||
|
public PartyHandler(Framework framework, ClientState clientState, PersistenceContext persistenceContext)
|
||||||
|
{
|
||||||
|
_framework = framework;
|
||||||
|
_clientState = clientState;
|
||||||
|
_persistenceContext = persistenceContext;
|
||||||
|
|
||||||
|
_framework.Update += FrameworkUpdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
private unsafe void FrameworkUpdate(Framework _)
|
||||||
|
{
|
||||||
|
long now = Environment.TickCount64;
|
||||||
|
if (!_clientState.IsLoggedIn || _clientState.IsPvPExcludingDen || now - _lastUpdate < 180_000)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_lastUpdate = now;
|
||||||
|
List<ContentIdToName> mappings = new();
|
||||||
|
|
||||||
|
var groupManager = GroupManager.Instance();
|
||||||
|
foreach (var partyMember in groupManager->PartyMembersSpan)
|
||||||
|
HandlePartyMember(partyMember, mappings);
|
||||||
|
|
||||||
|
foreach (var allianceMember in groupManager->AllianceMembersSpan)
|
||||||
|
HandlePartyMember(allianceMember, mappings);
|
||||||
|
|
||||||
|
if (mappings.Count > 0)
|
||||||
|
Task.Run(() => _persistenceContext.HandleContentIdMapping(mappings));
|
||||||
|
}
|
||||||
|
|
||||||
|
private unsafe void HandlePartyMember(PartyMember partyMember, List<ContentIdToName> contentIdToNames)
|
||||||
|
{
|
||||||
|
if (partyMember.ContentID == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
string name = MemoryHelper.ReadStringNullTerminated((nint)partyMember.Name);
|
||||||
|
contentIdToNames.Add(new ContentIdToName
|
||||||
|
{
|
||||||
|
ContentId = (ulong)partyMember.ContentID,
|
||||||
|
PlayerName = name,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_framework.Update -= FrameworkUpdate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
121
RetainerTrack/Handlers/PersistenceContext.cs
Normal file
121
RetainerTrack/Handlers/PersistenceContext.cs
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Dalamud.Game.ClientState;
|
||||||
|
using Dalamud.Game.Network.Structures;
|
||||||
|
using LiteDB;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using RetainerTrack.Database;
|
||||||
|
|
||||||
|
namespace RetainerTrack.Handlers
|
||||||
|
{
|
||||||
|
internal sealed class PersistenceContext
|
||||||
|
{
|
||||||
|
private readonly ILogger<PersistenceContext> _logger;
|
||||||
|
private readonly ClientState _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,
|
||||||
|
LiteDatabase liteDatabase)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
_clientState = clientState;
|
||||||
|
_liteDatabase = liteDatabase;
|
||||||
|
|
||||||
|
var retainersByWorld = _liteDatabase.GetCollection<Retainer>().FindAll()
|
||||||
|
.GroupBy(r => r.WorldId);
|
||||||
|
foreach (var retainers in retainersByWorld)
|
||||||
|
{
|
||||||
|
var world = _worldRetainerCache.GetOrAdd(retainers.Key, _ => new());
|
||||||
|
foreach (var retainer in retainers)
|
||||||
|
{
|
||||||
|
if (retainer.Name != null)
|
||||||
|
world[retainer.Name] = retainer.OwnerContentId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var player in _liteDatabase.GetCollection<Player>().FindAll())
|
||||||
|
_playerNameCache[player.Id] = player.Name ?? string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetCharacterNameOnCurrentWorld(string retainerName)
|
||||||
|
{
|
||||||
|
uint currentWorld = _clientState.LocalPlayer?.CurrentWorld.Id ?? 0;
|
||||||
|
if (currentWorld == 0)
|
||||||
|
return string.Empty;
|
||||||
|
|
||||||
|
var currentWorldCache = _worldRetainerCache.GetOrAdd(currentWorld, _ => new());
|
||||||
|
if (!currentWorldCache.TryGetValue(retainerName, out ulong playerContentId))
|
||||||
|
return string.Empty;
|
||||||
|
|
||||||
|
return _playerNameCache.TryGetValue(playerContentId, out string? playerName) ? playerName : string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void HandleMarketBoardPage(MarketBoardCurrentOfferings listings, ushort worldId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var updates =
|
||||||
|
listings.ItemListings.DistinctBy(o => o.RetainerId)
|
||||||
|
.Where(l => l.RetainerId != 0)
|
||||||
|
.Where(l => l.RetainerOwnerId != 0)
|
||||||
|
.Select(l =>
|
||||||
|
new Retainer
|
||||||
|
{
|
||||||
|
Id = l.RetainerId,
|
||||||
|
Name = l.RetainerName,
|
||||||
|
WorldId = worldId,
|
||||||
|
OwnerContentId = l.RetainerOwnerId,
|
||||||
|
})
|
||||||
|
.ToList();
|
||||||
|
_liteDatabase.GetCollection<Retainer>().Upsert(updates);
|
||||||
|
foreach (var retainer in updates)
|
||||||
|
{
|
||||||
|
if (!_playerNameCache.TryGetValue(retainer.OwnerContentId, out string? ownerName))
|
||||||
|
ownerName = retainer.OwnerContentId.ToString();
|
||||||
|
_logger.LogTrace("Retainer {RetainerName} belongs to {OwnerId}", retainer.Name,
|
||||||
|
ownerName);
|
||||||
|
|
||||||
|
if (retainer.Name != null)
|
||||||
|
{
|
||||||
|
var world = _worldRetainerCache.GetOrAdd(retainer.WorldId, _ => new());
|
||||||
|
world[retainer.Name] = retainer.OwnerContentId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.LogError(e, "Could not persist retainer info from market board page");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void HandleContentIdMapping(ContentIdToName mapping)
|
||||||
|
=> HandleContentIdMapping(new List<ContentIdToName> { mapping });
|
||||||
|
|
||||||
|
public void HandleContentIdMapping(IReadOnlyList<ContentIdToName> mappings)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var updates = mappings
|
||||||
|
.Where(mapping => mapping.ContentId != 0 && !string.IsNullOrEmpty(mapping.PlayerName))
|
||||||
|
.Select(mapping =>
|
||||||
|
new Player
|
||||||
|
{
|
||||||
|
Id = mapping.ContentId,
|
||||||
|
Name = mapping.PlayerName,
|
||||||
|
})
|
||||||
|
.ToList();
|
||||||
|
_liteDatabase.GetCollection<Player>().Upsert(updates);
|
||||||
|
foreach (var player in updates)
|
||||||
|
_playerNameCache[player.Id] = player.Name ?? string.Empty;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.LogError(e, "Could not persist multiple mappings");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -19,7 +19,10 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Dalamud.Extensions.MicrosoftLogging" Version="1.0.0"/>
|
||||||
<PackageReference Include="DalamudPackager" Version="2.1.10"/>
|
<PackageReference Include="DalamudPackager" Version="2.1.10"/>
|
||||||
|
<PackageReference Include="LiteDB" Version="5.0.15"/>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -1,13 +1,75 @@
|
|||||||
using Dalamud.Plugin;
|
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 LiteDB;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using RetainerTrack.Database;
|
||||||
|
using RetainerTrack.Handlers;
|
||||||
|
|
||||||
namespace RetainerTrack
|
namespace RetainerTrack
|
||||||
{
|
{
|
||||||
public class RetainerTrackPlugin : IDalamudPlugin
|
// ReSharper disable once UnusedType.Global
|
||||||
|
internal sealed class RetainerTrackPlugin : IDalamudPlugin
|
||||||
{
|
{
|
||||||
|
private readonly ServiceProvider? _serviceProvider;
|
||||||
|
|
||||||
public string Name => "RetainerTrack";
|
public string Name => "RetainerTrack";
|
||||||
|
|
||||||
|
public RetainerTrackPlugin(
|
||||||
|
DalamudPluginInterface pluginInterface,
|
||||||
|
GameNetwork gameNetwork,
|
||||||
|
DataManager dataManager,
|
||||||
|
Framework framework,
|
||||||
|
ClientState clientState,
|
||||||
|
GameGui gameGui)
|
||||||
|
{
|
||||||
|
ServiceCollection serviceCollection = new();
|
||||||
|
serviceCollection.AddLogging(builder => builder.SetMinimumLevel(LogLevel.Trace)
|
||||||
|
.ClearProviders()
|
||||||
|
.AddDalamudLogger(this));
|
||||||
|
serviceCollection.AddSingleton<IDalamudPlugin>(this);
|
||||||
|
serviceCollection.AddSingleton(pluginInterface);
|
||||||
|
serviceCollection.AddSingleton(gameNetwork);
|
||||||
|
serviceCollection.AddSingleton(dataManager);
|
||||||
|
serviceCollection.AddSingleton(framework);
|
||||||
|
serviceCollection.AddSingleton(clientState);
|
||||||
|
serviceCollection.AddSingleton(gameGui);
|
||||||
|
|
||||||
|
serviceCollection.AddSingleton<LiteDatabase>(_ =>
|
||||||
|
new LiteDatabase(new ConnectionString
|
||||||
|
{
|
||||||
|
Filename = Path.Join(pluginInterface.GetPluginConfigDirectory(), "retainer-data.litedb"),
|
||||||
|
Connection = ConnectionType.Direct,
|
||||||
|
Upgrade = true,
|
||||||
|
}));
|
||||||
|
|
||||||
|
serviceCollection.AddSingleton<PersistenceContext>();
|
||||||
|
serviceCollection.AddSingleton<NetworkHandler>();
|
||||||
|
serviceCollection.AddSingleton<PartyHandler>();
|
||||||
|
serviceCollection.AddSingleton<MarketBoardUiHandler>();
|
||||||
|
|
||||||
|
_serviceProvider = serviceCollection.BuildServiceProvider();
|
||||||
|
|
||||||
|
LiteDatabase liteDatabase = _serviceProvider.GetRequiredService<LiteDatabase>();
|
||||||
|
liteDatabase.GetCollection<Retainer>()
|
||||||
|
.EnsureIndex(x => x.Id);
|
||||||
|
liteDatabase.GetCollection<Player>()
|
||||||
|
.EnsureIndex(x => x.Id);
|
||||||
|
|
||||||
|
_serviceProvider.GetRequiredService<PartyHandler>();
|
||||||
|
_serviceProvider.GetRequiredService<NetworkHandler>();
|
||||||
|
_serviceProvider.GetRequiredService<MarketBoardUiHandler>();
|
||||||
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
_serviceProvider?.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user