Skip to content

Commit

Permalink
refactor: update for 6.5
Browse files Browse the repository at this point in the history
  • Loading branch information
zhudotexe committed Oct 5, 2023
1 parent 00fd42f commit bdbcfed
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 89 deletions.
4 changes: 2 additions & 2 deletions AutoSweep.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
<AssemblyName>autoSweep</AssemblyName>
<AssemblyVersion>1.4.2.0</AssemblyVersion>
<AssemblyVersion>1.4.3.0</AssemblyVersion>
</PropertyGroup>

<PropertyGroup>
Expand Down Expand Up @@ -68,7 +68,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="DalamudPackager" Version="2.1.11" />
<PackageReference Include="DalamudPackager" Version="2.1.12" />
<PackageReference Include="DebounceThrottle" Version="2.0.0" />
<PackageReference Include="WebSocketSharp.Standard" Version="1.0.3" />
</ItemGroup>
Expand Down
53 changes: 27 additions & 26 deletions Paissa/Client.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,8 @@
using System.Text;
using System.Threading.Tasks;
using AutoSweep.Structures;
using Dalamud.Game.ClientState;
using Dalamud.Game.ClientState.Objects.SubKinds;
using Dalamud.Game.Gui;
using Dalamud.Logging;
using Dalamud.Plugin.Services;
using DebounceThrottle;
using Newtonsoft.Json;
using WebSocketSharp;
Expand All @@ -22,8 +20,9 @@ public class PaissaClient : IDisposable {
private string sessionToken;

// dalamud
private readonly ClientState clientState;
private readonly ChatGui chat;
private readonly IClientState clientState;
private readonly IChatGui chat;
private readonly IPluginLog log;

// ingest debounce
private readonly DebounceDispatcher ingestDebounceDispatcher = new DebounceDispatcher(1200);
Expand All @@ -42,9 +41,10 @@ public class PaissaClient : IDisposable {
public event EventHandler<PlotUpdateEventArgs> OnPlotUpdate;
public event EventHandler<PlotSoldEventArgs> OnPlotSold;

public PaissaClient(ClientState clientState, ChatGui chatGui) {
public PaissaClient(IClientState clientState, IChatGui chatGui, IPluginLog log) {
this.clientState = clientState;
chat = chatGui;
this.log = log;
http = new HttpClient();
ReconnectWS();
}
Expand All @@ -61,21 +61,22 @@ public void Dispose() {
/// </summary>
public async Task Hello() {
PlayerCharacter player = clientState.LocalPlayer;
if (player == null)
return;
if (player == null) return;
var homeworld = player.HomeWorld.GameData;
if (homeworld == null) return;
var charInfo = new Dictionary<string, object> {
{ "cid", clientState.LocalContentId },
{ "name", player.Name.ToString() },
{ "world", player.HomeWorld.GameData.Name.ToString() },
{ "world", homeworld.Name.ToString() },
{ "worldId", player.HomeWorld.Id }
};
string content = JsonConvert.SerializeObject(charInfo);
PluginLog.Debug(content);
log.Debug(content);
var response = await Post("/hello", content, false);
if (response.IsSuccessStatusCode) {
string respText = await response.Content.ReadAsStringAsync();
sessionToken = JsonConvert.DeserializeObject<HelloResponse>(respText).session_token;
PluginLog.Log("Completed PaissaDB HELLO");
log.Info("Completed PaissaDB HELLO");
}
}

Expand Down Expand Up @@ -123,7 +124,7 @@ public void PostLotteryInfo(uint worldId, ushort districtId, ushort wardId, usho
/// <returns>The DistrictDetail</returns>
public async Task<DistrictDetail> GetDistrictDetailAsync(short worldId, short districtId) {
HttpResponseMessage response = await http.GetAsync($"{apiBase}/worlds/{worldId}/{districtId}");
PluginLog.Debug($"GET {apiBase}/worlds/{worldId}/{districtId} returned {response.StatusCode} ({response.ReasonPhrase})");
log.Debug($"GET {apiBase}/worlds/{worldId}/{districtId} returned {response.StatusCode} ({response.ReasonPhrase})");
response.EnsureSuccessStatusCode();
string respText = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<DistrictDetail>(respText);
Expand All @@ -135,7 +136,7 @@ private void queueIngest(object data) {
ingestDebounceDispatcher.Debounce(() => {
string bulkIngestData = JsonConvert.SerializeObject(ingestDataQueue);
PostFireAndForget("/ingest", bulkIngestData);
PluginLog.Debug($"Bulk ingesting {ingestDataQueue.Count} entries ({bulkIngestData.Length}B)");
log.Debug($"Bulk ingesting {ingestDataQueue.Count} entries ({bulkIngestData.Length}B)");
ingestDataQueue.Clear();
});
}
Expand All @@ -146,13 +147,13 @@ private async void PostFireAndForget(string route, string content, bool auth = t

private async Task<HttpResponseMessage> Post(string route, string content, bool auth = true, ushort retries = 5) {
HttpResponseMessage response = null;
PluginLog.Verbose(content);
log.Verbose(content);

for (var i = 0; i < retries; i++) {
HttpRequestMessage request;
if (auth) {
if (sessionToken == null) {
PluginLog.LogWarning("Trying to send authed request but no session token!");
log.Warning("Trying to send authed request but no session token!");
await Hello();
continue;
}
Expand All @@ -169,20 +170,20 @@ private async Task<HttpResponseMessage> Post(string route, string content, bool
}
try {
response = await http.SendAsync(request);
PluginLog.Debug($"{request.Method} {request.RequestUri} returned {response.StatusCode} ({response.ReasonPhrase})");
log.Debug($"{request.Method} {request.RequestUri} returned {response.StatusCode} ({response.ReasonPhrase})");
if (!response.IsSuccessStatusCode) {
string respText = await response.Content.ReadAsStringAsync();
PluginLog.Warning($"{request.Method} {request.RequestUri} returned {response.StatusCode} ({response.ReasonPhrase}):\n{respText}");
log.Warning($"{request.Method} {request.RequestUri} returned {response.StatusCode} ({response.ReasonPhrase}):\n{respText}");
} else {
break;
}
} catch (Exception e) {
PluginLog.Warning(e, $"{request.Method} {request.RequestUri} raised an error:");
log.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);
PluginLog.Warning($"Request {i} failed, waiting for {toDelay}ms before retry...");
log.Warning($"Request {i} failed, waiting for {toDelay}ms before retry...");
await Task.Delay(toDelay);
}
}
Expand Down Expand Up @@ -214,17 +215,17 @@ private void ReconnectWS() {
// todo what is happening here?
// https://github.com/zhudotexe/FFXIV_PaissaHouse/issues/14
}
PluginLog.Debug("ReconnectWS complete");
log.Debug("ReconnectWS complete");
});
}

private void OnWSOpen(object sender, EventArgs e) {
PluginLog.Information("WebSocket connected");
log.Information("WebSocket connected");
}

private void OnWSMessage(object sender, MessageEventArgs e) {
if (!e.IsText) return;
PluginLog.Verbose($">>>> R: {e.Data}");
log.Verbose($">>>> R: {e.Data}");
var message = JsonConvert.DeserializeObject<WSMessage>(e.Data);
switch (message.Type) {
case "plot_open":
Expand All @@ -239,28 +240,28 @@ private void OnWSMessage(object sender, MessageEventArgs e) {
case "ping":
break;
default:
PluginLog.Warning($"Got unknown WS message: {e.Data}");
log.Warning($"Got unknown WS message: {e.Data}");
break;
}
}

private void OnWSClose(object sender, CloseEventArgs e) {
PluginLog.Information($"WebSocket closed ({e.Code}: {e.Reason})");
log.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) {
PluginLog.LogWarning(e.Exception, $"WebSocket error: {e.Message}");
log.Warning(e.Exception, $"WebSocket error: {e.Message}");
if (!disposed)
WSReconnectSoon();
}

private void WSReconnectSoon() {
if (ws.IsAlive) return;
int t = new Random().Next(5_000, 15_000);
PluginLog.Warning($"WebSocket closed unexpectedly: will reconnect to socket in {t / 1000f:F3} seconds");
log.Warning($"WebSocket closed unexpectedly: will reconnect to socket in {t / 1000f:F3} seconds");
Task.Run(async () => await Task.Delay(t)).ContinueWith(_ => {
if (!disposed) ReconnectWS();
});
Expand Down
20 changes: 10 additions & 10 deletions Paissa/LotteryObserver.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System;
using AutoSweep.Structures;
using Dalamud.Hooking;
using Dalamud.Logging;
using Dalamud.Utility.Signatures;
using Lumina.Excel.GeneratedSheets;
using Lumina.Text;
Expand All @@ -22,16 +21,16 @@ long a8
);

[Signature("E8 ?? ?? ?? ?? 48 8B B4 24 ?? ?? ?? ?? 48 8B 6C 24 ?? E9", DetourName = nameof(OnPlacardSaleInfo))]
private Hook<HandlePlacardSaleInfoDelegate>? PlacardSaleInfoHook { get; init; }
private Hook<HandlePlacardSaleInfoDelegate>? placardSaleInfoHook;

public LotteryObserver(Plugin plugin) {
SignatureHelper.Initialise(this);
this.plugin = plugin;
PlacardSaleInfoHook?.Enable();
plugin.InteropProvider.InitializeFromAttributes(this);
placardSaleInfoHook?.Enable();
}

public void Dispose() {
PlacardSaleInfoHook?.Dispose();
placardSaleInfoHook?.Dispose();
}

public void OnPlacardSaleInfo(
Expand All @@ -44,18 +43,19 @@ public void OnPlacardSaleInfo(
IntPtr placardSaleInfoPtr,
long a8
) {
PlacardSaleInfoHook!.Original(agentBase, housingType, territoryTypeId, wardId, plotId, apartmentNumber, placardSaleInfoPtr, a8);
placardSaleInfoHook!.Original(agentBase, housingType, territoryTypeId, wardId, plotId, apartmentNumber, placardSaleInfoPtr, a8);

// if the plot is owned, ignore it
if (housingType != HousingType.UnownedHouse) return;
if (placardSaleInfoPtr == IntPtr.Zero) return;

PlacardSaleInfo saleInfo = PlacardSaleInfo.Read(placardSaleInfoPtr);

PluginLog.LogDebug(
plugin.PluginLog.Debug(
$"Got PlacardSaleInfo: PurchaseType={saleInfo.PurchaseType}, TenantType={saleInfo.TenantType}, available={saleInfo.AvailabilityType}, until={saleInfo.PhaseEndsAt}, numEntries={saleInfo.EntryCount}");
PluginLog.LogDebug($"unknown1={saleInfo.Unknown1}, unknown2={saleInfo.Unknown2}, unknown3={saleInfo.Unknown3}, unknown4={BitConverter.ToString(saleInfo.Unknown4)}");
PluginLog.LogDebug(
plugin.PluginLog.Debug(
$"unknown1={saleInfo.Unknown1}, unknown2={saleInfo.Unknown2}, unknown3={saleInfo.Unknown3}, unknown4={BitConverter.ToString(saleInfo.Unknown4)}");
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
Expand All @@ -64,7 +64,7 @@ long a8

SeString place = plugin.Territories.GetRow(territoryTypeId)?.PlaceName.Value?.Name;
SeString worldName = world.Name;
PluginLog.LogInformation($"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);
}
Expand Down
6 changes: 1 addition & 5 deletions Paissa/Utils.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
using Dalamud.Game.ClientState;
using Dalamud.Logging;
using Lumina.Excel.GeneratedSheets;

namespace AutoSweep.Paissa {
Expand Down Expand Up @@ -46,7 +44,7 @@ public static bool ConfigEnabledForPlot(Plugin plugin, ushort worldId, ushort di
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.DatacenterNotifs && eventWorld?.DataCenter.Row == plugin.ClientState.LocalPlayer?.HomeWorld.GameData?.DataCenter.Row))
return false;
// get the district config
DistrictNotifConfig districtNotifs;
Expand All @@ -67,7 +65,6 @@ public static bool ConfigEnabledForPlot(Plugin plugin, ushort worldId, ushort di
districtNotifs = plugin.Configuration.Empyrean;
break;
default:
PluginLog.Warning($"Unknown district in plot open event: {districtId}");
return false;
}
// what about house sizes in this district?
Expand All @@ -83,7 +80,6 @@ public static bool ConfigEnabledForPlot(Plugin plugin, ushort worldId, ushort di
notifEnabled = districtNotifs.Large;
break;
default:
PluginLog.Warning($"Unknown plot size in plot open event: {size}");
return false;
}
// and FC/individual purchase?
Expand Down
33 changes: 27 additions & 6 deletions Paissa/WardObserver.cs
Original file line number Diff line number Diff line change
@@ -1,23 +1,44 @@
using System;
using System.Runtime.InteropServices;
using AutoSweep.Structures;
using Dalamud.Logging;
using Dalamud.Hooking;
using Dalamud.Utility.Signatures;
using Lumina.Text;

namespace AutoSweep.Paissa {
public class WardObserver {
public unsafe class WardObserver {
private Plugin plugin;
internal readonly SweepState SweepState;

private delegate void HandleHousingWardInfoDelegate(
void* agentBase,
IntPtr housingWardInfoPtr
);

[Signature("40 55 57 41 54 41 56 41 57 48 8D AC 24 ?? ?? ?? ?? B8", DetourName = nameof(OnHousingWardInfo))]
private Hook<HandleHousingWardInfoDelegate>? housingWardInfoHook;

public WardObserver(Plugin plugin) {
this.plugin = plugin;
plugin.InteropProvider.InitializeFromAttributes(this);
SweepState = new SweepState(Utils.NumWardsPerDistrict);
housingWardInfoHook?.Enable();
}

public void OnHousingWardInfo(IntPtr dataPtr) {
public void Dispose() {
housingWardInfoHook?.Dispose();
}

public void OnHousingWardInfo(
void* agentBase,
IntPtr dataPtr
) {
housingWardInfoHook!.Original(agentBase, dataPtr);

if (!plugin.Configuration.Enabled) return;
HousingWardInfo wardInfo = HousingWardInfo.Read(dataPtr);
int serverTimestamp = Marshal.ReadInt32(dataPtr - 0x8);
PluginLog.LogDebug($"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
Expand All @@ -34,7 +55,7 @@ public void OnHousingWardInfo(IntPtr dataPtr) {

// if we've seen this ward already, ignore it
if (SweepState.Contains(wardInfo)) {
PluginLog.LogDebug($"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;
}

Expand All @@ -47,7 +68,7 @@ public void OnHousingWardInfo(IntPtr dataPtr) {
// if that's all the wards, display the district summary and thanks
if (SweepState.IsComplete) OnFinishedDistrictSweep(wardInfo);

PluginLog.LogDebug($"Done processing HousingWardInfo for ward: {wardInfo.LandIdent.WardNumber}");
plugin.PluginLog.Debug($"Done processing HousingWardInfo for ward: {wardInfo.LandIdent.WardNumber}");
}

/// <summary>
Expand Down
Loading

0 comments on commit bdbcfed

Please sign in to comment.