1
0

fix: moving to App wrapper

This commit is contained in:
Kacie 2023-01-24 22:50:56 +01:00
parent 38d7991097
commit 1a0790ffd4
29 changed files with 4184 additions and 303 deletions

View File

@ -1,138 +1,225 @@
root = true
# top-most EditorConfig file
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
# 4 space indentation
indent_style = space
indent_size = 4
# disable redundant style warnings
# Microsoft .NET properties
csharp_indent_braces = false
csharp_new_line_before_catch = true
csharp_new_line_before_else = true
csharp_new_line_before_finally = true
csharp_new_line_before_members_in_object_initializers = false
csharp_new_line_before_open_brace = all
csharp_preferred_modifier_order = public, private, protected, internal, new, abstract, virtual, sealed, override, static, readonly, extern, unsafe, volatile, async:suggestion
csharp_style_var_elsewhere = true:suggestion
csharp_style_var_for_built_in_types = true:suggestion
csharp_style_var_when_type_is_apparent = true:suggestion
dotnet_code_quality_unused_parameters = non_public
dotnet_naming_rule.event_rule.severity = warning
dotnet_naming_rule.event_rule.style = on_upper_camel_case_style
dotnet_naming_rule.event_rule.symbols = event_symbols
dotnet_naming_rule.private_constants_rule.severity = warning
dotnet_naming_rule.private_constants_rule.style = upper_camel_case_style
dotnet_naming_rule.private_constants_rule.symbols = private_constants_symbols
dotnet_naming_rule.private_instance_fields_rule.severity = warning
dotnet_naming_rule.private_instance_fields_rule.style = lower_camel_case_style
dotnet_naming_rule.private_instance_fields_rule.symbols = private_instance_fields_symbols
dotnet_naming_rule.private_static_fields_rule.severity = warning
dotnet_naming_rule.private_static_fields_rule.style = upper_camel_case_style
dotnet_naming_rule.private_static_fields_rule.symbols = private_static_fields_symbols
dotnet_naming_rule.private_static_readonly_rule.severity = warning
dotnet_naming_rule.private_static_readonly_rule.style = upper_camel_case_style
dotnet_naming_rule.private_static_readonly_rule.symbols = private_static_readonly_symbols
dotnet_naming_style.lower_camel_case_style.capitalization = camel_case
dotnet_naming_style.on_upper_camel_case_style.capitalization = pascal_case
dotnet_naming_style.on_upper_camel_case_style.required_prefix = On
dotnet_naming_style.upper_camel_case_style.capitalization = pascal_case
dotnet_naming_symbols.event_symbols.applicable_accessibilities = *
dotnet_naming_symbols.event_symbols.applicable_kinds = event
dotnet_naming_symbols.private_constants_symbols.applicable_accessibilities = private
dotnet_naming_symbols.private_constants_symbols.applicable_kinds = field
dotnet_naming_symbols.private_constants_symbols.required_modifiers = const
dotnet_naming_symbols.private_instance_fields_symbols.applicable_accessibilities = private
dotnet_naming_symbols.private_instance_fields_symbols.applicable_kinds = field
dotnet_naming_symbols.private_static_fields_symbols.applicable_accessibilities = private
dotnet_naming_symbols.private_static_fields_symbols.applicable_kinds = field
dotnet_naming_symbols.private_static_fields_symbols.required_modifiers = static
dotnet_naming_symbols.private_static_readonly_symbols.applicable_accessibilities = private
dotnet_naming_symbols.private_static_readonly_symbols.applicable_kinds = field
dotnet_naming_symbols.private_static_readonly_symbols.required_modifiers = static,readonly
dotnet_style_parentheses_in_arithmetic_binary_operators =always_for_clarity:suggestion
dotnet_style_parentheses_in_other_binary_operators =always_for_clarity:suggestion
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:suggestion
dotnet_style_predefined_type_for_member_access = true:suggestion
dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion
dotnet_style_parentheses_in_other_operators=always_for_clarity:silent
dotnet_style_object_initializer = false
csharp_space_between_method_call_empty_parameter_list_parentheses = false
csharp_space_between_method_call_parameter_list_parentheses = false
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
csharp_space_between_empty_square_brackets = false
csharp_space_before_semicolon_in_for_statement = false
csharp_space_before_open_square_brackets = false
csharp_space_before_comma = false
csharp_space_after_keywords_in_control_flow_statements = true
csharp_space_after_comma = true
csharp_space_after_cast = false
csharp_space_around_binary_operators = before_and_after
csharp_space_between_method_declaration_name_and_open_parenthesis = false
csharp_space_between_method_declaration_parameter_list_parentheses = false
csharp_space_between_parentheses = none
csharp_space_between_square_brackets = false
# ReSharper properties
resharper_align_linq_query = true
resharper_align_multiline_argument = true
resharper_align_multiline_calls_chain = true
resharper_align_multiline_expression = true
resharper_align_multiline_extends_list = true
resharper_align_multiline_for_stmt = true
resharper_align_multline_type_parameter_constrains = true
resharper_align_multline_type_parameter_list = true
resharper_apply_on_completion = true
resharper_auto_property_can_be_made_get_only_global_highlighting = none
resharper_auto_property_can_be_made_get_only_local_highlighting = none
resharper_autodetect_indent_settings = true
resharper_braces_for_ifelse = required_for_multiline
resharper_can_use_global_alias = false
resharper_csharp_align_multiline_parameter = true
resharper_csharp_align_multiple_declaration = true
resharper_csharp_empty_block_style = together_same_line
resharper_csharp_int_align_comments = true
resharper_csharp_new_line_before_while = true
resharper_csharp_wrap_after_declaration_lpar = true
resharper_enforce_line_ending_style = true
resharper_member_can_be_private_global_highlighting = none
resharper_member_can_be_private_local_highlighting = none
resharper_new_line_before_finally = false
resharper_place_accessorholder_attribute_on_same_line = false
resharper_place_field_attribute_on_same_line = false
resharper_show_autodetect_configure_formatting_tip = false
resharper_use_indent_from_vs = false
# ReSharper inspection severities
resharper_arrange_missing_parentheses_highlighting = hint
resharper_arrange_redundant_parentheses_highlighting = hint
resharper_arrange_this_qualifier_highlighting = none
resharper_arrange_type_member_modifiers_highlighting = hint
resharper_arrange_type_modifiers_highlighting = hint
resharper_built_in_type_reference_style_for_member_access_highlighting = hint
resharper_built_in_type_reference_style_highlighting = none
resharper_foreach_can_be_converted_to_query_using_another_get_enumerator_highlighting = none
resharper_foreach_can_be_partly_converted_to_query_using_another_get_enumerator_highlighting = none
resharper_invert_if_highlighting = none
resharper_loop_can_be_converted_to_query_highlighting = none
resharper_method_has_async_overload_highlighting = none
resharper_private_field_can_be_converted_to_local_variable_highlighting = none
resharper_redundant_base_qualifier_highlighting = none
resharper_suggest_var_or_type_built_in_types_highlighting = hint
resharper_suggest_var_or_type_elsewhere_highlighting = hint
resharper_suggest_var_or_type_simple_types_highlighting = hint
resharper_unused_auto_property_accessor_global_highlighting = none
csharp_style_deconstructed_variable_declaration=true:silent
[*.{appxmanifest,asax,ascx,aspx,axaml,axml,build,c,c++,cc,cginc,compute,config,cp,cpp,cs,cshtml,csproj,css,cu,cuh,cxx,dbml,discomap,dtd,h,hh,hlsl,hlsli,hlslinc,hpp,htm,html,hxx,inc,inl,ino,ipp,js,json,jsproj,jsx,lsproj,master,mpp,mq4,mq5,mqh,njsproj,nuspec,paml,proj,props,proto,razor,resjson,resw,resx,skin,StyleCop,targets,tasks,tpp,ts,tsx,usf,ush,vb,vbproj,xaml,xamlx,xml,xoml,xsd}]
indent_style = space
indent_size = 4
tab_width = 4
dotnet_style_parentheses_in_other_operators=always_for_clarity:silent
# Supprimer la ligne ci-dessous si vous voulez hériter les paramètres .editorconfig des répertoires supérieurs
root = true
# Fichiers C#
[*.cs]
#### Options EditorConfig principales ####
# Indentation et espacement
indent_size = 2
indent_style = space
tab_width = 2
# Préférences de nouvelle ligne
end_of_line = crlf
insert_final_newline = false
#### Conventions de codage .NET ####
# Organiser les instructions Using
dotnet_separate_import_directive_groups = false
dotnet_sort_system_directives_first = true
file_header_template = unset
# Préférences de this. et Me.
dotnet_style_qualification_for_event = false
dotnet_style_qualification_for_field = false
dotnet_style_qualification_for_method = false
dotnet_style_qualification_for_property = false
# Préférences des mots clés de langage par rapport aux types BCL
dotnet_style_predefined_type_for_locals_parameters_members = true
dotnet_style_predefined_type_for_member_access = true
# Préférences de parenthèses
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity
dotnet_style_parentheses_in_other_operators = never_if_unnecessary
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity
# Préférences de modificateur
dotnet_style_require_accessibility_modifiers = for_non_interface_members
# Préférences de niveau expression
dotnet_style_coalesce_expression = true
dotnet_style_collection_initializer = true
dotnet_style_explicit_tuple_names = true
dotnet_style_namespace_match_folder = true
dotnet_style_null_propagation = true
dotnet_style_object_initializer = true
dotnet_style_operator_placement_when_wrapping = beginning_of_line
dotnet_style_prefer_auto_properties = true
dotnet_style_prefer_compound_assignment = true
dotnet_style_prefer_conditional_expression_over_assignment = true
dotnet_style_prefer_conditional_expression_over_return = true
dotnet_style_prefer_foreach_explicit_cast_in_source = when_strongly_typed
dotnet_style_prefer_inferred_anonymous_type_member_names = true
dotnet_style_prefer_inferred_tuple_names = true
dotnet_style_prefer_is_null_check_over_reference_equality_method = true
dotnet_style_prefer_simplified_boolean_expressions = true
dotnet_style_prefer_simplified_interpolation = true
# Préférences de champ
dotnet_style_readonly_field = true
# Préférences de paramètre
dotnet_code_quality_unused_parameters = all
# Préférences de suppression
dotnet_remove_unnecessary_suppression_exclusions = none
# Préférences de nouvelle ligne
dotnet_style_allow_multiple_blank_lines_experimental = true
dotnet_style_allow_statement_immediately_after_block_experimental = true
#### Conventions de codage C# ####
# Préférences de var
csharp_style_var_elsewhere = false
csharp_style_var_for_built_in_types = false
csharp_style_var_when_type_is_apparent = false
# Membres expression-bodied
csharp_style_expression_bodied_accessors = true
csharp_style_expression_bodied_constructors = false
csharp_style_expression_bodied_indexers = true
csharp_style_expression_bodied_lambdas = true
csharp_style_expression_bodied_local_functions = false
csharp_style_expression_bodied_methods = false
csharp_style_expression_bodied_operators = false
csharp_style_expression_bodied_properties = true
# Préférences correspondants au modèle
csharp_style_pattern_matching_over_as_with_null_check = true
csharp_style_pattern_matching_over_is_with_cast_check = true
csharp_style_prefer_extended_property_pattern = true
csharp_style_prefer_not_pattern = true
csharp_style_prefer_pattern_matching = true
csharp_style_prefer_switch_expression = true
# Préférences de vérification de valeur Null
csharp_style_conditional_delegate_call = true
# Préférences de modificateur
csharp_prefer_static_local_function = true
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,required,volatile,async
# Préférences de bloc de code
csharp_prefer_braces = true
csharp_prefer_simple_using_statement = true
csharp_style_namespace_declarations = block_scoped
csharp_style_prefer_method_group_conversion = true
csharp_style_prefer_top_level_statements = true
# Préférences de niveau expression
csharp_prefer_simple_default_expression = true
csharp_style_deconstructed_variable_declaration = true
csharp_style_implicit_object_creation_when_type_is_apparent = true
csharp_style_inlined_variable_declaration = true
csharp_style_prefer_index_operator = true
csharp_style_prefer_local_over_anonymous_function = true
csharp_style_prefer_null_check_over_type_check = true
csharp_style_prefer_range_operator = true
csharp_style_prefer_tuple_swap = true
csharp_style_prefer_utf8_string_literals = true
csharp_style_throw_expression = true
csharp_style_unused_value_assignment_preference = discard_variable
csharp_style_unused_value_expression_statement_preference = discard_variable
# Préférences pour la directive 'using'
csharp_using_directive_placement = outside_namespace
# Préférences de nouvelle ligne
csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true
csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true
csharp_style_allow_embedded_statements_on_same_line_experimental = true
#### Règles de formatage C# ####
# Préférences de nouvelle ligne
csharp_new_line_before_catch = false
csharp_new_line_before_else = false
csharp_new_line_before_finally = false
csharp_new_line_before_members_in_anonymous_types = true
csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_open_brace = none
csharp_new_line_between_query_expression_clauses = true
# Préférences de mise en retrait
csharp_indent_block_contents = true
csharp_indent_braces = false
csharp_indent_case_contents = true
csharp_indent_case_contents_when_block = true
csharp_indent_labels = one_less_than_current
csharp_indent_switch_labels = true
# Préférences d'espace
csharp_space_after_cast = false
csharp_space_after_colon_in_inheritance_clause = true
csharp_space_after_comma = true
csharp_space_after_dot = false
csharp_space_after_keywords_in_control_flow_statements = true
csharp_space_after_semicolon_in_for_statement = true
csharp_space_around_binary_operators = before_and_after
csharp_space_around_declaration_statements = false
csharp_space_before_colon_in_inheritance_clause = true
csharp_space_before_comma = false
csharp_space_before_dot = false
csharp_space_before_open_square_brackets = false
csharp_space_before_semicolon_in_for_statement = false
csharp_space_between_empty_square_brackets = false
csharp_space_between_method_call_empty_parameter_list_parentheses = false
csharp_space_between_method_call_name_and_opening_parenthesis = false
csharp_space_between_method_call_parameter_list_parentheses = false
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
csharp_space_between_method_declaration_name_and_open_parenthesis = false
csharp_space_between_method_declaration_parameter_list_parentheses = false
csharp_space_between_parentheses = false
csharp_space_between_square_brackets = false
# Préférences d'enveloppement
csharp_preserve_single_line_blocks = true
csharp_preserve_single_line_statements = true
#### Styles de nommage ####
# Règles de nommage
dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.types_should_be_pascal_case.symbols = types
dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
# Spécifications de symboles
dotnet_naming_symbols.interface.applicable_kinds = interface
dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
dotnet_naming_symbols.interface.required_modifiers =
dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
dotnet_naming_symbols.types.required_modifiers =
dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
dotnet_naming_symbols.non_field_members.required_modifiers =
# Styles de nommage
dotnet_naming_style.pascal_case.required_prefix =
dotnet_naming_style.pascal_case.required_suffix =
dotnet_naming_style.pascal_case.word_separator =
dotnet_naming_style.pascal_case.capitalization = pascal_case
dotnet_naming_style.begins_with_i.required_prefix = I
dotnet_naming_style.begins_with_i.required_suffix =
dotnet_naming_style.begins_with_i.word_separator =
dotnet_naming_style.begins_with_i.capitalization = pascal_case

