1
0
vibe-plugin/FFXIV_Vibe_Plugin/App/App.cs
2023-01-30 21:04:22 +01:00

344 lines
12 KiB
C#

using System.Collections.Generic;
using System;
using System.Threading;
// Dalamud libs
using Dalamud.IoC;
using Dalamud.Data;
using Dalamud.Plugin;
using Dalamud.Game;
using Dalamud.Game.Text;
using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Game.Network;
using Dalamud.Game.Command;
using Dalamud.Game.ClientState;
using Dalamud.Game.ClientState.Objects;
using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel;
using Dalamud.Interface.Windowing;
// FFXIV_Vibe_Plugin libs
using FFXIV_Vibe_Plugin.Commons;
using FFXIV_Vibe_Plugin.Triggers;
using FFXIV_Vibe_Plugin.Hooks;
using FFXIV_Vibe_Plugin.Experimental;
using FFXIV_Vibe_Plugin.Migrations;
namespace FFXIV_Vibe_Plugin {
public class App {
private Dalamud.Game.Gui.ChatGui? DalamudChat { get; init; }
public Configuration Configuration { get; init; }
private GameNetwork GameNetwork { get; init; }
private DataManager DataManager { get; init; }
private ClientState ClientState { get; init; }
private SigScanner Scanner { get; init; }
private ObjectTable GameObjects { get; init; }
private DalamudPluginInterface PluginInterface { get; init; }
// Custom variables from Kacie
private readonly Plugin Plugin;
private readonly bool wasInit = false;
public readonly string CommandName = "";
public PluginUI PluginUi { get; init; }
private readonly string ShortName = "";
private bool _firstUpdated = false;
private readonly PlayerStats PlayerStats;
private ConfigurationProfile ConfigurationProfile;
private readonly Logger Logger;
private readonly ActionEffect hook_ActionEffect;
private readonly Device.DevicesController DeviceController;
private readonly TriggersController TriggersController;
private readonly Patterns Patterns;
// Experiments
private readonly NetworkCapture experiment_networkCapture;
public App(Plugin plugin, string commandName, string shortName, GameNetwork gameNetwork, ClientState clientState, DataManager dataManager, Dalamud.Game.Gui.ChatGui? dalamudChat, Configuration configuration, SigScanner scanner, ObjectTable gameObjects, DalamudPluginInterface pluginInterface) {
this.Plugin = plugin;
this.CommandName = commandName;
this.ShortName = shortName;
this.GameNetwork = gameNetwork;
this.ClientState = clientState;
this.DataManager = dataManager;
this.DalamudChat = dalamudChat;
this.Configuration = configuration;
this.GameObjects = gameObjects;
this.Scanner = scanner;
this.PluginInterface = pluginInterface;
if (DalamudChat != null) {
DalamudChat.ChatMessage += ChatWasTriggered;
}
this.Logger = new Logger(this.DalamudChat, ShortName, Logger.LogLevel.VERBOSE);
if(DalamudChat == null) {
this.Logger.Error("DalamudChat was not initialized correctly.");
}
// Migrations
Migration migration = new(Configuration, Logger);
migration.Patch_0_2_0_to_1_0_0_config_profile();
// Configuration Profile
this.ConfigurationProfile = this.Configuration.GetDefaultProfile();
// Patterns
this.Patterns = new Patterns();
this.Patterns.SetCustomPatterns(this.ConfigurationProfile.PatternList);
// Initialize the devices Controller
this.DeviceController = new Device.DevicesController(this.Logger, this.Configuration, this.ConfigurationProfile, this.Patterns);
if (this.ConfigurationProfile.AUTO_CONNECT) {
Thread t = new(delegate () {
Thread.Sleep(2000);
this.Command_DeviceController_Connect();
});
t.Start();
}
// Initialize Hook ActionEffect
this.hook_ActionEffect = new(this.DataManager, this.Logger, this.Scanner, clientState, gameObjects);
this.hook_ActionEffect.ReceivedEvent += SpellWasTriggered;
// Init the login event.
this.ClientState.Login += this.ClientState_LoginEvent;
// Initialize player stats monitoring.
this.PlayerStats = new PlayerStats(this.Logger, this.ClientState);
PlayerStats.Event_CurrentHpChanged += this.PlayerCurrentHPChanged;
PlayerStats.Event_MaxHpChanged += this.PlayerCurrentHPChanged;
// Triggers
this.TriggersController = new Triggers.TriggersController(this.Logger, this.PlayerStats, this.ConfigurationProfile);
// UI
this.PluginUi = new PluginUI(this, this.Logger, this.PluginInterface, this.Configuration, this.ConfigurationProfile, this.DeviceController, this.TriggersController, this.Patterns);
// Experimental
this.experiment_networkCapture = new NetworkCapture(this.Logger, this.GameNetwork);
// Make sure we set the current profile everywhere.
this.SetProfile(this.Configuration.CurrentProfileName);
// Set the init variable
this.wasInit = true;
}
public void Dispose() {
if (!this.wasInit) { return; }
this.Logger.Debug("Disposing plugin...");
// Cleaning device controller.
if (this.DeviceController != null) {
this.DeviceController.Dispose();
}
// Cleaning chat triggers.
if (DalamudChat != null) {
DalamudChat.ChatMessage -= ChatWasTriggered;
}
// Cleaning hooks
this.hook_ActionEffect.Dispose();
// Cleaning experimentations
this.experiment_networkCapture.Dispose();
this.PluginUi.Dispose();
this.Logger.Debug("Plugin disposed!");
}
public static string GetHelp(string command) {
string helpMessage = $@"Usage:
{command} config
{command} connect
{command} disconnect
{command} send <0-100> # Send vibe intensity to all toys
{command} stop
";
return helpMessage;
}
public void OnCommand(string command, string args) {
if (args.Length == 0) {
this.DisplayUI();
} else {
if (args.StartsWith("help")) {
this.Logger.Chat(App.GetHelp($"/{ShortName}"));
} else if (args.StartsWith("config")) {
this.DisplayConfigUI();
} else if (args.StartsWith("connect")) {
this.Command_DeviceController_Connect();
} else if (args.StartsWith("disconnect")) {
this.Command_DeviceController_Disconnect();
} else if (args.StartsWith("send")) {
this.Command_SendIntensity(args);
} else if (args.StartsWith("stop")) {
this.DeviceController.SendVibeToAll(0);
}
// Experimental
else if (args.StartsWith("exp_network_start")) {
this.experiment_networkCapture.StartNetworkCapture();
} else if (args.StartsWith("exp_network_stop")) {
this.experiment_networkCapture.StopNetworkCapture();
} else {
this.Logger.Chat($"Unknown subcommand: {args}");
}
}
}
private void FirstUpdated() {
this.Logger.Debug("First updated");
if (this.ConfigurationProfile != null && this.ConfigurationProfile.AUTO_OPEN) {
this.DisplayUI();
}
}
private void DisplayUI() {
this.Plugin.DrawConfigUI();
}
private void DisplayConfigUI() {
this.Plugin.DrawConfigUI();
}
public void DrawUI() {
if(this.PluginUi == null) {
return;
}
if (this.ClientState.IsLoggedIn) {
this.PlayerStats.Update(this.ClientState);
}
// Trigger first updated method
if (!this._firstUpdated) {
this.FirstUpdated();
this._firstUpdated = true;
}
}
public void Command_DeviceController_Connect() {
if (this.DeviceController == null) {
this.Logger.Error("No device controller available to connect.");
return;
}
if (this.ConfigurationProfile != null) {
string host = this.ConfigurationProfile.BUTTPLUG_SERVER_HOST;
int port = this.ConfigurationProfile.BUTTPLUG_SERVER_PORT;
this.DeviceController.Connect(host, port);
}
}
private void Command_DeviceController_Disconnect() {
if (this.DeviceController == null) {
this.Logger.Error("No device controller available to disconnect.");
return;
}
this.DeviceController.Disconnect();
}
private void Command_SendIntensity(string args) {
string[] blafuckcsharp;
int intensity;
try {
blafuckcsharp = args.Split(" ", 2);
intensity = int.Parse(blafuckcsharp[1]);
this.Logger.Chat($"Command Send intensity {intensity}");
} catch (Exception e) when (e is FormatException or IndexOutOfRangeException) {
this.Logger.Error($"Malformed arguments for send [intensity].", e);
return;
}
if (this.DeviceController == null) {
this.Logger.Error("No device controller available to send intensity.");
return;
}
this.DeviceController.SendVibeToAll(intensity);
}
/************************************
* LISTEN TO EVENTS *
************************************/
private void SpellWasTriggered(object? sender, HookActionEffects_ReceivedEventArgs args) {
if (this.TriggersController == null) {
this.Logger.Warn("SpellWasTriggered: TriggersController not init yet, ignoring spell...");
return;
}
Structures.Spell spell = args.Spell;
if (this.ConfigurationProfile != null && this.ConfigurationProfile.VERBOSE_SPELL) {
this.Logger.Debug($"VERBOSE_SPELL: {spell}");
}
List<Trigger>? triggers = this.TriggersController.CheckTrigger_Spell(spell);
foreach (Trigger trigger in triggers) {
this.DeviceController.SendTrigger(trigger);
}
}
private void ChatWasTriggered(XivChatType chatType, uint senderId, ref SeString _sender, ref SeString _message, ref bool isHandled) {
string fromPlayerName = _sender.ToString();
if (this.TriggersController == null) {
this.Logger.Warn("ChatWasTriggered: TriggersController not init yet, ignoring chat...");
return;
}
if (this.ConfigurationProfile != null && this.ConfigurationProfile.VERBOSE_CHAT) {
string XivChatTypeName = ((XivChatType)chatType).ToString();
this.Logger.Debug($"VERBOSE_CHAT: {fromPlayerName} type={XivChatTypeName}: {_message}");
}
List<Trigger> triggers = this.TriggersController.CheckTrigger_Chat(chatType, fromPlayerName, _message.TextValue);
foreach (Trigger trigger in triggers) {
this.DeviceController.SendTrigger(trigger);
}
}
public bool SetProfile(string profileName) {
bool result = this.Configuration.SetCurrentProfile(profileName);
if (!result) {
this.Logger.Warn($"You are trying to use profile {profileName} which can't be found");
return false;
}
ConfigurationProfile? configProfileToCheck = this.Configuration.GetProfile(profileName);
if (configProfileToCheck != null) {
this.ConfigurationProfile = configProfileToCheck;
this.PluginUi.SetProfile(this.ConfigurationProfile);
this.DeviceController.SetProfile(this.ConfigurationProfile);
this.TriggersController.SetProfile(this.ConfigurationProfile);
}
return true;
}
private void ClientState_LoginEvent(object? send, EventArgs e) {
this.PlayerStats.Update(this.ClientState);
}
private void PlayerCurrentHPChanged(object? send, EventArgs e) {
float currentHP = this.PlayerStats.GetCurrentHP();
float maxHP = this.PlayerStats.GetMaxHP();
if (this.TriggersController == null) {
this.Logger.Warn("PlayerCurrentHPChanged: TriggersController not init yet, ignoring HP change...");
return;
}
float percentageHP = currentHP / maxHP * 100f;
List<Trigger> triggers = TriggersController.CheckTrigger_HPChanged((int)currentHP, (float)percentageHP);
this.Logger.Debug($"Player HPChanged {currentHP}/{maxHP} {percentageHP}%");
// Overwrites the threshold for every motors
foreach (Trigger trigger in triggers) {
this.DeviceController.SendTrigger(trigger);
}
}
}
}