From dc9e122aa0f5892d3a8918b7af0f476244170531 Mon Sep 17 00:00:00 2001 From: Andrew Zhu Date: Sat, 16 Apr 2022 02:28:48 -0700 Subject: [PATCH] feat: handle lottery state updates --- Paissa/Client.cs | 4 +++ Paissa/Events.cs | 8 ++++++ Paissa/Schema.cs | 29 ++++++++++++++++++++- Paissa/Utils.cs | 52 ++++++++++++++++++++++++++++++++++++++ Plugin.cs | 66 +++++++++++++++--------------------------------- 5 files changed, 112 insertions(+), 47 deletions(-) diff --git a/Paissa/Client.cs b/Paissa/Client.cs index e0d57c6..fdc0c2d 100644 --- a/Paissa/Client.cs +++ b/Paissa/Client.cs @@ -43,6 +43,7 @@ public class PaissaClient : IDisposable { private readonly byte[] secret = Encoding.UTF8.GetBytes(Secrets.JwtSecret); public event EventHandler OnPlotOpened; + public event EventHandler OnPlotUpdate; public event EventHandler OnPlotSold; public PaissaClient(ClientState clientState, ChatGui chatGui) { @@ -206,6 +207,9 @@ private void OnWSMessage(object sender, MessageEventArgs e) { case "plot_open": OnPlotOpened?.Invoke(this, new PlotOpenedEventArgs(message.Data.ToObject())); break; + case "plot_update": + OnPlotUpdate?.Invoke(this, new PlotUpdateEventArgs(message.Data.ToObject())); + break; case "plot_sold": OnPlotSold?.Invoke(this, new PlotSoldEventArgs(message.Data.ToObject())); break; diff --git a/Paissa/Events.cs b/Paissa/Events.cs index 47c43af..cfb43f4 100644 --- a/Paissa/Events.cs +++ b/Paissa/Events.cs @@ -9,6 +9,14 @@ public PlotOpenedEventArgs(OpenPlotDetail plotDetail) { public OpenPlotDetail PlotDetail { get; set; } } + public class PlotUpdateEventArgs : EventArgs { + public PlotUpdateEventArgs(PlotUpdate plotUpdate) { + PlotUpdate = plotUpdate; + } + + public PlotUpdate PlotUpdate { get; set; } + } + public class PlotSoldEventArgs : EventArgs { public PlotSoldEventArgs(SoldPlotDetail plotDetail) { PlotDetail = plotDetail; diff --git a/Paissa/Schema.cs b/Paissa/Schema.cs index eccc0dd..c7c0f17 100644 --- a/Paissa/Schema.cs +++ b/Paissa/Schema.cs @@ -1,4 +1,5 @@ using System; +using AutoSweep.Structures; using Newtonsoft.Json.Linq; // ReSharper disable InconsistentNaming @@ -22,10 +23,29 @@ public class OpenPlotDetail { public ushort ward_number { get; set; } public ushort plot_number { get; set; } public ushort size { get; set; } - public uint last_seen_price { get; set; } + public uint price { get; set; } public float last_updated_time { get; set; } public float est_time_open_min { get; set; } public float est_time_open_max { get; set; } + public PurchaseSystem purchase_system { get; set; } + public uint? lotto_entries { get; set; } + public AvailabilityType? lotto_phase { get; set; } + public uint? lotto_phase_until { get; set; } + } + + public class PlotUpdate { + public ushort world_id { get; set; } + public ushort district_id { get; set; } + public ushort ward_number { get; set; } + public ushort plot_number { get; set; } + public ushort size { get; set; } + public uint price { get; set; } + public float last_updated_time { get; set; } + public PurchaseSystem purchase_system { get; set; } + public uint lotto_entries { get; set; } + public AvailabilityType lotto_phase { get; set; } + public AvailabilityType? previous_lotto_phase { get; set; } + public uint lotto_phase_until { get; set; } } public class SoldPlotDetail { @@ -38,4 +58,11 @@ public class SoldPlotDetail { public float est_time_sold_min { get; set; } public float est_time_sold_max { get; set; } } + + [Flags] + public enum PurchaseSystem : byte { + Lottery = 1, + FreeCompany = 2, + Individual = 4 + } } diff --git a/Paissa/Utils.cs b/Paissa/Utils.cs index cb35faa..c3c2614 100644 --- a/Paissa/Utils.cs +++ b/Paissa/Utils.cs @@ -1,3 +1,7 @@ +using Dalamud.Game.ClientState; +using Dalamud.Logging; +using Lumina.Excel.GeneratedSheets; + namespace AutoSweep.Paissa { public class Utils { // configuration constants @@ -34,5 +38,53 @@ string houseSizeName .Replace("{housePriceMillions}", housePriceMillions) .Replace("{houseSizeName}", houseSizeName); } + + public static bool ConfigEnabledForPlot(Plugin plugin, ushort worldId, ushort districtId, ushort size) { + 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)) + return false; + // what about house sizes in this district? + DistrictNotifConfig districtNotifs; + switch (districtId) { + case 339: + districtNotifs = plugin.Configuration.Mist; + break; + case 340: + districtNotifs = plugin.Configuration.LavenderBeds; + break; + case 341: + districtNotifs = plugin.Configuration.Goblet; + break; + case 641: + districtNotifs = plugin.Configuration.Shirogane; + break; + case 979: + districtNotifs = plugin.Configuration.Empyrean; + break; + default: + PluginLog.Warning($"Unknown district in plot open event: {districtId}"); + return false; + } + bool notifEnabled; + switch (size) { + case 0: + notifEnabled = districtNotifs.Small; + break; + case 1: + notifEnabled = districtNotifs.Medium; + break; + case 2: + notifEnabled = districtNotifs.Large; + break; + default: + PluginLog.Warning($"Unknown plot size in plot open event: {size}"); + return false; + } + return notifEnabled; + } } } diff --git a/Plugin.cs b/Plugin.cs index 20486a1..7b02da9 100644 --- a/Plugin.cs +++ b/Plugin.cs @@ -1,5 +1,6 @@ using System; using AutoSweep.Paissa; +using AutoSweep.Structures; using Dalamud.Data; using Dalamud.Game; using Dalamud.Game.ClientState; @@ -80,6 +81,7 @@ GameGui gameGui lotteryObserver = new LotteryObserver(this); PaissaClient = new PaissaClient(clientState, chat); PaissaClient.OnPlotOpened += OnPlotOpened; + PaissaClient.OnPlotUpdate += OnPlotUpdate; PluginLog.LogDebug($"Initialization complete: configVersion={Configuration.Version}"); } @@ -131,55 +133,27 @@ private void OnNetworkEvent(IntPtr dataPtr, ushort opCode, uint sourceActorId, u /// Hook to call when a new plot open event is received over the websocket. /// private void OnPlotOpened(object sender, PlotOpenedEventArgs e) { - if (!Configuration.Enabled) return; if (e.PlotDetail == null) return; - // does the config want notifs for this world? + bool notifEnabled = Utils.ConfigEnabledForPlot(this, e.PlotDetail.world_id, e.PlotDetail.district_id, e.PlotDetail.size); + 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; World eventWorld = Worlds.GetRow(e.PlotDetail.world_id); - if (!(Configuration.AllNotifs - || Configuration.HomeworldNotifs && e.PlotDetail.world_id == ClientState.LocalPlayer?.HomeWorld.Id - || Configuration.DatacenterNotifs && eventWorld?.DataCenter.Row == ClientState.LocalPlayer?.HomeWorld.GameData.DataCenter.Row)) - return; - // what about house sizes in this district? - DistrictNotifConfig districtNotifs; - switch (e.PlotDetail.district_id) { - case 339: - districtNotifs = Configuration.Mist; - break; - case 340: - districtNotifs = Configuration.LavenderBeds; - break; - case 341: - districtNotifs = Configuration.Goblet; - break; - case 641: - districtNotifs = Configuration.Shirogane; - break; - case 979: - districtNotifs = Configuration.Empyrean; - break; - default: - PluginLog.Warning($"Unknown district in plot open event: {e.PlotDetail.district_id}"); - return; - } - bool notifEnabled; - switch (e.PlotDetail.size) { - case 0: - notifEnabled = districtNotifs.Small; - break; - case 1: - notifEnabled = districtNotifs.Medium; - break; - case 2: - notifEnabled = districtNotifs.Large; - break; - default: - PluginLog.Warning($"Unknown plot size in plot open event: {e.PlotDetail.size}"); - return; - } - // do the notification + 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); if (!notifEnabled) return; - OnFoundOpenHouse(e.PlotDetail.world_id, e.PlotDetail.district_id, e.PlotDetail.ward_number, e.PlotDetail.plot_number, e.PlotDetail.last_seen_price, - $"New plot up for sale on {eventWorld?.Name}: "); + // 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, + $"New plot available for purchase on {eventWorld?.Name}: "); }