View File

@ -0,0 +1,339 @@
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;
// 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 {
internal 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 bool wasInit = false;
public readonly string CommandName = "";
private readonly string ShortName = "";
private bool _firstUpdated = false;
private readonly PlayerStats PlayerStats;
private PluginUI PluginUi { get; init; }
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(string commandName, string shortName, GameNetwork gameNetwork, ClientState clientState, DataManager dataManager, Dalamud.Game.Gui.ChatGui? dalamudChat, Configuration configuration, SigScanner scanner, ObjectTable gameObjects, DalamudPluginInterface pluginInterface) {
return;
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);
// 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
/* TODO: this.DeviceController = new Device.DevicesController(this.Logger, this.Configuration, this.ConfigurationProfile, this.Patterns);*/
this.DeviceController = null;
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() {
if (this.PluginUi != null) {
this.PluginUi.Display();
}
}
private void DisplayConfigUI() {
this.PluginUi.Display();
}
public void DrawUI() {
if(this.PluginUi == null) {
return;
}
this.PluginUi.Draw();
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) {
if (this.TriggersController == null) {
this.Logger.Warn("ChatWasTriggered: TriggersController not init yet, ignoring chat...");
return;
}
string fromPlayerName = _sender.ToString();
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);
}
}
}
}

View File

