From 92e9893a35da6d253323862416d4dba082956c05 Mon Sep 17 00:00:00 2001 From: Jade Macho Date: Fri, 26 May 2023 15:26:16 +0200 Subject: [PATCH] Init --- .gitignore | 4 + PatMe2Mqtt.sln | 36 +++ PatMe2Mqtt/Cmd.cs | 52 ++++ PatMe2Mqtt/FastReflectionHelper.cs | 135 +++++++++ PatMe2Mqtt/PatMe2Mqtt.csproj | 59 ++++ PatMe2Mqtt/PatMe2Mqtt.json | 11 + PatMe2Mqtt/PatMeProxyApi/EmoteCounter.cs | 19 ++ PatMe2Mqtt/PatMeProxyApi/EmoteCountersList.cs | 21 ++ PatMe2Mqtt/PatMeProxyApi/IPatMeProxy.cs | 9 + PatMe2Mqtt/PatMeProxyApi/PatMe.cs | 264 ++++++++++++++++++ PatMe2Mqtt/Plugin.cs | 128 +++++++++ PatMe2Mqtt/Service.cs | 106 +++++++ PatMe2Mqtt/SyncCmd.cs | 14 + PatMe2Mqtt/images/icon.png | Bin 0 -> 31764 bytes PatMe2Mqtt/packages.lock.json | 13 + README.md | 5 + preview.png | Bin 0 -> 37826 bytes release.bat | 10 + 18 files changed, 886 insertions(+) create mode 100644 .gitignore create mode 100644 PatMe2Mqtt.sln create mode 100644 PatMe2Mqtt/Cmd.cs create mode 100644 PatMe2Mqtt/FastReflectionHelper.cs create mode 100644 PatMe2Mqtt/PatMe2Mqtt.csproj create mode 100644 PatMe2Mqtt/PatMe2Mqtt.json create mode 100644 PatMe2Mqtt/PatMeProxyApi/EmoteCounter.cs create mode 100644 PatMe2Mqtt/PatMeProxyApi/EmoteCountersList.cs create mode 100644 PatMe2Mqtt/PatMeProxyApi/IPatMeProxy.cs create mode 100644 PatMe2Mqtt/PatMeProxyApi/PatMe.cs create mode 100644 PatMe2Mqtt/Plugin.cs create mode 100644 PatMe2Mqtt/Service.cs create mode 100644 PatMe2Mqtt/SyncCmd.cs create mode 100644 PatMe2Mqtt/images/icon.png create mode 100644 PatMe2Mqtt/packages.lock.json create mode 100644 README.md create mode 100644 preview.png create mode 100644 release.bat diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7990fe7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.vs/ +obj/ +bin/ +*.user \ No newline at end of file diff --git a/PatMe2Mqtt.sln b/PatMe2Mqtt.sln new file mode 100644 index 0000000..634ec60 --- /dev/null +++ b/PatMe2Mqtt.sln @@ -0,0 +1,36 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.3.32505.426 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PatMe2Mqtt", "PatMe2Mqtt\PatMe2Mqtt.csproj", "{13C812E9-0D42-4B95-8646-40EEBF30636F}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{5ECEDCE5-D60F-4A8A-AB33-4131F5C7371C}" + ProjectSection(SolutionItems) = preProject + Directory.Build.props = Directory.Build.props + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {13C812E9-0D42-4B95-8646-40EEBF30636F}.Debug|Any CPU.ActiveCfg = Debug|x64 + {13C812E9-0D42-4B95-8646-40EEBF30636F}.Debug|Any CPU.Build.0 = Debug|x64 + {13C812E9-0D42-4B95-8646-40EEBF30636F}.Debug|x64.ActiveCfg = Debug|x64 + {13C812E9-0D42-4B95-8646-40EEBF30636F}.Debug|x64.Build.0 = Debug|x64 + {13C812E9-0D42-4B95-8646-40EEBF30636F}.Release|Any CPU.ActiveCfg = Release|x64 + {13C812E9-0D42-4B95-8646-40EEBF30636F}.Release|Any CPU.Build.0 = Release|x64 + {13C812E9-0D42-4B95-8646-40EEBF30636F}.Release|x64.ActiveCfg = Release|x64 + {13C812E9-0D42-4B95-8646-40EEBF30636F}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {B17E85B1-5F60-4440-9F9A-3DDE877E8CDF} + EndGlobalSection +EndGlobal diff --git a/PatMe2Mqtt/Cmd.cs b/PatMe2Mqtt/Cmd.cs new file mode 100644 index 0000000..cd3b9ec --- /dev/null +++ b/PatMe2Mqtt/Cmd.cs @@ -0,0 +1,52 @@ +using Dalamud.Game.Command; +using System; + +namespace PatMe2Mqtt +{ + public abstract class Cmd : IDisposable + { + private CommandManager? _commandManager; + private string? _commandString; + + public abstract string Name { get; } + public string FullName => _commandString ?? $"/{Name}"; + + public abstract string HelpMessage { get; } + + public void Register(CommandManager commandManager) + { + if (_commandManager is not null) + { + Dispose(); + } + + _commandManager = commandManager; + _commandString = FullName; + + commandManager.AddHandler(FullName, new CommandInfo(Handle) + { + HelpMessage = HelpMessage + }); + } + + public abstract void Run(string arguments); + + public void Dispose() + { + _commandManager?.RemoveHandler(FullName); + _commandManager = null; + + GC.SuppressFinalize(this); + } + + private void Handle(string command, string arguments) + { + if (command != _commandString) + { + return; + } + + Run(arguments); + } + } +} diff --git a/PatMe2Mqtt/FastReflectionHelper.cs b/PatMe2Mqtt/FastReflectionHelper.cs new file mode 100644 index 0000000..5275133 --- /dev/null +++ b/PatMe2Mqtt/FastReflectionHelper.cs @@ -0,0 +1,135 @@ +using System; +using System.Reflection; +using System.Reflection.Emit; + +namespace MonoMod.Utils +{ + public delegate object? FastReflectionDelegate(object? target, params object?[] args); + + public static class FastReflectionHelper + { + private static readonly Type[] _dynamicMethodDelegateArgs = { typeof(object), typeof(object?[]) }; + + public static FastReflectionDelegate CreateFastDelegate(MethodBase method, bool directBoxValueAccess = true) + { + var dm = new DynamicMethod($"FastReflection<{method}>", typeof(object), _dynamicMethodDelegateArgs); + var il = dm.GetILGenerator(); + + var args = method.GetParameters(); + + var generateLocalBoxValuePtr = true; + + if (!method.IsStatic) + { + il.Emit(OpCodes.Ldarg_0); + + if (method.DeclaringType?.IsValueType ?? false) + { + il.Emit(OpCodes.Unbox_Any, method.DeclaringType); + } + } + + for (var i = 0; i < args.Length; i++) + { + var argType = args[i].ParameterType; + var argIsByRef = argType.IsByRef; + + if (argIsByRef) + { + argType = argType.GetElementType()!; + } + + var argIsValueType = argType.IsValueType; + + if (argIsByRef && argIsValueType && !directBoxValueAccess) + { + // Used later when storing back the reference to the new box in the array. + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Ldc_I4, i); + } + + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Ldc_I4, i); + + if (argIsByRef && !argIsValueType) + { + il.Emit(OpCodes.Ldelema, typeof(object)); + } + else + { + il.Emit(OpCodes.Ldelem_Ref); + + if (argIsValueType) + { + if (!argIsByRef || !directBoxValueAccess) + { + // if !directBoxValueAccess, create a new box if required + il.Emit(OpCodes.Unbox_Any, argType); + + if (argIsByRef) + { + // box back + il.Emit(OpCodes.Box, argType); + + // store new box value address to local 0 + il.Emit(OpCodes.Dup); + il.Emit(OpCodes.Unbox, argType); + + if (generateLocalBoxValuePtr) + { + generateLocalBoxValuePtr = false; + il.DeclareLocal(typeof(void*)); + } + + il.Emit(OpCodes.Stloc_0); + + // arr and index set up already + il.Emit(OpCodes.Stelem_Ref); + + // load address back to stack + il.Emit(OpCodes.Ldloc_0); + } + } + else + { + // if directBoxValueAccess, emit unbox (get value address) + il.Emit(OpCodes.Unbox, argType); + } + } + } + } + + if (method.IsConstructor) + { + il.Emit(OpCodes.Newobj, (ConstructorInfo) method); + } + else if (method.IsFinal || !method.IsVirtual) + { + il.Emit(OpCodes.Call, (MethodInfo) method); + } + else + { + il.Emit(OpCodes.Callvirt, (MethodInfo) method); + } + + var returnType = method.IsConstructor ? method.DeclaringType! : ((MethodInfo) method).ReturnType; + + if (returnType != typeof(void)) + { + if (returnType.IsValueType) + { + il.Emit(OpCodes.Box, returnType); + } + } + else + { + il.Emit(OpCodes.Ldnull); + } + + il.Emit(OpCodes.Ret); + + return (FastReflectionDelegate) dm.CreateDelegate(typeof(FastReflectionDelegate)); + } + + } +} diff --git a/PatMe2Mqtt/PatMe2Mqtt.csproj b/PatMe2Mqtt/PatMe2Mqtt.csproj new file mode 100644 index 0000000..94d3abc --- /dev/null +++ b/PatMe2Mqtt/PatMe2Mqtt.csproj @@ -0,0 +1,59 @@ + + + + 0x0ade + + 0.1.0.0 + Gluing PatMe and FFXIV2MQTT together. + + + + + + net7.0-windows + x64 + enable + latest + true + false + false + true + + + + $(appdata)\XIVLauncher\addon\Hooks\dev\ + + + + + + $(DalamudLibPath)FFXIVClientStructs.dll + false + + + $(DalamudLibPath)Newtonsoft.Json.dll + false + + + $(DalamudLibPath)Dalamud.dll + false + + + $(DalamudLibPath)ImGui.NET.dll + false + + + $(DalamudLibPath)ImGuiScene.dll + false + + + $(DalamudLibPath)Lumina.dll + false + + + $(DalamudLibPath)Lumina.Excel.dll + false + + + + diff --git a/PatMe2Mqtt/PatMe2Mqtt.json b/PatMe2Mqtt/PatMe2Mqtt.json new file mode 100644 index 0000000..889470b --- /dev/null +++ b/PatMe2Mqtt/PatMe2Mqtt.json @@ -0,0 +1,11 @@ +{ + "Name": "PatMe2MQTT", + "InternalName": "patme2mqtt", + "Author": "0x0ade", + "ApplicableVersion": "any", + "DalamudApiLevel": 8, + "Punchline": "Gluing PatMe and FFXIV2MQTT together.", + "Description": "Basic plugin that pokes FFXIV2MQTT every time PatMe detects a pat.", + "Tags": [ "pat", "emote", "mqtt", "patme", "ffxiv2mqtt" ], + "RepoUrl": "https://gitea.0x0a.de/0x0ade/PatMe2Mqtt" +} diff --git a/PatMe2Mqtt/PatMeProxyApi/EmoteCounter.cs b/PatMe2Mqtt/PatMeProxyApi/EmoteCounter.cs new file mode 100644 index 0000000..e611bbf --- /dev/null +++ b/PatMe2Mqtt/PatMeProxyApi/EmoteCounter.cs @@ -0,0 +1,19 @@ +using Dalamud.Game.ClientState.Objects.Enums; +using PatMe2Mqtt.PatMeProxyApi; +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Reflection; + +// This could be optimized in a thousand different ways (better dynamic methods, source-gen this class), but eh. + +namespace PatMe2Mqtt.PatMeProxyApi +{ + public readonly record struct EmoteCounter(PatMe PatMe, object ProxiedValue) : IPatMeProxy + { + public string descSingular => (string) PatMe.GetValue(ProxiedValue, nameof(descSingular))!; + public string descPlural => (string) PatMe.GetValue(ProxiedValue, nameof(descPlural))!; + public uint Value => (uint) PatMe.GetValue(ProxiedValue, nameof(Value))!; + } +} diff --git a/PatMe2Mqtt/PatMeProxyApi/EmoteCountersList.cs b/PatMe2Mqtt/PatMeProxyApi/EmoteCountersList.cs new file mode 100644 index 0000000..e89e139 --- /dev/null +++ b/PatMe2Mqtt/PatMeProxyApi/EmoteCountersList.cs @@ -0,0 +1,21 @@ +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; + +// This could be optimized in a thousand different ways (better dynamic methods, source-gen this class), but eh. + +namespace PatMe2Mqtt.PatMeProxyApi +{ + public readonly record struct EmoteCountersList(PatMe PatMe, object ProxiedValue) : IPatMeProxy, IEnumerable + { + public IEnumerator GetEnumerator() + { + foreach (var value in (IList) ProxiedValue) + { + yield return new EmoteCounter(PatMe, value); + } + } + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + } +} diff --git a/PatMe2Mqtt/PatMeProxyApi/IPatMeProxy.cs b/PatMe2Mqtt/PatMeProxyApi/IPatMeProxy.cs new file mode 100644 index 0000000..ce8f92d --- /dev/null +++ b/PatMe2Mqtt/PatMeProxyApi/IPatMeProxy.cs @@ -0,0 +1,9 @@ +namespace PatMe2Mqtt.PatMeProxyApi +{ + public interface IPatMeProxy + { + PatMe PatMe { get; } + object ProxiedValue { get; } + bool IsValid => PatMe is not null && ProxiedValue is not null; + } +} diff --git a/PatMe2Mqtt/PatMeProxyApi/PatMe.cs b/PatMe2Mqtt/PatMeProxyApi/PatMe.cs new file mode 100644 index 0000000..eb6c6d7 --- /dev/null +++ b/PatMe2Mqtt/PatMeProxyApi/PatMe.cs @@ -0,0 +1,264 @@ +using Dalamud.Logging; +using MonoMod.Utils; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.Loader; + +namespace PatMe2Mqtt.PatMeProxyApi +{ + public class PatMe + { + internal const BindingFlags _BindingFlags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static; + + private object? _realPatMe; + private Type? _realPatMeType; + private Type? _realPatMeServiceType; + + private WeakReference? _lastPatMe; + private readonly Dictionary<(Type, string), FastReflectionDelegate> _methodCache = new(); + private readonly Dictionary<(Type, string), MemberInfo> _memberCache = new(); + + public PatMe() + { + // Refresh(); + } + + public bool IsAvailable => _realPatMe is not null; + + public EmoteCountersList EmoteCounters { get; private set; } + + public bool Refresh() + { + PluginLog.LogInformation("Refreshing PatMeProxyApi"); + + if (Service.GetPluginInstance?.Invoke("PatMe") is not { } realPatMe) + { + PluginLog.LogInformation("PatMe not found"); + + Unset(); + + return false; + } + + _realPatMe = realPatMe; + _realPatMeType = realPatMe.GetType(); + _realPatMeServiceType = _realPatMeType.Assembly.GetType("PatMe.Service"); + + if (_realPatMeServiceType is null) + { + PluginLog.LogInformation("PatMe.Service not found"); + + Unset(); + + return false; + } + + PluginLog.LogInformation($"PatMe found: {_realPatMeType.Assembly.FullName}"); + + if (_lastPatMe?.Target != realPatMe) + { + PluginLog.LogInformation($"Different PatMe, clearing cache"); + + ClearCache(); + + _lastPatMe = new WeakReference(realPatMe); + } + + EmoteCounters = new(this, _realPatMeServiceType.GetField("emoteCounters")?.GetValue(null)!); + + return true; + } + + internal FastReflectionDelegate GetMethod(Type target, string name, Func? getMethod = null) + { + if (_methodCache.TryGetValue((target, name), out var fun)) + { + return fun; + } + + return _methodCache[(target, name)] = FastReflectionHelper.CreateFastDelegate(getMethod?.Invoke(target) ?? target.GetMethods().FirstOrDefault(m => m.Name == name) ?? target.GetMethod(name, _BindingFlags)!); + } + + internal object? InvokeStatic(string typeName, string name, params object?[] args) + { + if (_realPatMeType?.Assembly.GetType(typeName) is not { } type) + { + PluginLog.LogInformation($"GetStaticValue failed, type \"{typeName}\" not found"); + + return null; + } + + return GetMethod(type, name).Invoke(null, args); + } + + internal object? Invoke(object proxiedValue, string name, params object?[] args) + { + return GetMethod(proxiedValue.GetType(), name).Invoke(proxiedValue, args); + } + + internal object? GetStaticValue(string typeName, string name, params object?[] args) + { + if (_realPatMeType?.Assembly.GetType(typeName) is not { } type) + { + PluginLog.LogInformation($"GetStaticValue failed, type \"{typeName}\" not found"); + + return null; + } + + if (!_memberCache.TryGetValue((type, name), out var member)) + { + member = _memberCache[(type, name)] = type.GetMember(name, _BindingFlags).First(); + } + + if (member is FieldInfo field) + { + return field.GetValue(null); + } + + if (member is PropertyInfo property) + { + return property.GetValue(null, args); + } + + return InvokeStatic(typeName, name, args); + } + + internal object? GetValue(object proxiedValue, string name, params object?[] args) + { + if (!_memberCache.TryGetValue((proxiedValue.GetType(), name), out var member)) + { + member = _memberCache[(proxiedValue.GetType(), name)] = proxiedValue.GetType().GetMember(name, _BindingFlags).First(); + } + + if (member is FieldInfo field) + { + return field.GetValue(proxiedValue); + } + + if (member is PropertyInfo property) + { + return property.GetValue(proxiedValue, args); + } + + return Invoke(proxiedValue, name, args); + } + + internal void SetStaticValue(string typeName, string name, params object?[] args) + { + if (_realPatMeType?.Assembly.GetType(typeName) is not { } type) + { + PluginLog.LogInformation($"GetStaticValue failed, type \"{typeName}\" not found"); + + return; + } + + if (!_memberCache.TryGetValue((type, name), out var member)) + { + member = _memberCache[(type, name)] = type.GetMember(name, _BindingFlags).First(); + } + + if (member is FieldInfo field) + { + field.SetValue(null, args[0]); + + return; + } + + if (member is PropertyInfo property) + { + property.SetValue(null, args.First(), args.Length > 1 ? args.Skip(1).ToArray() : null); + + return; + } + + InvokeStatic(typeName, name, args); + } + + internal void SetValue(object proxiedValue, string name, params object?[] args) + { + if (!_memberCache.TryGetValue((proxiedValue.GetType(), name), out var member)) + { + member = _memberCache[(proxiedValue.GetType(), name)] = proxiedValue.GetType().GetMember(name, _BindingFlags).First(); + } + + if (member is FieldInfo field) + { + field.SetValue(proxiedValue, args[0]); + + return; + } + + if (member is PropertyInfo property) + { + property.SetValue(proxiedValue, args.First(), args.Length > 1 ? args.Skip(1).ToArray() : null); + + return; + } + + Invoke(proxiedValue, name, args); + } + + internal ITuple ConvertValueTuple(Type targetType, object proxiedValue) + { + var rawTuple = (ITuple) proxiedValue; + var dstItems = new object?[rawTuple.Length]; + var rawTypes = proxiedValue.GetType().GenericTypeArguments; + var dstTypes = targetType.GenericTypeArguments; + + for (var i = 0; i < rawTuple.Length; i++) + { + var raw = rawTuple[i]; + + if (dstTypes[i].IsAssignableFrom(rawTypes[i])) + { + dstItems[i] = raw; + } + else if (raw is not null) + { + var dstType = dstTypes[i]; + + var isNullable = dstType.FullName?.StartsWith("System.Nullable`1[[") ?? false; + + if (isNullable) + { + dstType = dstType.GenericTypeArguments[0]; + } + + dstItems[i] = Activator.CreateInstance(dstType, new object[] { this, raw }); + + if (isNullable) + { + dstItems[i] = Activator.CreateInstance(dstTypes[i], new object[] { dstItems[i]! }); + } + } + else + { + dstItems[i] = null; + } + } + + return (ITuple) Activator.CreateInstance(targetType, dstItems)!; + } + + private void Unset() + { + _realPatMe = default; + _realPatMeType = default; + _realPatMeServiceType = default; + + EmoteCounters = default; + + ClearCache(); + } + + private void ClearCache() + { + _lastPatMe = null; + _methodCache.Clear(); + _memberCache.Clear(); + } + } +} diff --git a/PatMe2Mqtt/Plugin.cs b/PatMe2Mqtt/Plugin.cs new file mode 100644 index 0000000..e0b95e3 --- /dev/null +++ b/PatMe2Mqtt/Plugin.cs @@ -0,0 +1,128 @@ +using Dalamud.IoC; +using Dalamud.Logging; +using Dalamud.Plugin; +using Dalamud.Plugin.Ipc; +using PatMe2Mqtt.PatMeProxyApi; +using System; +using System.Collections.Generic; +using System.Diagnostics.Metrics; +using System.Linq; + +namespace PatMe2Mqtt +{ + public sealed class Plugin : IDalamudPlugin + { + private readonly List _cmds; + private readonly ICallGateSubscriber _ipcPatMeCounter; + private readonly ICallGateSubscriber _ipcMqttPublish; + + public Plugin([RequiredVersion("1.0")] DalamudPluginInterface pluginInterface) + { + pluginInterface.Create(); + + Service.Plugin = this; + Service.PatMe = new(); + + _cmds = typeof(Plugin).Assembly.GetTypes() + .Where(t => !t.IsAbstract && typeof(Cmd).IsAssignableFrom(t)) + .Select(t => (Cmd) Activator.CreateInstance(t)!) + .ToList(); + + foreach (Cmd cmd in _cmds) + { + cmd.Register(Service.CommandManager); + } + + _ipcPatMeCounter = pluginInterface.GetIpcSubscriber("patMeEmoteCounter"); + _ipcMqttPublish = pluginInterface.GetIpcSubscriber("Ffxiv2Mqtt.Publish"); + + SyncAll(); + + Service.ClientState.Login += OnLogIn; + _ipcPatMeCounter.Subscribe(OnPatMeEmote); + } + + public string Name => "PatMe2Mqtt"; + + public void Dispose() + { + Service.ClientState.Login -= OnLogIn; + _ipcPatMeCounter.Unsubscribe(OnPatMeEmote); + + foreach (Cmd cmd in _cmds) + { + cmd.Dispose(); + } + + Service.Plugin = null!; + } + + public void SyncAll() + { + try + { + if (!Service.PatMe.Refresh()) + { + return; + } + + foreach (var emoteCounter in Service.PatMe.EmoteCounters) + { + Sync(emoteCounter); + } + } + catch (Exception e) + { + PluginLog.LogError(e, "PatMe2Mqtt couldn't SyncAll"); + } + } + + private void SyncByDescSingular(string descSingular) + { + try + { + if (!Service.PatMe.Refresh()) + { + return; + } + + foreach (var emoteCounter in Service.PatMe.EmoteCounters) + { + if (emoteCounter.descSingular == descSingular) + { + Sync(emoteCounter); + } + } + } + catch (Exception e) + { + PluginLog.LogError(e, "PatMe2Mqtt couldn't SyncByDescSingular({0})", descSingular); + } + } + + private void Sync(EmoteCounter counter) + { + var topic = $"patme/{Service.ClientState.LocalContentId}/{counter.descPlural}"; + var value = counter.Value.ToString(); + + try + { + _ipcMqttPublish.InvokeFunc(topic, value); + } + catch (Exception e) + { + PluginLog.LogWarning(e, "PatMe2Mqtt couldn't Sync(\"{0}\", {1})", topic, value); + } + } + + private void OnLogIn(object? sender, EventArgs e) + { + Service.Framework.RunOnTick(SyncAll, delayTicks: 10); + } + + private void OnPatMeEmote(string descSingular, ushort emoteId, string instigatorName, uint instigatorWorld) + { + SyncByDescSingular(descSingular); + } + } +} diff --git a/PatMe2Mqtt/Service.cs b/PatMe2Mqtt/Service.cs new file mode 100644 index 0000000..3bcd976 --- /dev/null +++ b/PatMe2Mqtt/Service.cs @@ -0,0 +1,106 @@ +using Dalamud.Data; +using Dalamud.Game; +using Dalamud.Game.ClientState; +using Dalamud.Game.ClientState.Objects; +using Dalamud.Game.Command; +using Dalamud.Game.Gui; +using Dalamud.Game.Text; +using Dalamud.IoC; +using Dalamud.Logging; +using Dalamud.Plugin; +using System.Reflection; +using System; +using System.Collections; + +namespace PatMe2Mqtt +{ + public sealed class Service + { + public Service() + { + // THIS. IS. UGLY. + try + { + if (typeof(PluginServiceAttribute).Assembly.GetType("Dalamud.Service`1") is not { } serviceContainerContainer) + { + PluginLog.LogInformation("PenumbraCmd couldn't find the service container types."); + + return; + } + + if (typeof(PluginServiceAttribute).Assembly.GetType("Dalamud.Plugin.Internal.PluginManager") is not { } pluginManagerType) + { + PluginLog.LogInformation("PenumbraCmd couldn't find the plugin manager type."); + + return; + } + + if (typeof(PluginServiceAttribute).Assembly.GetType("Dalamud.Plugin.Internal.Types.LocalPlugin") is not { } localPluginType || + localPluginType.GetField("instance", BindingFlags.NonPublic | BindingFlags.Instance) is not { } localPluginInstanceField) + { + PluginLog.LogInformation("PenumbraCmd couldn't find the local plugin type or important members."); + + return; + } + + serviceContainerContainer = serviceContainerContainer.MakeGenericType(pluginManagerType); + + if (serviceContainerContainer.GetMethod("Get")?.Invoke(null, Array.Empty()) is not object manager) + { + PluginLog.LogInformation("PenumbraCmd couldn't obtain the plugin manager."); + + return; + } + + if (pluginManagerType.GetProperty("InstalledPlugins") is not { } installedPluginsProperty) + { + PluginLog.LogInformation("PenumbraCmd couldn't obtain the plugin list property."); + + return; + } + + GetPluginInstance = name => + { + if (installedPluginsProperty?.GetValue(manager) is not IList installedPlugins) + { + PluginLog.LogInformation("PenumbraCmd couldn't obtain the plugin list."); + + return null; + } + + foreach (var plugin in installedPlugins) + { + if (localPluginInstanceField.GetValue(plugin) is { } instance && instance.GetType().Assembly.GetName().Name == name) + { + return instance; + } + } + + return null; + }; + } + catch (Exception e) + { + PluginLog.LogInformation($"PenumbraCmd couldn't obtain the plugin manager service: {e}"); + } + } + + public static Plugin Plugin { get; internal set; } = null!; + + public static PatMeProxyApi.PatMe PatMe { get; internal set; } = null!; + + [PluginService] + public static DalamudPluginInterface PluginInterface { get; private set; } = null!; + + [PluginService] + public static CommandManager CommandManager { get; private set; } = null!; + + [PluginService] + public static Framework Framework { get; private set; } = null!; + + [PluginService] + public static ClientState ClientState { get; private set; } = null!; + + public static Func? GetPluginInstance { get; private set; } + } +} diff --git a/PatMe2Mqtt/SyncCmd.cs b/PatMe2Mqtt/SyncCmd.cs new file mode 100644 index 0000000..cbf58e5 --- /dev/null +++ b/PatMe2Mqtt/SyncCmd.cs @@ -0,0 +1,14 @@ +namespace PatMe2Mqtt +{ + public sealed class SyncCmd : Cmd + { + public override string Name => "patme2mqtt"; + + public override string HelpMessage => "Manually pushes the PatMe stats to MQTT."; + + public override void Run(string arguments) + { + Service.Plugin.SyncAll(); + } + } +} diff --git a/PatMe2Mqtt/images/icon.png b/PatMe2Mqtt/images/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..911e1dc3eb0ef3fd340d0b8d56760225238afd17 GIT binary patch literal 31764 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 literal 0 HcmV?d00001 diff --git a/PatMe2Mqtt/packages.lock.json b/PatMe2Mqtt/packages.lock.json new file mode 100644 index 0000000..467f0f2 --- /dev/null +++ b/PatMe2Mqtt/packages.lock.json @@ -0,0 +1,13 @@ +{ + "version": 1, + "dependencies": { + "net7.0-windows7.0": { + "DalamudPackager": { + "type": "Direct", + "requested": "[2.1.11, )", + "resolved": "2.1.11", + "contentHash": "9qlAWoRRTiL/geAvuwR/g6Bcbrd/bJJgVnB/RurBiyKs6srsP0bvpoo8IK+Eg8EA6jWeM6/YJWs66w4FIAzqPw==" + } + } + } +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..e08e6d8 --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +# PatMe2Mqtt +### Gluing PatMe and Ffxiv2Mqtt together +Basic plugin that pokes Ffxiv2Mqtt every time PatMe detects a pat. + +![preview of MQTTExplorer showing the ffxiv/patme/cid/emote topics](./preview.png) diff --git a/preview.png b/preview.png new file mode 100644 index 0000000000000000000000000000000000000000..4e3720910b324d0ebd96d4c9546613db34ecfa58 GIT binary patch literal 37826 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 nUH