diff --git a/AutoSweep.csproj b/AutoSweep.csproj
index 15a991b..61c128b 100644
--- a/AutoSweep.csproj
+++ b/AutoSweep.csproj
@@ -3,7 +3,7 @@
autoSweep
zhudotexe
- net7.0-windows
+ net8.0-windows
9
true
true
@@ -14,7 +14,7 @@
true
true
autoSweep
- 1.4.3.0
+ 1.4.4.0
@@ -68,7 +68,7 @@
-
+
diff --git a/Configuration.cs b/Configuration.cs
index 1188e83..3619d6e 100644
--- a/Configuration.cs
+++ b/Configuration.cs
@@ -1,15 +1,11 @@
using System;
using Dalamud.Configuration;
using Dalamud.Game.Text;
-using Dalamud.Plugin;
namespace AutoSweep {
[Serializable]
public class Configuration : IPluginConfiguration {
// the below exist just to make saving less cumbersome
- [NonSerialized]
- private DalamudPluginInterface pluginInterface;
-
public bool Enabled { get; set; } = true;
public string OutputFormatString { get; set; } = "";
public OutputFormat OutputFormat { get; set; } = OutputFormat.Simple;
@@ -28,12 +24,8 @@ public class Configuration : IPluginConfiguration {
public bool ChatSweepAlert { get; set; } = true; // thank the user for contributions in chat/"began sweep"
public int Version { get; set; } = 4;
- public void Initialize(DalamudPluginInterface pluginInterface) {
- this.pluginInterface = pluginInterface;
- }
-
public void Save() {
- pluginInterface.SavePluginConfig(this);
+ Plugin.PluginInterface.SavePluginConfig(this);
}
}
@@ -64,4 +56,4 @@ public enum OutputFormat {
Custom = 4
}
-}
+}
\ No newline at end of file
diff --git a/Paissa/Client.cs b/Paissa/Client.cs
index debe885..b5c7b81 100644
--- a/Paissa/Client.cs
+++ b/Paissa/Client.cs
@@ -20,9 +20,7 @@ public class PaissaClient : IDisposable {
private string sessionToken;
// dalamud
- private readonly IClientState clientState;
- private readonly IChatGui chat;
- private readonly IPluginLog log;
+ private Plugin plugin;
// ingest debounce
private readonly DebounceDispatcher ingestDebounceDispatcher = new DebounceDispatcher(1200);
@@ -41,10 +39,8 @@ public class PaissaClient : IDisposable {
public event EventHandler OnPlotUpdate;
public event EventHandler OnPlotSold;
- public PaissaClient(IClientState clientState, IChatGui chatGui, IPluginLog log) {
- this.clientState = clientState;
- chat = chatGui;
- this.log = log;
+ public PaissaClient(Plugin plugin) {
+ this.plugin = plugin;
http = new HttpClient();
ReconnectWS();
}
@@ -60,23 +56,23 @@ public void Dispose() {
/// Make a POST request to register the current character's content ID.
///
public async Task Hello() {
- PlayerCharacter player = clientState.LocalPlayer;
+ IPlayerCharacter player = Plugin.ClientState.LocalPlayer;
if (player == null) return;
var homeworld = player.HomeWorld.GameData;
if (homeworld == null) return;
var charInfo = new Dictionary {
- { "cid", clientState.LocalContentId },
+ { "cid", Plugin.ClientState.LocalContentId },
{ "name", player.Name.ToString() },
{ "world", homeworld.Name.ToString() },
{ "worldId", player.HomeWorld.Id }
};
string content = JsonConvert.SerializeObject(charInfo);
- log.Debug(content);
+ Plugin.PluginLog.Debug(content);
var response = await Post("/hello", content, false);
if (response.IsSuccessStatusCode) {
string respText = await response.Content.ReadAsStringAsync();
sessionToken = JsonConvert.DeserializeObject(respText).session_token;
- log.Info("Completed PaissaDB HELLO");
+ Plugin.PluginLog.Info("Completed PaissaDB HELLO");
}
}
@@ -99,7 +95,8 @@ public void PostWardInfo(HousingWardInfo wardInfo, int serverTimestamp) {
///
/// Fire and forget a POST request for a placard's lottery info.
///
- public void PostLotteryInfo(uint worldId, ushort districtId, ushort wardId, ushort plotId, PlacardSaleInfo saleInfo) {
+ public void PostLotteryInfo(uint worldId, ushort districtId, ushort wardId, ushort plotId,
+ PlacardSaleInfo saleInfo) {
var data = new Dictionary {
{ "event_type", "LOTTERY_INFO" },
{ "client_timestamp", new DateTimeOffset(DateTime.UtcNow).ToUnixTimeSeconds() },
@@ -124,7 +121,8 @@ public void PostLotteryInfo(uint worldId, ushort districtId, ushort wardId, usho
/// The DistrictDetail
public async Task GetDistrictDetailAsync(short worldId, short districtId) {
HttpResponseMessage response = await http.GetAsync($"{apiBase}/worlds/{worldId}/{districtId}");
- log.Debug($"GET {apiBase}/worlds/{worldId}/{districtId} returned {response.StatusCode} ({response.ReasonPhrase})");
+ Plugin.PluginLog.Debug(
+ $"GET {apiBase}/worlds/{worldId}/{districtId} returned {response.StatusCode} ({response.ReasonPhrase})");
response.EnsureSuccessStatusCode();
string respText = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject(respText);
@@ -136,7 +134,7 @@ private void queueIngest(object data) {
ingestDebounceDispatcher.Debounce(() => {
string bulkIngestData = JsonConvert.SerializeObject(ingestDataQueue);
PostFireAndForget("/ingest", bulkIngestData);
- log.Debug($"Bulk ingesting {ingestDataQueue.Count} entries ({bulkIngestData.Length}B)");
+ Plugin.PluginLog.Debug($"Bulk ingesting {ingestDataQueue.Count} entries ({bulkIngestData.Length}B)");
ingestDataQueue.Clear();
});
}
@@ -145,55 +143,66 @@ private async void PostFireAndForget(string route, string content, bool auth = t
await Post(route, content, auth, retries);
}
- private async Task Post(string route, string content, bool auth = true, ushort retries = 5) {
+ private async Task
+ Post(string route, string content, bool auth = true, ushort retries = 5) {
HttpResponseMessage response = null;
- log.Verbose(content);
+ Plugin.PluginLog.Verbose(content);
for (var i = 0; i < retries; i++) {
HttpRequestMessage request;
if (auth) {
if (sessionToken == null) {
- log.Warning("Trying to send authed request but no session token!");
+ Plugin.PluginLog.Warning("Trying to send authed request but no session token!");
await Hello();
continue;
}
+
request = new HttpRequestMessage(HttpMethod.Post, $"{apiBase}{route}") {
Content = new StringContent(content, Encoding.UTF8, "application/json"),
Headers = {
Authorization = new AuthenticationHeaderValue("Bearer", sessionToken)
}
};
- } else {
+ }
+ else {
request = new HttpRequestMessage(HttpMethod.Post, $"{apiBase}{route}") {
Content = new StringContent(content, Encoding.UTF8, "application/json"),
};
}
+
try {
response = await http.SendAsync(request);
- log.Debug($"{request.Method} {request.RequestUri} returned {response.StatusCode} ({response.ReasonPhrase})");
+ Plugin.PluginLog.Debug(
+ $"{request.Method} {request.RequestUri} returned {response.StatusCode} ({response.ReasonPhrase})");
if (!response.IsSuccessStatusCode) {
string respText = await response.Content.ReadAsStringAsync();
- log.Warning($"{request.Method} {request.RequestUri} returned {response.StatusCode} ({response.ReasonPhrase}):\n{respText}");
- } else {
+ Plugin.PluginLog.Warning(
+ $"{request.Method} {request.RequestUri} returned {response.StatusCode} ({response.ReasonPhrase}):\n{respText}");
+ }
+ else {
break;
}
- } catch (Exception e) {
- log.Warning(e, $"{request.Method} {request.RequestUri} raised an error:");
}
+ catch (Exception e) {
+ Plugin.PluginLog.Warning(e, $"{request.Method} {request.RequestUri} raised an error:");
+ }
+
// if our request failed, exponential backoff for 2 * (i + 1) seconds
if (i + 1 < retries) {
int toDelay = 2000 * (i + 1) + new Random().Next(500, 1_500);
- log.Warning($"Request {i} failed, waiting for {toDelay}ms before retry...");
+ Plugin.PluginLog.Warning($"Request {i} failed, waiting for {toDelay}ms before retry...");
await Task.Delay(toDelay);
}
}
// todo better error handling
if (response == null) {
- chat.PrintError("There was an error connecting to PaissaDB.");
- } else if (!response.IsSuccessStatusCode) {
- chat.PrintError($"There was an error connecting to PaissaDB: {response.ReasonPhrase}");
+ Plugin.Chat.PrintError("There was an error connecting to PaissaDB.");
+ }
+ else if (!response.IsSuccessStatusCode) {
+ Plugin.Chat.PrintError($"There was an error connecting to PaissaDB: {response.ReasonPhrase}");
}
+
return response;
}
@@ -209,23 +218,25 @@ private void ReconnectWS() {
ws.OnError += OnWSError;
try {
ws.Connect();
- } catch (PlatformNotSupportedException) {
+ }
+ catch (PlatformNotSupportedException) {
// idk why this happens but it doesn't seem to affect the ws
// silence for now to avoid polluting logs
// todo what is happening here?
// https://github.com/zhudotexe/FFXIV_PaissaHouse/issues/14
}
- log.Debug("ReconnectWS complete");
+
+ Plugin.PluginLog.Debug("ReconnectWS complete");
});
}
private void OnWSOpen(object sender, EventArgs e) {
- log.Information("WebSocket connected");
+ Plugin.PluginLog.Information("WebSocket connected");
}
private void OnWSMessage(object sender, MessageEventArgs e) {
if (!e.IsText) return;
- log.Verbose($">>>> R: {e.Data}");
+ Plugin.PluginLog.Verbose($">>>> R: {e.Data}");
var message = JsonConvert.DeserializeObject(e.Data);
switch (message.Type) {
case "plot_open":
@@ -240,20 +251,20 @@ private void OnWSMessage(object sender, MessageEventArgs e) {
case "ping":
break;
default:
- log.Warning($"Got unknown WS message: {e.Data}");
+ Plugin.PluginLog.Warning($"Got unknown WS message: {e.Data}");
break;
}
}
private void OnWSClose(object sender, CloseEventArgs e) {
- log.Information($"WebSocket closed ({e.Code}: {e.Reason})");
+ Plugin.PluginLog.Information($"WebSocket closed ({e.Code}: {e.Reason})");
// reconnect if unexpected close or server restarting
if ((!e.WasClean || e.Code == 1012) && !disposed)
WSReconnectSoon();
}
private void OnWSError(object sender, ErrorEventArgs e) {
- log.Warning(e.Exception, $"WebSocket error: {e.Message}");
+ Plugin.PluginLog.Warning(e.Exception, $"WebSocket error: {e.Message}");
if (!disposed)
WSReconnectSoon();
}
@@ -261,10 +272,11 @@ private void OnWSError(object sender, ErrorEventArgs e) {
private void WSReconnectSoon() {
if (ws.IsAlive) return;
int t = new Random().Next(5_000, 15_000);
- log.Warning($"WebSocket closed unexpectedly: will reconnect to socket in {t / 1000f:F3} seconds");
+ Plugin.PluginLog.Warning(
+ $"WebSocket closed unexpectedly: will reconnect to socket in {t / 1000f:F3} seconds");
Task.Run(async () => await Task.Delay(t)).ContinueWith(_ => {
if (!disposed) ReconnectWS();
});
}
}
-}
+}
\ No newline at end of file
diff --git a/Paissa/LotteryObserver.cs b/Paissa/LotteryObserver.cs
index ae8d467..1aa0649 100644
--- a/Paissa/LotteryObserver.cs
+++ b/Paissa/LotteryObserver.cs
@@ -20,12 +20,13 @@ private delegate void HandlePlacardSaleInfoDelegate(
long a8
);
- [Signature("E8 ?? ?? ?? ?? 48 8B B4 24 ?? ?? ?? ?? 48 8B 6C 24 ?? E9", DetourName = nameof(OnPlacardSaleInfo))]
+ // easy way to find sig: search for scalar 7043
+ [Signature("E8 ?? ?? ?? ?? 48 8B 74 24 ?? 48 8B 6C 24 ?? E9", DetourName = nameof(OnPlacardSaleInfo))]
private Hook? placardSaleInfoHook;
public LotteryObserver(Plugin plugin) {
this.plugin = plugin;
- plugin.InteropProvider.InitializeFromAttributes(this);
+ Plugin.InteropProvider.InitializeFromAttributes(this);
placardSaleInfoHook?.Enable();
}
@@ -51,20 +52,20 @@ long a8
PlacardSaleInfo saleInfo = PlacardSaleInfo.Read(placardSaleInfoPtr);
- plugin.PluginLog.Debug(
+ Plugin.PluginLog.Debug(
$"Got PlacardSaleInfo: PurchaseType={saleInfo.PurchaseType}, TenantType={saleInfo.TenantType}, available={saleInfo.AvailabilityType}, until={saleInfo.PhaseEndsAt}, numEntries={saleInfo.EntryCount}");
- plugin.PluginLog.Debug(
+ Plugin.PluginLog.Debug(
$"unknown1={saleInfo.Unknown1}, unknown2={saleInfo.Unknown2}, unknown3={saleInfo.Unknown3}, unknown4={BitConverter.ToString(saleInfo.Unknown4)}");
- plugin.PluginLog.Debug(
+ Plugin.PluginLog.Debug(
$"housingType={housingType}, territoryTypeId={territoryTypeId}, wardId={wardId}, plotId={plotId}, apartmentNumber={apartmentNumber}, placardSaleInfoPtr={placardSaleInfoPtr}, a8={a8}");
// get information about the world from the clientstate
- World world = plugin.ClientState.LocalPlayer?.CurrentWorld.GameData;
+ World world = Plugin.ClientState.LocalPlayer?.CurrentWorld.GameData;
if (world is null) return;
SeString place = plugin.Territories.GetRow(territoryTypeId)?.PlaceName.Value?.Name;
SeString worldName = world.Name;
- plugin.PluginLog.Info($"Plot {place} {wardId + 1}-{plotId + 1} ({worldName}) has {saleInfo.EntryCount} lottery entries.");
+ Plugin.PluginLog.Info($"Plot {place} {wardId + 1}-{plotId + 1} ({worldName}) has {saleInfo.EntryCount} lottery entries.");
plugin.PaissaClient.PostLotteryInfo(world.RowId, territoryTypeId, wardId, plotId, saleInfo);
}
diff --git a/Paissa/Utils.cs b/Paissa/Utils.cs
index 69c3249..dc40807 100644
--- a/Paissa/Utils.cs
+++ b/Paissa/Utils.cs
@@ -38,13 +38,15 @@ string houseSizeName
.Replace("{houseSizeName}", houseSizeName);
}
- public static bool ConfigEnabledForPlot(Plugin plugin, ushort worldId, ushort districtId, ushort size, PurchaseSystem purchaseSystem) {
+ public static bool ConfigEnabledForPlot(Plugin plugin, ushort worldId, ushort districtId, ushort size,
+ PurchaseSystem purchaseSystem) {
if (!plugin.Configuration.Enabled) return false;
// does the config want notifs for this world?
World eventWorld = plugin.Worlds.GetRow(worldId);
if (!(plugin.Configuration.AllNotifs
- || plugin.Configuration.HomeworldNotifs && worldId == plugin.ClientState.LocalPlayer?.HomeWorld.Id
- || plugin.Configuration.DatacenterNotifs && eventWorld?.DataCenter.Row == plugin.ClientState.LocalPlayer?.HomeWorld.GameData?.DataCenter.Row))
+ || plugin.Configuration.HomeworldNotifs && worldId == Plugin.ClientState.LocalPlayer?.HomeWorld.Id
+ || plugin.Configuration.DatacenterNotifs && eventWorld?.DataCenter.Row ==
+ Plugin.ClientState.LocalPlayer?.HomeWorld.GameData?.DataCenter.Row))
return false;
// get the district config
DistrictNotifConfig districtNotifs;
@@ -67,6 +69,7 @@ public static bool ConfigEnabledForPlot(Plugin plugin, ushort worldId, ushort di
default:
return false;
}
+
// what about house sizes in this district?
bool notifEnabled;
switch (size) {
@@ -82,10 +85,12 @@ public static bool ConfigEnabledForPlot(Plugin plugin, ushort worldId, ushort di
default:
return false;
}
+
// and FC/individual purchase?
- PurchaseSystem purchaseSystemMask = (districtNotifs.FreeCompany ? PurchaseSystem.FreeCompany : 0) | (districtNotifs.Individual ? PurchaseSystem.Individual : 0);
+ PurchaseSystem purchaseSystemMask = (districtNotifs.FreeCompany ? PurchaseSystem.FreeCompany : 0) |
+ (districtNotifs.Individual ? PurchaseSystem.Individual : 0);
notifEnabled = notifEnabled && (purchaseSystem & purchaseSystemMask) != 0;
return notifEnabled;
}
}
-}
+}
\ No newline at end of file
diff --git a/Paissa/WardObserver.cs b/Paissa/WardObserver.cs
index e60c04e..9945f7e 100644
--- a/Paissa/WardObserver.cs
+++ b/Paissa/WardObserver.cs
@@ -15,12 +15,12 @@ private delegate void HandleHousingWardInfoDelegate(
IntPtr housingWardInfoPtr
);
- [Signature("40 55 57 41 54 41 56 41 57 48 8D AC 24 ?? ?? ?? ?? B8", DetourName = nameof(OnHousingWardInfo))]
+ [Signature("40 55 53 41 54 41 55 41 57 48 8D AC 24 ?? ?? ?? ?? B8", DetourName = nameof(OnHousingWardInfo))]
private Hook? housingWardInfoHook;
public WardObserver(Plugin plugin) {
this.plugin = plugin;
- plugin.InteropProvider.InitializeFromAttributes(this);
+ Plugin.InteropProvider.InitializeFromAttributes(this);
SweepState = new SweepState(Utils.NumWardsPerDistrict);
housingWardInfoHook?.Enable();
}
@@ -38,7 +38,7 @@ IntPtr dataPtr
if (!plugin.Configuration.Enabled) return;
HousingWardInfo wardInfo = HousingWardInfo.Read(dataPtr);
int serverTimestamp = Marshal.ReadInt32(dataPtr - 0x8);
- plugin.PluginLog.Debug($"Got HousingWardInfo for ward: {wardInfo.LandIdent.WardNumber} territory: {wardInfo.LandIdent.TerritoryTypeId}");
+ Plugin.PluginLog.Debug($"Got HousingWardInfo for ward: {wardInfo.LandIdent.WardNumber} territory: {wardInfo.LandIdent.TerritoryTypeId}");
// if the current wardinfo is for a different district than the last swept one, print the header
// or if the last sweep was > 10m ago
@@ -49,13 +49,13 @@ IntPtr dataPtr
SeString districtName = plugin.Territories.GetRow((uint)wardInfo.LandIdent.TerritoryTypeId)?.PlaceName.Value?.Name;
SeString worldName = plugin.Worlds.GetRow((uint)wardInfo.LandIdent.WorldId)?.Name;
if (plugin.Configuration.ChatSweepAlert) {
- plugin.Chat.Print($"Began sweep for {districtName} ({worldName})");
+ Plugin.Chat.Print($"Began sweep for {districtName} ({worldName})");
}
}
// if we've seen this ward already, ignore it
if (SweepState.Contains(wardInfo)) {
- plugin.PluginLog.Debug($"Skipped processing HousingWardInfo for ward: {wardInfo.LandIdent.WardNumber} because we have seen it already");
+ Plugin.PluginLog.Debug($"Skipped processing HousingWardInfo for ward: {wardInfo.LandIdent.WardNumber} because we have seen it already");
return;
}
@@ -68,7 +68,7 @@ IntPtr dataPtr
// if that's all the wards, display the district summary and thanks
if (SweepState.IsComplete) OnFinishedDistrictSweep(wardInfo);
- plugin.PluginLog.Debug($"Done processing HousingWardInfo for ward: {wardInfo.LandIdent.WardNumber}");
+ Plugin.PluginLog.Debug($"Done processing HousingWardInfo for ward: {wardInfo.LandIdent.WardNumber}");
}
///
@@ -79,9 +79,9 @@ private void OnFinishedDistrictSweep(HousingWardInfo housingWardInfo) {
SeString districtName = plugin.Territories.GetRow((uint)SweepState.DistrictId)?.PlaceName.Value?.Name;
- plugin.Chat.Print($"Swept all {Utils.NumWardsPerDistrict} wards. Thank you for your contribution!");
- plugin.Chat.Print($"Here's a summary of open plots in {districtName}:");
- plugin.Chat.Print($"{districtName}: {SweepState.OpenHouses.Count} open plots.");
+ Plugin.Chat.Print($"Swept all {Utils.NumWardsPerDistrict} wards. Thank you for your contribution!");
+ Plugin.Chat.Print($"Here's a summary of open plots in {districtName}:");
+ Plugin.Chat.Print($"{districtName}: {SweepState.OpenHouses.Count} open plots.");
foreach (OpenHouse openHouse in SweepState.OpenHouses)
plugin.OnFoundOpenHouse((uint)SweepState.WorldId, (uint)SweepState.DistrictId, openHouse.WardNum, openHouse.PlotNum, openHouse.HouseInfoEntry.HousePrice);
}
diff --git a/Plugin.cs b/Plugin.cs
index 022d193..5ffaed2 100644
--- a/Plugin.cs
+++ b/Plugin.cs
@@ -6,24 +6,26 @@
using Dalamud.Game.Text;
using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Game.Text.SeStringHandling.Payloads;
+using Dalamud.IoC;
using Dalamud.Plugin;
using Dalamud.Plugin.Services;
using Lumina.Excel;
using Lumina.Excel.GeneratedSheets;
namespace AutoSweep {
- public class Plugin : IDalamudPlugin {
+ public sealed class Plugin : IDalamudPlugin {
public string Name => "PaissaHouse";
// frameworks/data
- internal readonly DalamudPluginInterface PluginInterface;
+ [PluginService] internal static IDalamudPluginInterface PluginInterface { get; private set; } = null!;
+ [PluginService] internal static IChatGui Chat { get; private set; } = null!;
+ [PluginService] internal static IClientState ClientState { get; private set; } = null!;
+ [PluginService] internal static ICommandManager Commands { get; private set; } = null!;
+ [PluginService] internal static IFramework Framework { get; private set; } = null!;
+ [PluginService] internal static IPluginLog PluginLog { get; private set; } = null!;
+ [PluginService] internal static IGameInteropProvider InteropProvider { get; private set; } = null!;
+ [PluginService] internal static IDataManager DataManager { get; private set; } = null!;
internal readonly Configuration Configuration;
- internal readonly IChatGui Chat;
- internal readonly IClientState ClientState;
- internal readonly ICommandManager Commands;
- internal readonly IFramework Framework;
- internal readonly IPluginLog PluginLog;
- internal readonly IGameInteropProvider InteropProvider;
internal readonly PaissaClient PaissaClient;
internal readonly ExcelSheet HousingLandSets;
@@ -37,51 +39,34 @@ public class Plugin : IDalamudPlugin {
private readonly PluginUI ui;
private bool clientNeedsHello = true;
- public Plugin(
- DalamudPluginInterface pi,
- IChatGui chat,
- IDataManager data,
- ICommandManager commands,
- IClientState clientState,
- IFramework framework,
- IPluginLog log,
- IGameInteropProvider interopProvider
- ) {
- PluginInterface = pi;
- Chat = chat;
- Commands = commands;
- ClientState = clientState;
- Framework = framework;
- PluginLog = log;
- InteropProvider = interopProvider;
-
+ public Plugin() {
// setup
- Configuration = pi.GetPluginConfig() as Configuration ?? new Configuration();
- Configuration.Initialize(pi);
+ Configuration = PluginInterface.GetPluginConfig() as Configuration ?? new Configuration();
ui = new PluginUI(Configuration);
- Territories = data.GetExcelSheet();
- Worlds = data.GetExcelSheet();
- HousingLandSets = data.GetExcelSheet();
+ Territories = DataManager.GetExcelSheet();
+ Worlds = DataManager.GetExcelSheet();
+ HousingLandSets = DataManager.GetExcelSheet();
- commands.AddHandler(Utils.HouseCommandName, new CommandInfo(OnHouseCommand) {
+ Commands.AddHandler(Utils.HouseCommandName, new CommandInfo(OnHouseCommand) {
HelpMessage = "View all houses available for sale."
});
- commands.AddHandler(Utils.CommandName, new CommandInfo(OnCommand) {
- HelpMessage = $"Configure PaissaHouse settings.\n\"{Utils.CommandName} reset\" to reset a sweep if sweeping the same district multiple times in a row."
+ Commands.AddHandler(Utils.CommandName, new CommandInfo(OnCommand) {
+ HelpMessage =
+ $"Configure PaissaHouse settings.\n\"{Utils.CommandName} reset\" to reset a sweep if sweeping the same district multiple times in a row."
});
- chatLinkPayload = pi.AddChatLinkHandler(0, OnChatLinkClick);
+ chatLinkPayload = PluginInterface.AddChatLinkHandler(0, OnChatLinkClick);
// event hooks
- pi.UiBuilder.Draw += DrawUI;
- pi.UiBuilder.OpenConfigUi += DrawConfigUI;
- framework.Update += OnUpdateEvent;
- clientState.Login += OnLogin;
+ PluginInterface.UiBuilder.Draw += DrawUI;
+ PluginInterface.UiBuilder.OpenConfigUi += DrawConfigUI;
+ Framework.Update += OnUpdateEvent;
+ ClientState.Login += OnLogin;
// paissa setup
wardObserver = new WardObserver(this);
lotteryObserver = new LotteryObserver(this);
- PaissaClient = new PaissaClient(clientState, chat, log);
+ PaissaClient = new PaissaClient(this);
PaissaClient.OnPlotOpened += OnPlotOpened;
PaissaClient.OnPlotUpdate += OnPlotUpdate;
@@ -149,25 +134,30 @@ private void OnUpdateEvent(IFramework f) {
///
private void OnPlotOpened(object sender, PlotOpenedEventArgs e) {
if (e.PlotDetail == null) return;
- bool notifEnabled = Utils.ConfigEnabledForPlot(this, e.PlotDetail.world_id, e.PlotDetail.district_id, e.PlotDetail.size, e.PlotDetail.purchase_system);
+ bool notifEnabled = Utils.ConfigEnabledForPlot(this, e.PlotDetail.world_id, e.PlotDetail.district_id,
+ e.PlotDetail.size, e.PlotDetail.purchase_system);
if (!notifEnabled) return;
// we only notify on PlotOpen if the purchase type is FCFS or we know it is available
- if (!((e.PlotDetail.purchase_system & PurchaseSystem.Lottery) == 0 || e.PlotDetail.lotto_phase == AvailabilityType.Available)) return;
+ if (!((e.PlotDetail.purchase_system & PurchaseSystem.Lottery) == 0 ||
+ e.PlotDetail.lotto_phase == AvailabilityType.Available)) return;
World eventWorld = Worlds.GetRow(e.PlotDetail.world_id);
- OnFoundOpenHouse(e.PlotDetail.world_id, e.PlotDetail.district_id, e.PlotDetail.ward_number, e.PlotDetail.plot_number, e.PlotDetail.price,
+ OnFoundOpenHouse(e.PlotDetail.world_id, e.PlotDetail.district_id, e.PlotDetail.ward_number,
+ e.PlotDetail.plot_number, e.PlotDetail.price,
$"New plot available for purchase on {eventWorld?.Name}: ");
}
private void OnPlotUpdate(object sender, PlotUpdateEventArgs e) {
if (e.PlotUpdate == null) return;
- bool notifEnabled = Utils.ConfigEnabledForPlot(this, e.PlotUpdate.world_id, e.PlotUpdate.district_id, e.PlotUpdate.size, e.PlotUpdate.purchase_system);
+ bool notifEnabled = Utils.ConfigEnabledForPlot(this, e.PlotUpdate.world_id, e.PlotUpdate.district_id,
+ e.PlotUpdate.size, e.PlotUpdate.purchase_system);
if (!notifEnabled) return;
// we only notify on PlotUpdate if the purchase type is lottery and it is available now and was not before
if (!((e.PlotUpdate.purchase_system & PurchaseSystem.Lottery) == PurchaseSystem.Lottery
&& e.PlotUpdate.previous_lotto_phase != AvailabilityType.Available
&& e.PlotUpdate.lotto_phase == AvailabilityType.Available)) return;
World eventWorld = Worlds.GetRow(e.PlotUpdate.world_id);
- OnFoundOpenHouse(e.PlotUpdate.world_id, e.PlotUpdate.district_id, e.PlotUpdate.ward_number, e.PlotUpdate.plot_number, e.PlotUpdate.price,
+ OnFoundOpenHouse(e.PlotUpdate.world_id, e.PlotUpdate.district_id, e.PlotUpdate.ward_number,
+ e.PlotUpdate.plot_number, e.PlotUpdate.price,
$"New plot available for purchase on {eventWorld?.Name}: ");
}
@@ -175,15 +165,19 @@ private void OnPlotUpdate(object sender, PlotUpdateEventArgs e) {
///
/// Display the details of an open plot in the user's preferred format.
///
- internal void OnFoundOpenHouse(uint worldId, uint territoryTypeId, int wardNumber, int plotNumber, uint? price, string messagePrefix = "") {
+ internal void OnFoundOpenHouse(uint worldId, uint territoryTypeId, int wardNumber, int plotNumber, uint? price,
+ string messagePrefix = "") {
PlaceName place = Territories.GetRow(territoryTypeId)?.PlaceName.Value;
// languages like German do not use NameNoArticle (#2)
- Lumina.Text.SeString districtName = place?.NameNoArticle.RawString.Length > 0 ? place.NameNoArticle : place?.Name;
+ Lumina.Text.SeString districtName =
+ place?.NameNoArticle.RawString.Length > 0 ? place.NameNoArticle : place?.Name;
Lumina.Text.SeString worldName = Worlds.GetRow(worldId)?.Name;
HousingLandSet landSet = HousingLandSets.GetRow(Utils.TerritoryTypeIdToLandSetId(territoryTypeId));
byte? houseSize = landSet?.PlotSize[plotNumber];
- uint realPrice = price.GetValueOrDefault(landSet?.InitialPrice[plotNumber] ?? 0); // if price is null, it's probably the default price (landupdate)
+ uint realPrice =
+ price.GetValueOrDefault(landSet?.InitialPrice[plotNumber] ??
+ 0); // if price is null, it's probably the default price (landupdate)
string districtNameNoSpaces = districtName?.ToString().Replace(" ", "");
int wardNum = wardNumber + 1;
@@ -198,17 +192,21 @@ internal void OnFoundOpenHouse(uint worldId, uint territoryTypeId, int wardNumbe
string output;
switch (Configuration.OutputFormat) {
case OutputFormat.Pings:
- output = $"{messagePrefix}@{houseSizeName}{districtNameNoSpaces} {wardNum}-{plotNum} ({housePriceMillions:F3}m)";
+ output =
+ $"{messagePrefix}@{houseSizeName}{districtNameNoSpaces} {wardNum}-{plotNum} ({housePriceMillions:F3}m)";
break;
case OutputFormat.Custom:
var template = $"{messagePrefix}{Configuration.OutputFormatString}";
- output = Utils.FormatCustomOutputString(template, districtName?.ToString(), districtNameNoSpaces, worldName, wardNum.ToString(),
+ output = Utils.FormatCustomOutputString(template, districtName?.ToString(), districtNameNoSpaces,
+ worldName, wardNum.ToString(),
plotNum.ToString(), realPrice.ToString(), housePriceMillions.ToString("F3"), houseSizeName);
break;
default:
- output = $"{messagePrefix}{districtName} {wardNum}-{plotNum} ({houseSizeName}, {housePriceMillions:F3}m)";
+ output =
+ $"{messagePrefix}{districtName} {wardNum}-{plotNum} ({houseSizeName}, {housePriceMillions:F3}m)";
break;
}
+
SendChatToConfiguredChannel(output);
}
@@ -230,4 +228,4 @@ private void DrawConfigUI() {
ui.SettingsVisible = true;
}
}
-}
+}
\ No newline at end of file
diff --git a/packages.lock.json b/packages.lock.json
index 7395c0f..0c68f30 100644
--- a/packages.lock.json
+++ b/packages.lock.json
@@ -1,12 +1,12 @@
{
"version": 1,
"dependencies": {
- "net7.0-windows7.0": {
+ "net8.0-windows7.0": {
"DalamudPackager": {
"type": "Direct",
- "requested": "[2.1.12, )",
- "resolved": "2.1.12",
- "contentHash": "Sc0PVxvgg4NQjcI8n10/VfUQBAS4O+Fw2pZrAqBdRMbthYGeogzu5+xmIGCGmsEZ/ukMOBuAqiNiB5qA3MRalg=="
+ "requested": "[2.1.13, )",
+ "resolved": "2.1.13",
+ "contentHash": "rMN1omGe8536f4xLMvx9NwfvpAc9YFFfeXJ1t4P4PE6Gu8WCIoFliR1sh07hM+bfODmesk/dvMbji7vNI+B/pQ=="
},
"DebounceThrottle": {
"type": "Direct",