@ -0,0 +1,50 @@
using System;
using System.Text.RegularExpressions;
namespace FFXIV_Vibe_Plugin.Commons {
internal class Helpers {
/** Get number of milliseconds (unix timestamp) */
public static int GetUnix() {
return (int)DateTimeOffset.Now.ToUnixTimeMilliseconds();
}
public static int ClampInt(int value, int min, int max) {
if(value < min) { return min; } else if( value > max) { return max; }
return value;
}
public static float ClampFloat(float value, float min, float max) {
if(value < min) { return min; } else if(value > max) { return max; }
return value;
}
public static int ClampIntensity(int intensity, int threshold) {
intensity = ClampInt(intensity, 0, 100);
return (int)(intensity / (100.0f / threshold));
}
/** Check if a regexp matches the given text */
public static bool RegExpMatch(Logger Logger, string text, string regexp) {
bool found = false;
if(regexp.Trim() == "") {
found = true;
} else {
string patternCheck = String.Concat(@"", regexp);
try {
System.Text.RegularExpressions.Match m = Regex.Match(text, patternCheck, RegexOptions.IgnoreCase);
if(m.Success) {
found = true;
}
} catch(Exception) {
Logger.Error($"Probably a wrong REGEXP for {regexp}");
}
}
return found;
}
}
}

View File

