158 lines
5.5 KiB
C#
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();
|
|
}
|
|
}
|