TheWatcher/AutoShutdown/Plogon.cs
2024-11-15 23:22:00 +01:00

158 lines
5.5 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Threading.Tasks;
using System.Windows.Forms;
using AutoRetainerAPI;
using Dalamud;
using Dalamud.Game;
using Dalamud.Plugin;
using Dalamud.Plugin.Services;
using ECommons;
using FFXIVClientStructs.FFXIV.Client.System.Framework;
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
using FFXIVClientStructs.FFXIV.Component.GUI;
using LLib;
using LLib.GameUI;
using Task = System.Threading.Tasks.Task;
namespace AutoShutdown;
public sealed class Plogon : IDalamudPlugin
{
private readonly HttpClient _httpClient = new() { Timeout = TimeSpan.FromSeconds(1) };
private readonly nint _skipMovieAddress;
private readonly byte[] _skipMovieOriginalBytes;
private readonly AutoRetainerApi _autoRetainerApi;
private readonly DalamudReflector _reflector;
private readonly IPluginLog _pluginLog;
private readonly IClientState _clientState;
private readonly IGameGui _gameGui;
private readonly IFramework _framework;
public Plogon(IDalamudPluginInterface pluginInterface, IFramework framework, IPluginLog pluginLog,
IClientState clientState, IGameGui gameGui, ISigScanner sigScanner)
{
_skipMovieAddress = sigScanner.ScanText("48 01 8E ?? ?? ?? ?? 48 81 BE ?? ?? ?? ?? 60 EA 00 00");
SafeMemory.ReadBytes(_skipMovieAddress, 7, out _skipMovieOriginalBytes);
ECommonsMain.Init(pluginInterface, this);
_autoRetainerApi = new AutoRetainerApi();
_reflector = new DalamudReflector(pluginInterface, framework, pluginLog);
_framework = framework;
_pluginLog = pluginLog;
_clientState = clientState;
_gameGui = gameGui;
_clientState.Logout += OnLogout;
_framework.Update += FrameworkUpdate;
_framework.RunOnTick(MoveToBackground, TimeSpan.FromSeconds(10));
// we don't want to watch movies, regardless of how long we're gone - 7 byte NOP for the 'add [rsi+1110h], rcx'
SafeMemory.WriteBytes(_skipMovieAddress, [0x0F, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00]);
unsafe
{
var lobby = AgentLobby.Instance();
if (lobby != null)
lobby->IdleTime = 0;
}
}
private DateTime ShutdownAt { get; } = DateTime.Now.AddDays(2);
private unsafe void FrameworkUpdate(IFramework _)
{
if (DateTime.Now > ShutdownAt && _gameGui.TryGetAddonByName<AtkUnitBase>("_TitleMenu", out var _))
{
Environment.Exit(0);
}
}
private bool IsMultiAndNightMode()
{
if (_autoRetainerApi.Ready && _reflector.TryGetDalamudPlugin("AutoRetainer", out var autoRetainer, false, true))
{
var mm = autoRetainer.GetType().Assembly.GetType("AutoRetainer.Modules.Multi.MultiMode")!;
bool multi = (bool)mm.GetProperty("Active", BindingFlags.Static | BindingFlags.NonPublic)!.GetValue(null)!;
var config =
autoRetainer.GetType().GetProperty("C", BindingFlags.Static | BindingFlags.NonPublic)!.GetValue(null)!;
bool nightMode = (bool)config.GetType().GetField("NightMode", BindingFlags.Instance | BindingFlags.Public)!
.GetValue(config)!;
//_pluginLog.Information($"AR: multi={multi}, night={nightMode}");
return multi && nightMode;
}
return false;
}
private void MoveToBackground()
{
if (IsMultiAndNightMode())
{
// move to background using alt+esc
unsafe
{
if (!Framework.Instance()->WindowInactive)
SendKeys.SendWait("%({esc})");
}
}
}
private void OnLogout(int type, int code)
{
if (IsMultiAndNightMode())
{
List<TimeSpan> nextVesselTimes =
_autoRetainerApi.GetRegisteredCharacters().SelectMany(localContentId =>
{
var data = _autoRetainerApi.GetOfflineCharacterData(localContentId);
return data.OfflineSubmarineData.Where(x => data.EnabledSubs.Contains(x.Name))
.Select(x => TimeSpan.FromSeconds(x.ReturnTime - Framework.GetServerTime()))
.Select(x => x <= TimeSpan.Zero ? TimeSpan.Zero : x)
.ToList();
})
.ToList();
if (nextVesselTimes.Count > 0)
{
TimeSpan next = nextVesselTimes.Min();
_pluginLog.Information($"Next vessel time: {next}");
if (next != TimeSpan.Zero)
{
Task.Factory.StartNew(async () =>
{
try
{
await _httpClient.PostAsync(new Uri($"http://localhost:12994/{next.TotalSeconds:F0}"),
null);
}
catch (Exception e)
{
_pluginLog.Warning(e, "Unable to send IPC");
}
}, TaskCreationOptions.LongRunning);
}
}
}
MoveToBackground();
}
public void Dispose()
{
SafeMemory.WriteBytes(_skipMovieAddress, _skipMovieOriginalBytes);
_framework.Update -= FrameworkUpdate;
_clientState.Logout -= OnLogout;
_reflector.Dispose();
_autoRetainerApi.Dispose();
ECommonsMain.Dispose();
}
}