@ -0,0 +1,132 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Dalamud.Plugin;
using Dalamud.IoC;
namespace FFXIV_Vibe_Plugin.Commons {
internal class Logger {
// Initialize the Dalamud.Gui system.
private readonly Dalamud.Game.Gui.ChatGui? DalamudChatGui;
// Logger name.
private readonly string name = "";
// Current log level.
private readonly LogLevel log_level = LogLevel.DEBUG;
// The prefix symbol of the log message.
private readonly string prefix = ">";
// Available log levels.
public enum LogLevel {
VERBOSE, DEBUG, LOG, INFO, WARN, ERROR, FATAL,
}
/** Constructor */
public Logger(Dalamud.Game.Gui.ChatGui? DalamudChatGui, string name, LogLevel log_level) {
this.DalamudChatGui = DalamudChatGui;
this.name = name;
this.log_level = log_level;
}
/** Printing in the chat gui a message. */
public void Chat(string msg) {
if(DalamudChatGui != null) {
string m = this.FormatMessage(LogLevel.LOG, msg);
DalamudChatGui.Print(m);
} else {
Dalamud.Logging.PluginLog.LogError("No gui chat");
}
}
/** Printing in the chat gui an error message. */
public void ChatError(string msg) {
string m = this.FormatMessage(LogLevel.ERROR, msg);
DalamudChatGui?.PrintError(m);
this.Error(msg);
}
/** Printing in the chat gui an error message with an exception. */
public void ChatError(string msg, Exception e) {
string m = this.FormatMessage(LogLevel.ERROR, msg, e);
DalamudChatGui?.PrintError(m);
this.Error(m);
}
/** Log message as 'debug' to logs. */
public void Verbose(string msg) {
if(this.log_level > LogLevel.VERBOSE) { return; }
string m = this.FormatMessage(LogLevel.VERBOSE, msg);
Dalamud.Logging.PluginLog.LogVerbose(m);
}
/** Log message as 'debug' to logs. */
public void Debug(string msg) {
if(this.log_level > LogLevel.DEBUG) { return; }
string m = this.FormatMessage(LogLevel.DEBUG, msg);
Dalamud.Logging.PluginLog.LogDebug(m);
}
/** Log message as 'log' to logs. */
public void Log(string msg) {
if(this.log_level > LogLevel.LOG) { return; }
string m = this.FormatMessage(LogLevel.LOG, msg);
Dalamud.Logging.PluginLog.Log(m);
}
/** Log message as 'info' to logs. */
public void Info(string msg) {
if(this.log_level > LogLevel.INFO) { return; }
string m = this.FormatMessage(LogLevel.INFO, msg);
Dalamud.Logging.PluginLog.Information(m);
}
/** Log message as 'warning' to logs. */
public void Warn(string msg) {
if(this.log_level > LogLevel.WARN) { return; }
string m = this.FormatMessage(LogLevel.WARN, msg);
Dalamud.Logging.PluginLog.Warning(m);
}
/** Log message as 'error' to logs. */
public void Error(string msg) {
if(this.log_level > LogLevel.ERROR) { return; }
string m = this.FormatMessage(LogLevel.ERROR, msg);
Dalamud.Logging.PluginLog.Error(m);
}
/** Log message as 'error' to logs with an exception. */
public void Error(string msg, Exception e) {
if(this.log_level > LogLevel.ERROR) { return; }
string m = this.FormatMessage(LogLevel.ERROR, msg, e);
Dalamud.Logging.PluginLog.Error(m);
}
/** Log message as 'fatal' to logs. */
public void Fatal(string msg) {
if(this.log_level > LogLevel.FATAL) { return; }
string m = this.FormatMessage(LogLevel.FATAL, msg);
Dalamud.Logging.PluginLog.Fatal(m);
}
/** Log message as 'fatal' to logs with an exception. */
public void Fatal(string msg, Exception e) {
if(this.log_level > LogLevel.FATAL) { return; }
string m = this.FormatMessage(LogLevel.FATAL, msg, e);
Dalamud.Logging.PluginLog.Fatal(m);
}
private string FormatMessage(LogLevel type, string msg) {
return $"{(name != "" ? name + " " : "")}{type} {this.prefix} {msg}";
}
private string FormatMessage(LogLevel type, string msg, Exception e) {
return $"{(name != "" ? name+" " : "")}{type} {this.prefix} {e.Message}\\n{msg}";
}
}
}

View File

@ -0,0 +1,251 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FFXIV_Vibe_Plugin {
internal class OpCodes {
////////////////////////////////////////////////////////////////////////////////
/// Lobby Connection IPC Codes
/**
* Server IPC Lobby Type Codes.
*/
public enum ServerLobbyIpcType : ushort {
LobbyError = 0x0002,
LobbyServiceAccountList = 0x000C,
LobbyCharList = 0x000D,
LobbyCharCreate = 0x000E,
LobbyEnterWorld = 0x000F,
LobbyServerList = 0x0015,
LobbyRetainerList = 0x0017,
};
/**
* Client IPC Lobby Type Codes.
*/
public enum ClientLobbyIpcType : ushort {
ReqCharList = 0x0003,
ReqEnterWorld = 0x0004,
ClientVersionInfo = 0x0005,
ReqCharDelete = 0x000A,
ReqCharCreate = 0x000B,
};
////////////////////////////////////////////////////////////////////////////////
/// Zone Connection IPC Codes
/**
* Server IPC Zone Type Codes.
*/
public enum ServerZoneIpcType : ushort {
PlayerSetup = 0x008B, // updated 6.0
UpdateHpMpTp = 0x0296,// updated 6.0
PlayerStats = 0x038D,// updated 6.0
ActorControl = 0x017E,// updated 6.0
ActorControlSelf = 0x02E6,// updated 6.0
ActorControlTarget = 0x0168,// updated 6.0
Playtime = 0x03C3,// updated 6.0
Examine = 0x011B,// updated 6.0
MarketBoardSearchResult = 0x0201,// updated 6.0
MarketBoardItemListingCount = 0x023C,// updated 6.0
MarketBoardItemListingHistory = 0x0192,// updated 6.0
MarketBoardItemListing = 0x0323,// updated 6.0
MarketBoardPurchase = 0x009D,// updated 6.0
ActorMove = 0x0235,// updated 6.0
ResultDialog = 0x00AF,// updated 6.0
RetainerInformation = 0x0129,// updated 6.0
NpcSpawn = 0x032E,// updated 6.0
ItemMarketBoardInfo = 0x008A,// updated 6.0
PlayerSpawn = 0x0133,// updated 6.0
ContainerInfo = 0x00EE,// updated 6.0
ItemInfo = 0x0173,// updated 6.0
UpdateClassInfo = 0x03A5,// updated 6.0
ActorCast = 0x0108,// updated 6.0
CurrencyCrystalInfo = 0x0258,// updated 6.0
InitZone = 0x02C4,// updated 6.0
EffectResult = 0x0196,// updated 6.0
EventStart = 0x0334,// updated 6.0
EventFinish = 0x01B8,// updated 6.0
SomeDirectorUnk4 = 0x0164,// updated 6.0
UpdateInventorySlot = 0x02B6,// updated 6.0
DesynthResult = 0x02D5,// updated 6.0
InventoryActionAck = 0x00FC,// updated 6.0
InventoryTransaction = 0x008F,// updated 6.0
InventoryTransactionFinish = 0x039B,// updated 6.0
CFNotify = 0x0317,// updated 6.0
PrepareZoning = 0x0090,// updated 6.0
ActorSetPos = 0x0199,// updated 6.0
PlaceFieldMarker = 0x037D,// updated 6.0
PlaceFieldMarkerPreset = 0x01CF,// updated 6.0
ObjectSpawn = 0x0319,// updated 6.0
Effect = 0x035A,// updated 6.0
StatusEffectList = 0x02C5,// updated 6.0
ActorGauge = 0x0283,// updated 6.0
FreeCompanyInfo = 0x031C,// updated 6.0
FreeCompanyDialog = 0x036E,// updated 6.0
AirshipTimers = 0x00ED,// updated 6.0
SubmarineTimers = 0x00F5,// updated 6.0
AirshipStatusList = 0x023F,// updated 6.0
AirshipStatus = 0x01E3,// updated 6.0
AirshipExplorationResult = 0x00B4,// updated 6.0
SubmarineProgressionStatus = 0x030B,// updated 6.0
SubmarineStatusList = 0x02F4,// updated 6.0
SubmarineExplorationResult = 0x0183,// updated 6.0
EventPlay = 0x00A5, // Updated 6.0
EventPlay4 = 0x022E, // Updated 6.0
EventPlay8 = 0x18B, // Updated 6.0
EventPlay16 = 0x1F4, // Updated 6.0
EventPlay32 = 0x65, // Updated 6.0
EventPlay64 = 0x3A8, // Updated 6.0
EventPlay128 = 0x16E, // Updated 6.0
EventPlay255 = 0x366, // Updated 6.0
WeatherChange = 0x01FD, // Updated 6.0
Logout = 0x02EC, // updated 6.0 hotfix
//HousingWardInfo = 0x012A, // updated 5.58 hotfix
};
/**
* Client IPC Zone Type Codes.
*/
public enum ClientZoneIpcType : ushort {
UpdatePositionHandler = 0x0346,// updated 6.0
ClientTrigger = 0x03AC,// updated 6.0
ChatHandler = 0x01CC,// updated 6.0
SetSearchInfoHandler = 0x03B1,// updated 6.0
MarketBoardPurchaseHandler = 0x00DC,// updated 6.0
InventoryModifyHandler = 0x00A3,// updated 6.0 (Base offset: 0x00AA)
UpdatePositionInstance = 0x0163,// updated 6.0
//PingHandler = 0x02CD, // updated 5.58 hotfix
//InitHandler = 0x01AA, // updated 5.58 hotfix
//FinishLoadingHandler = 0x02DA, // updated 5.58 hotfix
//CFCommenceHandler = 0x0092, // updated 5.58 hotfix
//CFRegisterDuty = 0x03C7, // updated 5.58 hotfix
//CFRegisterRoulette = 0x00C2, // updated 5.58 hotfix
//PlayTimeHandler = 0x00B0, // updated 5.58 hotfix
//LogoutHandler = 0x0178, // updated 5.58 hotfix
//CancelLogout = 0x01F9, // updated 5.58 hotfix
//CFDutyInfoHandler = 0x0092, // updated 5.58 hotfix
//SocialReqSendHandler = 0x023A, // updated 5.58 hotfix
//CreateCrossWorldLS = 0x0336, // updated 5.58 hotfix
//SocialListHandler = 0x0187, // updated 5.58 hotfix
//ReqSearchInfoHandler = 0x022C, // updated 5.58 hotfix
//ReqExamineSearchCommentHandler = 0x0315, // updated 5.58 hotfix
//ReqRemovePlayerFromBlacklist = 0x0145, // updated 5.58 hotfix
//BlackListHandler = 0x0161, // updated 5.58 hotfix
//PlayerSearchHandler = 0x02FF, // updated 5.58 hotfix
//LinkshellListHandler = 0x023B, // updated 5.58 hotfix
//MarketBoardRequestItemListingInfo = 0x0189, // updated 5.58 hotfix
//MarketBoardRequestItemListings = 0x0092, // updated 5.58 hotfix
//MarketBoardSearch = 0x02F9, // updated 5.58 hotfix
//ReqExamineFcInfo = 0x0136, // updated 5.58 hotfix
//FcInfoReqHandler = 0x0234, // updated 5.58 hotfix
//FreeCompanyUpdateShortMessageHandler = 0x0123, // added 5.0
//ReqMarketWishList = 0x0306, // updated 5.58 hotfix
//ReqJoinNoviceNetwork = 0x01D5, // updated 5.58 hotfix
//ReqCountdownInitiate = 0x00C2, // updated 5.58 hotfix
//ReqCountdownCancel = 0x00E6, // updated 5.58 hotfix
//ZoneLineHandler = 0x03CC, // updated 5.58 hotfix
//DiscoveryHandler = 0x023A, // updated 5.58 hotfix
//PlaceFieldMarker = 0x02AF, // updated 5.58 hotfix
//PlaceFieldMarkerPreset = 0x018E, // updated 5.58 hotfix
//SkillHandler = 0x0244, // updated 5.58 hotfix
//GMCommand1 = 0x018A, // updated 5.58 hotfix
//GMCommand2 = 0x02FD, // updated 5.58 hotfix
//AoESkillHandler = 0x01F1, // updated 5.58 hotfix
//InventoryEquipRecommendedItems = 0x0109, // updated 5.58 hotfix
//ReqPlaceHousingItem = 0x0352, // updated 5.58 hotfix
//BuildPresetHandler = 0x024E, // updated 5.58 hotfix
//TalkEventHandler = 0x0305, // updated 5.58 hotfix
//EmoteEventHandler = 0x03A7, // updated 5.58 hotfix
//WithinRangeEventHandler = 0x02EE, // updated 5.58 hotfix
//OutOfRangeEventHandler = 0x00EE, // updated 5.58 hotfix
//EnterTeriEventHandler = 0x0389, // updated 5.58 hotfix
//ReturnEventHandler = 0x03B4, // updated 5.58 hotfix
//TradeReturnEventHandler = 0x0216, // updated 5.58 hotfix
//LinkshellEventHandler = 0x0239, // updated 5.58 hotfix
//LinkshellEventHandler1 = 0x0239, // updated 5.58 hotfix
//ReqEquipDisplayFlagsChange = 0x01F6, // updated 5.58 hotfix
//LandRenameHandler = 0x018C, // updated 5.58 hotfix
//HousingUpdateHouseGreeting = 0x02F4, // updated 5.58 hotfix
//HousingUpdateObjectPosition = 0x02CB, // updated 5.58 hotfix
//SetSharedEstateSettings = 0x0179, // updated 5.58 hotfix
//PerformNoteHandler = 0x016E, // updated 5.58 hotfix
};
////////////////////////////////////////////////////////////////////////////////
/// Chat Connection IPC Codes
/**
* Server IPC Chat Type Codes.
*/
public enum ServerChatIpcType : ushort {
//Tell = 0x0064, // updated for sb
//TellErrNotFound = 0x0066,
//FreeCompanyEvent = 0x012C, // added 5.0
};
/**
* Client IPC Chat Type Codes.
*/
public enum ClientChatIpcType : ushort {
//TellReq = 0x0064,
};
public static string? GetName(ushort opCode) {
string? name = "?Unknow?";
if(Enum.IsDefined(typeof(OpCodes.ServerLobbyIpcType), opCode)) {
name = "ServerLobbyIpcType-" + Enum.GetName(typeof(OpCodes.ServerLobbyIpcType), opCode);
}
if(Enum.IsDefined(typeof(OpCodes.ClientLobbyIpcType), opCode)) {
name = "ClientLobbyIpcType-" + Enum.GetName(typeof(OpCodes.ClientLobbyIpcType), opCode);
}
if(Enum.IsDefined(typeof(OpCodes.ServerZoneIpcType), opCode)) {
name = "ServerZoneIpcType-" + Enum.GetName(typeof(OpCodes.ServerZoneIpcType), opCode);
}
if(Enum.IsDefined(typeof(OpCodes.ClientZoneIpcType), opCode)) {
name = "ClientZoneIpcType-" + Enum.GetName(typeof(OpCodes.ClientZoneIpcType), opCode);
}
if(Enum.IsDefined(typeof(OpCodes.ServerChatIpcType), opCode)) {
name = "ServerChatIpcType-" + Enum.GetName(typeof(OpCodes.ServerChatIpcType), opCode);
}
if(Enum.IsDefined(typeof(OpCodes.ClientChatIpcType), opCode)) {
name = "ClientChatIpcType-"+Enum.GetName(typeof(OpCodes.ClientChatIpcType), opCode);
}
return name;
}
}
}

View File

@ -0,0 +1,100 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FFXIV_Vibe_Plugin {
public class Patterns {
private readonly List<Pattern> BuiltinPatterns = new();
private List<Pattern> CustomPatterns = new();
/**
* Pattern is: [intensity]:[duration in ms]
*/
public Patterns() {
this.AddBuiltinPattern(new Pattern("intensity", "100:0")); // Don't change this one.
this.AddBuiltinPattern(new Pattern("ramp", "10:150|20:150|30:150|40:150|50:150|60:150|70:150|80:150|90:150|100:250|0:0"));
this.AddBuiltinPattern(new Pattern("bump", "10:150|20:150|30:150|40:150|50:150|60:150|70:150|80:150|90:150|100:250|50:250|100:500|0:0"));
this.AddBuiltinPattern(new Pattern("square", "100:800|50:800|0:200|100:1000|0:0"));
this.AddBuiltinPattern(new Pattern("shake", "100:500|20:200|100:500|80:500|100:200|90:100|100:200|90:200|100:800|0:0"));
this.AddBuiltinPattern(new Pattern("sos", "100:500|50:200|100:500|50:200|100:500|50:200|100:1000|30:200|100:1000|30:200|100:1000|30:200|100:500|50:200|100:500|50:200|100:500|0:0"));
this.AddBuiltinPattern(new Pattern("xenoWave", "10:650|15:500|20:400|30:400|45:350|60:300|75:300|95:250|100:200|90:250|75:300|60:300|45:350|30:400|20:400|15:500|10:650|5:750|0:0"));
this.AddBuiltinPattern(new Pattern("slowVibe", "10:1000|20:1000|10:1000|50:1000|0:0"));
this.AddBuiltinPattern(new Pattern("Vel: Poke Release 25s", "100:3000|50:500|60:500|70:500|80:500|90:500|100:3000|50:500|60:500|70:500|80:500|90:500|100:3000|50:500|60:500|70:500|80:500|90:500|100:3000|50:500|60:500|70:500|80:500|90:500|100:3000|0:0"));
this.AddBuiltinPattern(new Pattern("Vel: Stop to gentle 14.6s", "40:200|50:200|60:200|70:200|80:200|90:200|100:3000|90:600|80:800|70:1000|60:1200|50:1400|40:1600|30:1800|25:2000|0:0"));
this.AddBuiltinPattern(new Pattern("Vel: Teleport 7s", "20:500|30:500|40:500|50:500|60:500|70:500|80:500|90:500|100:1000|90:200|80:200|70:200|60:200|50:200|40:200|30:200|20:200|10:200|5:200|0:0"));
this.AddBuiltinPattern(new Pattern("Vel: Paralysis 7s", "100:200|0:200|100:200|0:200|100:200|0:500|100:200|0:200|100:200|0:200|100:200|0:500|100:200|0:200|100:200|0:200|100:200|0:500|200:100|200:0|200:100|200:0|200:100|500:0|200:100|200:0|200:100|200:0|200:100|0:0"));
this.AddBuiltinPattern(new Pattern("Vel: Paralysis (longer) 11.3s", "50:200|0:200|100:500|0:200|40:200|0:700|20:200|0:500|100:200|0:200|60:200|0:400|80:200|0:300|90:200|0:200|35:200|0:500|55:200|0:200|40:200|0:700|20:200|0:200|100:900|0:200|60:200|0:200|30:200|0:300|70:200|0:200|100:500|0:200|50:200|0:200|100:400|0:200|100:200|0:0"));
this.AddBuiltinPattern(new Pattern("Vel: Simple vibe 12s", "50:2000|100:2000|0:200|100:200|0:200|100:200|0:200|100:200|0:200|100:200|0:200|100:200|0:200|100:200|0:200|100:200|0:200|100:200|0:200|100:200|0:200|100:200|0:200|100:200|0:200|100:200|0:200|100:200|0:200|100:200|0:200|100:200|0:200|100:200|0:200|100:200|0:200|100:200|0:200|100:200|0:200|100:200|0:0"));
this.AddBuiltinPattern(new Pattern("Vel: Impact 1.25s", "100:500|90:100|80:100|70:100|60:100|50:100|40:100|30:100|20:100|10:100|0:0"));
this.AddBuiltinPattern(new Pattern("Vel: Skyshard 5.65s", "100:100|20:100|40:100|60:100|20:2500|40:150|20:150|80:150|100:2000|80:150|40:150|0:0"));
this.AddBuiltinPattern(new Pattern("Vel: Sprint 20s", "100:400|50:400|100:400|50:400|100:400|50:400|100:400|50:400|100:400|50:400|100:400|50:400|100:400|50:400|100:400|50:400|100:400|50:400|100:400|50:400|100:400|50:400|100:400|50:400|100:400|50:400|100:400|50:400|100:400|50:400|100:400|50:400|100:400|50:400|100:400|50:400|100:400|50:400|400:100|400:50|400:100|400:50|400:100|400:50|400:100|400:50|400:100|400:50|400:100|400:50"));
this.AddBuiltinPattern(new Pattern("Vel: Heartbeat (fast) 8.3s", "50:200|0:200|70:200|0:1000|50:200|0:200|70:200|0:1000|50:200|0:200|70:200|0:1000|50:200|0:200|70:200|0:1000|0:0"));
this.AddBuiltinPattern(new Pattern("FF Victory Jingle 4.95sec", "20:150|0:150|70:150|0:150|0:500|60:150|0:150|40:150|0:150|0:500|30:150|0:150|80:150|0:150|0:500|100:150|0:150|20:150|0:150|0:500|30:150|0:150|40:150|0:150|0:500|90:150|0:150|80:150|0:150|0:500|20:150|0:150|10:150|0:150|0:500|90:150|0:150|80:150|0:150|0:0"));
}
public List<Pattern> GetAllPatterns() {
return this.BuiltinPatterns.Concat(this.CustomPatterns).ToList();
}
public List<Pattern> GetBuiltinPatterns() {
return this.BuiltinPatterns;
}
/** Returns a copy of the list to avoid error if any modification happens */
public List<Pattern> GetCustomPatterns() {
List<Pattern> newList = new();
foreach(Pattern pattern in this.CustomPatterns) {
newList.Add(pattern);
}
return newList;
}
public void SetCustomPatterns(List<Pattern> customPatterns) {
this.CustomPatterns = customPatterns;
}
public Pattern GetPatternById(int index) {
return this.GetAllPatterns()[index];
}
public void AddBuiltinPattern(Pattern pattern) {
BuiltinPatterns.Add(pattern);
}
public void AddCustomPattern(Pattern pattern) {
Pattern? foundPattern = CustomPatterns.FirstOrDefault<Pattern>(p => p.Name == pattern.Name );
if(foundPattern != null) {
foundPattern.Name = pattern.Name;
foundPattern.Value = pattern.Value;
} else {
CustomPatterns.Add(pattern);
}
}
public bool RemoveCustomPattern(Pattern pattern) {
int index = CustomPatterns.IndexOf(pattern);
if(index > -1) {
this.CustomPatterns.RemoveAt(index);
return true;
}
return false;
}
}
public class Pattern {
public int Index = -1;
public string Name = "pattern";
public string Value = "10:1000";
public Pattern(string name="pattern", string value="10:1000") {
this.Name = name;
this.Value = value;
}
}
}

View File

@ -0,0 +1,130 @@
using System;
using System.Collections.Generic;
namespace FFXIV_Vibe_Plugin.Commons {
internal class Structures {
public enum ActionEffectType : byte {
Any = 0,
Miss = 1,
FullResist = 2,
Damage = 3,
Heal = 4,
BlockedDamage = 5,
ParriedDamage = 6,
Invulnerable = 7,
NoEffectText = 8,
Unknown_0 = 9,
MpLoss = 10,
MpGain = 11,
TpLoss = 12,
TpGain = 13,
GpGain = 14,
ApplyStatusEffectTarget = 15,
ApplyStatusEffectSource = 16,
StatusNoEffect = 20,
Taunt = 24,
StartActionCombo = 27,
ComboSucceed = 28,
Knockback = 33,
Mount = 40,
MountJapaneseVersion = 240,
VFX = 59,
Transport = 60,
};
// Unused, should be usefull for HookActionEffects but don't know where this field is.
public enum DamageType {
Unknown = 0,
Slashing = 1,
Piercing = 2,
Blunt = 3,
Magic = 5,
Darkness = 6,
Physical = 7,
LimitBreak = 8,
}
/**
* Still testing: https://github.com/SapphireServer/Sapphire/blob/master/src/common/Network/PacketDef/Zone/ClientZoneDef.h#L73
*/
public struct EffectEntry
{
public ActionEffectType type = ActionEffectType.Any;
public byte param0 = 0;
public byte param1 = 0;
public byte param2 = 0;
public byte mult = 0;
public byte flags = 0;
public ushort value = 0;
public EffectEntry(ActionEffectType type, byte param0, byte param1, byte param2, byte mult, byte flags, ushort value) {
this.type = type;
this.param0 = param0;
this.param1 = param1;
this.param2 = param2;
this.mult = mult;
this.flags = flags;
this.value = value;
}
public override string ToString() {
return $"type: {this.type}, p0: {param0}, p1: {param1}, p2: {param2}, mult: {mult}, flags: {flags} | {Convert.ToString(flags, 2)}, value: {value}";
}
}
public struct Player {
public int Id;
public string Name;
public string? Info;
public Player(int id, string name, string? info=null) {
this.Id = id;
this.Name = name;
this.Info = info;
}
public override string ToString() {
if(this.Info != null) {
return $"{Name}({Id}) [info:{this.Info}]";
}
return $"{Name}({Id})";
}
}
public struct Spell {
public int Id;
public string Name = "Undefined_Spell_Name";
public Player Player;
public int[]? Amounts;
public float AmountAverage;
public List<Player>? Targets;
public DamageType DamageType = 0;
public ActionEffectType ActionEffectType = 0;
public Spell(int id, string name, Player player, int[]? amounts, float amountAverage, List<Player>? targets, DamageType damageType, ActionEffectType actionEffectType) {
Id = id;
Name = name;
Player = player;
Amounts = amounts;
AmountAverage = amountAverage;
Targets = targets;
DamageType = damageType;
ActionEffectType = actionEffectType;
}
public override string ToString() {
string targetsString = "";
if(Targets != null) {
if(Targets.Count > 0) {
targetsString = String.Join(",", this.Targets);
} else {
targetsString = "*no target*";
}
}
return $"{Player} casts {Name}#{ActionEffectType} on: {targetsString}. Avg: {AmountAverage}";
}
}
}
}

View File

@ -0,0 +1,131 @@
using Dalamud.Configuration;
using Dalamud.Plugin;
using System;
using System.Collections.Generic;
using FFXIV_Vibe_Plugin.Triggers;
namespace FFXIV_Vibe_Plugin {
[Serializable]
public class Configuration : IPluginConfiguration {
public int Version { get; set; } = 0;
public string CurrentProfileName = "Default";
public List<ConfigurationProfile> Profiles = new();
/**
* TODO: 2022.01.12
* LEGACY from version 2.0.0. Changed to presets in 2.1.0.
* This was moved to presets. It should be remove one day */
public bool VERBOSE_SPELL = false;
public bool VERBOSE_CHAT = false;
public bool VIBE_HP_TOGGLE { get; set; } = false;
public int VIBE_HP_MODE { get; set; } = 0;
public int MAX_VIBE_THRESHOLD { get; set; } = 100;
public bool AUTO_CONNECT { get; set; } = true;
public bool AUTO_OPEN { get; set; } = false;
public List<Pattern> PatternList = new();
public string BUTTPLUG_SERVER_HOST { get; set; } = "127.0.0.1";
public int BUTTPLUG_SERVER_PORT { get; set; } = 12345;
public List<Triggers.Trigger> TRIGGERS { get; set; } = new();
public Dictionary<string, FFXIV_Vibe_Plugin.Device.Device> VISITED_DEVICES = new();
// the below exist just to make saving less cumbersome
[NonSerialized]
private DalamudPluginInterface? pluginInterface;
public void Initialize(DalamudPluginInterface pluginInterface) {
this.pluginInterface = pluginInterface;
}
public void Save() {
this.pluginInterface!.SavePluginConfig(this);
}
/**
* Get the profile specified by name.
*/
public ConfigurationProfile? GetProfile(String name="") {
if(name == "") {
name = this.CurrentProfileName;
}
ConfigurationProfile? profile = this.Profiles.Find(i => i.Name == name);
return profile;
}
public ConfigurationProfile GetDefaultProfile() {
String defaultProfileName = "Default profile";
ConfigurationProfile? profileToCheck = this.GetProfile(this.CurrentProfileName);
if(profileToCheck == null) {
profileToCheck = this.GetProfile(defaultProfileName);
}
ConfigurationProfile profileToReturn = profileToCheck ?? (new());
if(profileToCheck == null) {
profileToReturn.Name = defaultProfileName;
this.Profiles.Add(profileToReturn);
this.CurrentProfileName = defaultProfileName;
this.Save();
}
return profileToReturn;
}
public ConfigurationProfile? GetFirstProfile() {
ConfigurationProfile? profile = null;
if(profile == null && this.Profiles.Count > 0) {
profile = this.Profiles[0];
}
return profile;
}
public void RemoveProfile(String name) {
ConfigurationProfile? profile = this.GetProfile(name);
if(profile != null) {
this.Profiles.Remove(profile);
}
}
public bool AddProfile(String name) {
ConfigurationProfile? profile = GetProfile(name);
if(profile == null) {
profile = new();
profile.Name = name;
this.Profiles.Add(profile);
return true;
}
return false;
}
public bool SetCurrentProfile(String name) {
ConfigurationProfile? profile = this.GetProfile(name);
if(profile != null) {
this.CurrentProfileName = profile.Name;
return true;
}
return false;
}
}
public class ConfigurationProfile{
public string Name = "Default";
public bool VERBOSE_SPELL = false;
public bool VERBOSE_CHAT = false;
public bool VIBE_HP_TOGGLE { get; set; } = false;
public int VIBE_HP_MODE { get; set; } = 0;
public int MAX_VIBE_THRESHOLD { get; set; } = 100;
public bool AUTO_CONNECT { get; set; } = true;
public bool AUTO_OPEN { get; set; } = false;
public List<Pattern> PatternList = new();
public string BUTTPLUG_SERVER_HOST { get; set; } = "127.0.0.1";
public int BUTTPLUG_SERVER_PORT { get; set; } = 12345;
public List<Triggers.Trigger> TRIGGERS { get; set; } = new();
public Dictionary<string, FFXIV_Vibe_Plugin.Device.Device> VISITED_DEVICES = new();
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

View File

@ -0,0 +1,193 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using FFXIV_Vibe_Plugin.Commons;
using Buttplug;
namespace FFXIV_Vibe_Plugin.Device {
public enum UsableCommand {