diff --git a/.gitmodules b/.gitmodules index 02acc3b..39257f3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ -[submodule "machina"] - path = machina - url = https://github.com/marzent/machina [submodule "OverlayPlugin.Core/resources/act-overlays"] path = OverlayPlugin.Core/resources/act-overlays url = https://github.com/cking/act-overlays diff --git a/FetchDependencies/Costura.cs b/FetchDependencies/Costura.cs index 8e65f7d..472f50a 100644 --- a/FetchDependencies/Costura.cs +++ b/FetchDependencies/Costura.cs @@ -7,7 +7,7 @@ internal static class Costura { public static bool CheckForPlugin(string name) { - return name.Contains("act"); + return name.Contains("act") || name.Contains("machina"); } public static string Fix(string name) @@ -16,6 +16,8 @@ public static string Fix(string name) return "FFXIV_ACT_" + name.Substring(18, name.Length - 33).ToTitleCase() + ".dll"; if (name.Contains("machina.ffxiv")) return "Machina.FFXIV.dll"; + if (name.Contains("machina")) + return "Machina.dll"; return name.Substring(8, name.Length - 23).ToTitleCase() + ".dll"; } diff --git a/FetchDependencies/FetchDependencies.cs b/FetchDependencies/FetchDependencies.cs index 732f84a..0378a37 100644 --- a/FetchDependencies/FetchDependencies.cs +++ b/FetchDependencies/FetchDependencies.cs @@ -1,4 +1,5 @@ using System.IO.Compression; +using Dalamud.Plugin.Services; namespace FetchDependencies; @@ -13,13 +14,15 @@ public class FetchDependencies private string DependenciesDir { get; } private bool IsChinese { get; } private HttpClient HttpClient { get; } + private IPluginLog PluginLog { get; } - public FetchDependencies(Version version, string assemblyDir, bool isChinese, HttpClient httpClient) + public FetchDependencies(Version version, string assemblyDir, bool isChinese, HttpClient httpClient, IPluginLog pluginLog) { PluginVersion = version; DependenciesDir = assemblyDir; IsChinese = isChinese; HttpClient = httpClient; + PluginLog = pluginLog; } public void GetFfxivPlugin() @@ -53,10 +56,11 @@ public void GetFfxivPlugin() File.Delete(deucalionDll); } - var patcher = new Patcher(PluginVersion, DependenciesDir); + var patcher = new Patcher(PluginVersion, DependenciesDir, PluginLog); patcher.MainPlugin(); patcher.LogFilePlugin(); patcher.MemoryPlugin(); + patcher.MachinaFFXIV(); } private bool NeedsUpdate(string dllPath) diff --git a/FetchDependencies/FetchDependencies.csproj b/FetchDependencies/FetchDependencies.csproj index 73afc0d..6c0d449 100644 --- a/FetchDependencies/FetchDependencies.csproj +++ b/FetchDependencies/FetchDependencies.csproj @@ -26,6 +26,13 @@ $(HOME)/Library/Application Support/XIV on Mac/dalamud/Hooks/dev/ + + + $(DalamudLibPath)Dalamud.dll + false + + + $(DalamudLibPath)Mono.Cecil.dll diff --git a/FetchDependencies/Patcher.cs b/FetchDependencies/Patcher.cs index dfdf1f7..4a4db89 100644 --- a/FetchDependencies/Patcher.cs +++ b/FetchDependencies/Patcher.cs @@ -1,3 +1,4 @@ +using Dalamud.Plugin.Services; using Mono.Cecil; using Mono.Cecil.Cil; @@ -7,11 +8,13 @@ internal class Patcher { private Version PluginVersion { get; } private string WorkPath { get; } + private IPluginLog PluginLog { get; } - public Patcher(Version version, string workPath) + public Patcher(Version version, string workPath, IPluginLog pluginLog) { PluginVersion = version; WorkPath = workPath; + PluginLog = pluginLog; } public void MainPlugin() @@ -196,4 +199,112 @@ void UseMarshallCopyBuffer(MethodDefinition method) memory.WriteOut(); } + + public void MachinaFFXIV() + { + var machinaDalamud = new TargetAssembly(Path.Combine(WorkPath, "Machina.FFXIV.Dalamud.dll")); + + var machina = new TargetAssembly(Path.Combine(WorkPath, "Machina.FFXIV.dll")); + machina.RemoveStrongNaming(); + + // For the Machina library, we want to replace all usages of `DeucalionClient` with our reimplemented + // `NotDeucalionClient`. That class is used only in `Machina.FFXIV.FFXIVNetworkMonitor` class. So we need + // to do the following modifications: + // + // 1. Replace its private member `_deucalionClient`'s type. + // 2. In its every method: + // - Replace all its `ldfld` and `stfld` instructions of the current class's `_deucalionClient` member. + // - Replace all its `ldfld` and `stfld` instructions of `DeucalionClient`'s members with `NotDeucalionClient`'s + // corresponding members. Thay have the same names and types, so we can just replace the type references. + // - Replace all its `newobj` and `call*` instructions of `DeucalionClient`'s methods with `NotDeucalionClient`'s + // corresponding methods. + // - To prevent the Deucalion library from being really injected, replace all its `call*` instructions that to + // class `DeucalionInjector` with `NotDeucalionInjector`. + // 3. Safely remove the `DeucalionClient` and `DeucalionInjector` classes from the Machina library. + + var oldClientFullName = "Machina.FFXIV.Deucalion.DeucalionClient"; + var newClientFullName = "Machina.FFXIV.Dalamud.NotDeucalionClient"; + var oldClientDefiniton = machina.Assembly.MainModule.Types.First(type => type.FullName == oldClientFullName); + var newClientDefiniton = machinaDalamud.Assembly.MainModule.Types.First(type => type.FullName == newClientFullName); + + var oldInjectorFullName = "Machina.FFXIV.Deucalion.DeucalionInjector"; + var newInjectorFullName = "Machina.FFXIV.Dalamud.NotDeucalionInjector"; + var oldInjectorDefiniton = machina.Assembly.MainModule.Types.First(type => type.FullName == oldInjectorFullName); + var newInjectorDefiniton = machinaDalamud.Assembly.MainModule.Types.First(type => type.FullName == newInjectorFullName); + + // For method replacements, also replace for the nested types of `DeucalionClient`. + // (i.e. `MessageReceivedHandler` / `MessageSentHandler` delegates) + var typeReplacements = new Dictionary + { + {oldClientFullName, newClientDefiniton}, + {oldInjectorFullName, newInjectorDefiniton}, + }; + foreach (var nestedType in oldClientDefiniton.NestedTypes) + { + var target = newClientDefiniton.NestedTypes.FirstOrDefault( + type => type.Name == nestedType.Name); + if (target != null) + typeReplacements[nestedType.FullName] = target; + } + + // Get the `FFXIVNetworkMonitor` class. + var ffxivNetworkMonitor = machina.Assembly.MainModule.Types.First(type => + type.FullName == "Machina.FFXIV.FFXIVNetworkMonitor"); + + { + // Step 1 - Replace its private member `_deucalionClient`'s type. + var deucalionClientField = ffxivNetworkMonitor.Fields.First(field => field.Name == "_deucalionClient"); + deucalionClientField.FieldType = machina.Assembly.MainModule.ImportReference(newClientDefiniton); + } + { + // Step 2 + foreach (var method in ffxivNetworkMonitor.Methods) + { + foreach (var instruction in method.Body.Instructions) + { + if (instruction.OpCode == OpCodes.Newobj || + instruction.OpCode == OpCodes.Call || + instruction.OpCode == OpCodes.Calli || + instruction.OpCode == OpCodes.Callvirt) + { + var methodReference = (MethodReference)instruction.Operand; + foreach (var (oldType, newType) in typeReplacements) + { + if (methodReference.DeclaringType.FullName == oldType) + { + var newMethodDefinition = newType.Methods.FirstOrDefault(m => + m.Name == methodReference.Name && m.Parameters.Count == methodReference.Parameters.Count); + if (newMethodDefinition != null) + instruction.Operand = machina.Assembly.MainModule.ImportReference(newMethodDefinition); + else + { + PluginLog.Error($"[Patcher] Could not find method {methodReference.Name} in {newType.FullName}"); + } + } + } + } + else if (instruction.OpCode == OpCodes.Ldfld || instruction.OpCode == OpCodes.Stfld) + { + var fieldReference = (FieldReference)instruction.Operand; + if (fieldReference.DeclaringType.FullName == ffxivNetworkMonitor.FullName && + fieldReference.FieldType.FullName == oldClientFullName) + { + fieldReference.FieldType = machina.Assembly.MainModule.ImportReference(newClientDefiniton); + } + else if (fieldReference.DeclaringType.FullName == oldClientFullName) + { + var newFieldDefiniton = newClientDefiniton.Fields.First(f => f.Name == fieldReference.Name); + instruction.Operand = machina.Assembly.MainModule.ImportReference(newFieldDefiniton); + } + } + } + } + } + + // Step 3 - Remove the unused classes. + machina.Assembly.MainModule.Types.Remove(oldClientDefiniton); + machina.Assembly.MainModule.Types.Remove(oldInjectorDefiniton); + + machina.WriteOut(); + } } diff --git a/IINACT.sln b/IINACT.sln index 62a6737..40a840f 100644 --- a/IINACT.sln +++ b/IINACT.sln @@ -13,10 +13,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OverlayPlugin.Core", "Overl EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FetchDependencies", "FetchDependencies\FetchDependencies.csproj", "{4EDF0EAF-0BC8-40CB-A2D1-F4A207770002}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Machina", "machina\Machina\Machina.csproj", "{38F9CA44-D795-4F78-8DFC-5D555CDEC4F5}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Machina.FFXIV", "machina\Machina.FFXIV\Machina.FFXIV.csproj", "{1AAD30B3-55ED-4C10-94BF-41889B6BD44A}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU diff --git a/IINACT/IINACT.csproj b/IINACT/IINACT.csproj index 4dafee8..f482405 100644 --- a/IINACT/IINACT.csproj +++ b/IINACT/IINACT.csproj @@ -70,10 +70,9 @@ - - + @@ -109,6 +108,14 @@ ..\external_dependencies\SDK\FFXIV_ACT_Plugin.Resource.dll False + + ..\external_dependencies\SDK\Machina.dll + False + + + ..\external_dependencies\SDK\Machina.FFXIV.dll + False + diff --git a/IINACT/Plugin.cs b/IINACT/Plugin.cs index f565b1f..a2703a8 100644 --- a/IINACT/Plugin.cs +++ b/IINACT/Plugin.cs @@ -80,7 +80,7 @@ public Plugin(IDalamudPluginInterface pluginInterface, var fetchDeps = new FetchDependencies.FetchDependencies(Version, PluginInterface.AssemblyLocation.Directory!.FullName, - DataManager.Language.ToString() == "ChineseSimplified", HttpClient); + DataManager.Language.ToString() == "ChineseSimplified", HttpClient, Log); fetchDeps.GetFfxivPlugin(); diff --git a/IINACT/packages.lock.json b/IINACT/packages.lock.json index e058285..6ce4476 100644 --- a/IINACT/packages.lock.json +++ b/IINACT/packages.lock.json @@ -1,76 +1,68 @@ -{ - "version": 1, - "dependencies": { - "net8.0-windows7.0": { - "DalamudPackager": { - "type": "Direct", - "requested": "[2.1.13, )", - "resolved": "2.1.13", - "contentHash": "rMN1omGe8536f4xLMvx9NwfvpAc9YFFfeXJ1t4P4PE6Gu8WCIoFliR1sh07hM+bfODmesk/dvMbji7vNI+B/pQ==" - }, - "System.Speech": { - "type": "Direct", - "requested": "[8.0.0, )", - "resolved": "8.0.0", - "contentHash": "CNuiA6vb95Oe5PRjClZEBiaju31vwB8OIeCgeSBXyZL6+MS4RVVB2X/C11z0xCkooHE3Vy91nM2z76emIzR+sg==" - }, - "Microsoft.CSharp": { - "type": "Transitive", - "resolved": "4.7.0", - "contentHash": "pTj+D3uJWyN3My70i2Hqo+OXixq3Os2D1nJ2x92FFo6sk8fYS1m1WLNTs0Dc1uPaViH0YvEEwvzddQ7y4rhXmA==" - }, - "NetCoreServer": { - "type": "Transitive", - "resolved": "8.0.7", - "contentHash": "BhNiJ6EVxKS1eKqlHINy7BruLDc+xCH59oZxu7d2Hve8CzFki69PumVlf6vyAQvIVfxbZiHw/FI3UHNnMajuVg==" - }, - "System.Data.DataSetExtensions": { - "type": "Transitive", - "resolved": "4.5.0", - "contentHash": "221clPs1445HkTBZPL+K9sDBdJRB8UN8rgjO3ztB0CQ26z//fmJXtlsr6whGatscsKGBrhJl5bwJuKSA8mwFOw==" - }, - "Advanced Combat Tracker": { - "type": "Project" - }, - "fetchdependencies": { - "type": "Project" - }, - "machina": { - "type": "Project" - }, - "machina.ffxiv": { - "type": "Project", - "dependencies": { - "Machina": "[2.3.1.3, )" - } - }, - "overlayplugin.common": { - "type": "Project", - "dependencies": { - "Advanced Combat Tracker": "[6.9.0, )", - "Microsoft.CSharp": "[4.7.0, )", - "System.Data.DataSetExtensions": "[4.5.0, )" - } - }, - "overlayplugin.core": { - "type": "Project", - "dependencies": { - "Machina": "[2.3.1.3, )", - "Machina.FFXIV": "[2.3.8.5, )", - "Microsoft.CSharp": "[4.7.0, )", - "NetCoreServer": "[8.0.7, )", - "OverlayPlugin.Common": "[1.0.0, )", - "System.Data.DataSetExtensions": "[4.5.0, )" - } - } - }, - "net8.0-windows7.0/win-x64": { - "System.Speech": { - "type": "Direct", - "requested": "[8.0.0, )", - "resolved": "8.0.0", - "contentHash": "CNuiA6vb95Oe5PRjClZEBiaju31vwB8OIeCgeSBXyZL6+MS4RVVB2X/C11z0xCkooHE3Vy91nM2z76emIzR+sg==" - } - } - } +{ + "version": 1, + "dependencies": { + "net8.0-windows7.0": { + "DalamudPackager": { + "type": "Direct", + "requested": "[2.1.13, )", + "resolved": "2.1.13", + "contentHash": "rMN1omGe8536f4xLMvx9NwfvpAc9YFFfeXJ1t4P4PE6Gu8WCIoFliR1sh07hM+bfODmesk/dvMbji7vNI+B/pQ==" + }, + "System.Speech": { + "type": "Direct", + "requested": "[8.0.0, )", + "resolved": "8.0.0", + "contentHash": "CNuiA6vb95Oe5PRjClZEBiaju31vwB8OIeCgeSBXyZL6+MS4RVVB2X/C11z0xCkooHE3Vy91nM2z76emIzR+sg==" + }, + "Microsoft.CSharp": { + "type": "Transitive", + "resolved": "4.7.0", + "contentHash": "pTj+D3uJWyN3My70i2Hqo+OXixq3Os2D1nJ2x92FFo6sk8fYS1m1WLNTs0Dc1uPaViH0YvEEwvzddQ7y4rhXmA==" + }, + "NetCoreServer": { + "type": "Transitive", + "resolved": "8.0.7", + "contentHash": "BhNiJ6EVxKS1eKqlHINy7BruLDc+xCH59oZxu7d2Hve8CzFki69PumVlf6vyAQvIVfxbZiHw/FI3UHNnMajuVg==" + }, + "System.Data.DataSetExtensions": { + "type": "Transitive", + "resolved": "4.5.0", + "contentHash": "221clPs1445HkTBZPL+K9sDBdJRB8UN8rgjO3ztB0CQ26z//fmJXtlsr6whGatscsKGBrhJl5bwJuKSA8mwFOw==" + }, + "Advanced Combat Tracker": { + "type": "Project" + }, + "fetchdependencies": { + "type": "Project" + }, + "machina.ffxiv.dalamud": { + "type": "Project" + }, + "overlayplugin.common": { + "type": "Project", + "dependencies": { + "Advanced Combat Tracker": "[6.9.0, )", + "Microsoft.CSharp": "[4.7.0, )", + "System.Data.DataSetExtensions": "[4.5.0, )" + } + }, + "overlayplugin.core": { + "type": "Project", + "dependencies": { + "Microsoft.CSharp": "[4.7.0, )", + "NetCoreServer": "[8.0.7, )", + "OverlayPlugin.Common": "[1.0.0, )", + "System.Data.DataSetExtensions": "[4.5.0, )" + } + } + }, + "net8.0-windows7.0/win-x64": { + "System.Speech": { + "type": "Direct", + "requested": "[8.0.0, )", + "resolved": "8.0.0", + "contentHash": "CNuiA6vb95Oe5PRjClZEBiaju31vwB8OIeCgeSBXyZL6+MS4RVVB2X/C11z0xCkooHE3Vy91nM2z76emIzR+sg==" + } + } + } } \ No newline at end of file diff --git a/Machina.FFXIV.Dalamud/DalamudClient.cs b/Machina.FFXIV.Dalamud/DalamudClient.cs new file mode 100644 index 0000000..2aceb48 --- /dev/null +++ b/Machina.FFXIV.Dalamud/DalamudClient.cs @@ -0,0 +1,183 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using Dalamud.Game.Network; +using Dalamud.Plugin.Services; +using Machina.FFXIV.Headers; + +namespace Machina.FFXIV.Dalamud +{ + public class DalamudClient : IDisposable + { + public static IGameNetwork GameNetwork { get; set; } + public delegate long GetTimeDelegate(); + public static GetTimeDelegate GetServerTime; + + public delegate void MessageReceivedHandler(long epoch, byte[] message); + public MessageReceivedHandler MessageReceived; + + private CancellationTokenSource _tokenSource; + private Task _monitorTask; + private ConcurrentQueue<(long, byte[])> _messageQueue; + + private DateTime _lastLoopError; + + private readonly Dictionary OpcodeSizes; + + internal unsafe DalamudClient() + { + OpcodeSizes = new Dictionary + { + { Server_MessageType.StatusEffectList, sizeof(Server_StatusEffectList) }, + { Server_MessageType.StatusEffectList2, sizeof(Server_StatusEffectList2) }, + { Server_MessageType.StatusEffectList3, sizeof(Server_StatusEffectList3) }, + { Server_MessageType.BossStatusEffectList, sizeof(Server_BossStatusEffectList) }, + { Server_MessageType.Ability1, sizeof(Server_ActionEffect1) }, + { Server_MessageType.Ability8, sizeof(Server_ActionEffect8) }, + { Server_MessageType.Ability16, sizeof(Server_ActionEffect16) }, + { Server_MessageType.Ability24, sizeof(Server_ActionEffect24) }, + { Server_MessageType.Ability32, sizeof(Server_ActionEffect32) }, + { Server_MessageType.ActorCast, sizeof(Server_ActorCast) }, + { Server_MessageType.EffectResult, sizeof(Server_EffectResult) }, + { Server_MessageType.EffectResultBasic, sizeof(Server_EffectResultBasic) }, + { Server_MessageType.ActorControl, sizeof(Server_ActorControl) }, + { Server_MessageType.ActorControlSelf, sizeof(Server_ActorControlSelf) }, + { Server_MessageType.ActorControlTarget, sizeof(Server_ActorControlTarget) }, + { Server_MessageType.UpdateHpMpTp, sizeof(Server_UpdateHpMpTp) }, + { Server_MessageType.ActorGauge, sizeof(Server_ActorGauge) }, + { Server_MessageType.PresetWaymark, sizeof(Server_PresetWaymark) }, + { Server_MessageType.Waymark, sizeof(Server_Waymark) }, + { Server_MessageType.SystemLogMessage, sizeof(Server_SystemLogMessage) }, + { Server_MessageType.ActorMove, 0x30 }, + { Server_MessageType.NpcSpawn, 0x2A0 } + }; + } + + + public void OnMessageReceived(long epoch, byte[] message) + { + MessageReceived?.Invoke(epoch, message); + } + + public void Connect() + { + if (GameNetwork is null) + { + Trace.WriteLine($"DalamudClient: Dalamud GameNetwork has not been injected/set.", "DEBUG-MACHINA"); + return; + } + + _messageQueue = new ConcurrentQueue<(long, byte[])>(); + + GameNetwork.NetworkMessage += GameNetworkOnNetworkMessage; + + _tokenSource = new CancellationTokenSource(); + + _monitorTask = Task.Run(() => ProcessReadLoop(_tokenSource.Token)); + } + + private void ProcessReadLoop(CancellationToken token) + { + try + { + while (!token.IsCancellationRequested) + { + try + { + while (_messageQueue.TryDequeue(out var messageInfo)) + { + OnMessageReceived(messageInfo.Item1, messageInfo.Item2); + } + + Task.Delay(10, token).Wait(token); + } + catch (OperationCanceledException) + { + + } + catch (Exception ex) + { + if (DateTime.UtcNow.Subtract(_lastLoopError).TotalSeconds > 5) + Trace.WriteLine("DalamudClient: Error in inner ProcessReadLoop. " + ex.ToString(), "DEBUG-MACHINA"); + _lastLoopError = DateTime.UtcNow; + } + + } + } + catch (OperationCanceledException) + { + + } + catch (Exception ex) + { + Trace.WriteLine("DalamudClient: Error in outer ProcessReadLoop. " + ex.ToString(), "DEBUG-MACHINA"); + } + } + + protected unsafe void GameNetworkOnNetworkMessage(IntPtr dataPtr, ushort opcode, uint sourceActorId, uint targetActorId, NetworkMessageDirection direction) + { + if (direction != NetworkMessageDirection.ZoneDown || GetServerTime == null) + return; + + var size = 0x1000; // best effort + + // if we can't map the opcode to its true size it *should* still be fine + if (OpcodeSizes.ContainsKey((Server_MessageType)opcode)) + size = OpcodeSizes[(Server_MessageType)opcode]; + var serverTime = GetServerTime(); + dataPtr -= 0x20; + + var stream = new UnmanagedMemoryStream((byte*)dataPtr.ToPointer(), size); + var reader = new BinaryReader(stream); + var message = reader.ReadBytes(size); + + if (sourceActorId == 0) // no idea why this happens, probably a Dalamud bug + sourceActorId = targetActorId; // in that case targetActorId seems to be what we actually want + + fixed (byte* ptr = message) // fix up corrupted segment header with what we have + { + Server_MessageHeader* headerPtr = (Server_MessageHeader*)ptr; + headerPtr->MessageLength = (uint)size; + headerPtr->LoginUserID = targetActorId; + headerPtr->ActorID = sourceActorId; + } + + _messageQueue.Enqueue((serverTime, message)); + + reader.Close(); + stream.Close(); + reader.Dispose(); + stream.Dispose(); + } + + public void Disconnect() + { + _tokenSource?.Cancel(); + _tokenSource?.Dispose(); + _tokenSource = null; + + if (GameNetwork is null) + return; + + GameNetwork.NetworkMessage -= GameNetworkOnNetworkMessage; + } + + #region IDisposable + protected virtual void Dispose(bool disposing) + { + Disconnect(); + } + + public void Dispose() + { + // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + #endregion + } +} diff --git a/Machina.FFXIV.Dalamud/Machina.FFXIV.Dalamud.csproj b/Machina.FFXIV.Dalamud/Machina.FFXIV.Dalamud.csproj new file mode 100644 index 0000000..289a023 --- /dev/null +++ b/Machina.FFXIV.Dalamud/Machina.FFXIV.Dalamud.csproj @@ -0,0 +1,46 @@ + + + false + false + true + net8.0-windows + true + enable + enable + x64 + win-x64 + 11 + + + + $(appdata)\XIVLauncher\addon\Hooks\dev\ + true + True + + + + $(DALAMUD_HOME)/ + + + + $(HOME)/Library/Application Support/XIV on Mac/dalamud/Hooks/dev/ + + + + + $(DalamudLibPath)Dalamud.dll + false + + + + + + ..\external_dependencies\SDK\Machina.dll + False + + + ..\external_dependencies\SDK\Machina.FFXIV.dll + False + + + diff --git a/Machina.FFXIV.Dalamud/NotDeucalionClient.cs b/Machina.FFXIV.Dalamud/NotDeucalionClient.cs new file mode 100644 index 0000000..4f96404 --- /dev/null +++ b/Machina.FFXIV.Dalamud/NotDeucalionClient.cs @@ -0,0 +1,63 @@ +using System.Runtime.CompilerServices; + +namespace Machina.FFXIV.Dalamud +{ + public class NotDeucalionClient : IDisposable + { + public delegate void MessageReceivedHandler(byte[] message); + public MessageReceivedHandler? MessageReceived; + + public delegate void MessageSentHandler(byte[] message); + public MessageSentHandler? MessageSent; + + private DalamudClient _dalamudClient; + private static ConditionalWeakTable EpochWeakTable = new ConditionalWeakTable(); + + public NotDeucalionClient() + { + _dalamudClient = new DalamudClient(); + } + + public void OnMessageReceived(long epoch, byte[] message) + { + EpochWeakTable.Add(message, (object)epoch); + MessageReceived?.Invoke(message); + } + + public void Connect(int processId) + { + _dalamudClient.MessageReceived += OnMessageReceived; + _dalamudClient.Connect(); + } + + public void Disconnect() + { + _dalamudClient.MessageReceived -= OnMessageReceived; + _dalamudClient.Disconnect(); + } + + public static (long, byte[]) ConvertDeucalionFormatToPacketFormat(byte[] message) + { + if (!EpochWeakTable.TryGetValue(message, out object epoch)) + { + throw new InvalidOperationException("Message does not have an associated epoch"); + } + return ((long)epoch, message); + } + + #region IDisposable + protected virtual void Dispose(bool disposing) + { + Disconnect(); + _dalamudClient.Dispose(); + } + + public void Dispose() + { + // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + #endregion + } +} diff --git a/Machina.FFXIV.Dalamud/NotDeucalionInjector.cs b/Machina.FFXIV.Dalamud/NotDeucalionInjector.cs new file mode 100644 index 0000000..56e72f9 --- /dev/null +++ b/Machina.FFXIV.Dalamud/NotDeucalionInjector.cs @@ -0,0 +1,32 @@ +namespace Machina.FFXIV.Dalamud +{ + public static class NotDeucalionInjector + { + public static string LastInjectionError + { + get + { + return string.Empty; + } + set + { + // Do nothing + } + } + + public static bool ValidateLibraryChecksum() + { + return true; + } + + public static string ExtractLibrary() + { + return string.Empty; + } + + public static bool InjectLibrary(int processId) + { + return true; + } + } +} diff --git a/Machina.FFXIV.Dalamud/packages.lock.json b/Machina.FFXIV.Dalamud/packages.lock.json new file mode 100644 index 0000000..94646cb --- /dev/null +++ b/Machina.FFXIV.Dalamud/packages.lock.json @@ -0,0 +1,7 @@ +{ + "version": 1, + "dependencies": { + "net8.0-windows7.0": {}, + "net8.0-windows7.0/win-x64": {} + } +} \ No newline at end of file diff --git a/OverlayPlugin.Core/Integration/FFXIVRepository.cs b/OverlayPlugin.Core/Integration/FFXIVRepository.cs index a3517d7..ddd6a06 100644 --- a/OverlayPlugin.Core/Integration/FFXIVRepository.cs +++ b/OverlayPlugin.Core/Integration/FFXIVRepository.cs @@ -335,7 +335,7 @@ public string GetLocaleString() public static Dictionary> GetMachinaOpcodes() => (Dictionary>)typeof(OpcodeManager).GetField( - "_opcodes", BindingFlags.NonPublic | BindingFlags.Instance)!.GetValue(OpcodeManager.Instance); + "_opcodes", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)!.GetValue(OpcodeManager.Instance); public GameRegion GetMachinaRegion() => Machina.FFXIV.Headers.Opcodes.OpcodeManager.Instance.GameRegion; diff --git a/OverlayPlugin.Core/OverlayPlugin.Core.csproj b/OverlayPlugin.Core/OverlayPlugin.Core.csproj index 29e184c..09811e7 100644 --- a/OverlayPlugin.Core/OverlayPlugin.Core.csproj +++ b/OverlayPlugin.Core/OverlayPlugin.Core.csproj @@ -56,8 +56,6 @@ - - @@ -81,6 +79,14 @@ ..\external_dependencies\SDK\FFXIV_ACT_Plugin.Memory.dll + + ..\external_dependencies\SDK\Machina.dll + False + + + ..\external_dependencies\SDK\Machina.FFXIV.dll + False + diff --git a/OverlayPlugin.Core/resources/opcodes.jsonc b/OverlayPlugin.Core/resources/opcodes.jsonc index 8175cd4..bd9b111 100644 --- a/OverlayPlugin.Core/resources/opcodes.jsonc +++ b/OverlayPlugin.Core/resources/opcodes.jsonc @@ -3,42 +3,42 @@ // For more information, see comments on https://github.com/OverlayPlugin/OverlayPlugin/issues/235 { "Chinese": { - "2024.07.19.0000.0000": { - // Version: 6.58 + "2024.09.17.0000.0000": { + // Version: 7.0 "MapEffect": { - "opcode": 140, + "opcode": 401, "size": 11 }, "CEDirector": { - "opcode": 867, + "opcode": 125, "size": 16 }, "RSVData": { - "opcode": 809, + "opcode": 270, "size": 1080 }, "NpcYell": { - "opcode": 254, + "opcode": 971, "size": 32 }, "BattleTalk2": { - "opcode": 810, + "opcode": 561, "size": 40 }, "Countdown": { - "opcode": 144, + "opcode": 712, "size": 48 }, "CountdownCancel": { - "opcode": 518, + "opcode": 762, "size": 40 }, "ActorMove": { - "opcode": 316, + "opcode": 672, "size": 16 }, "ActorSetPos": { - "opcode": 795, + "opcode": 465, "size": 24 } } @@ -85,42 +85,42 @@ } }, "Korean": { - "2024.07.02.0000.0000": { - // Version: 6.57 + "2024.09.11.0000.0000": { + // Version: 6.58 "MapEffect": { - "opcode": 154, + "opcode": 958, "size": 11 }, "CEDirector": { - "opcode": 696, + "opcode": 306, "size": 16 }, "RSVData": { - "opcode": 626, + "opcode": 176, "size": 1080 }, "NpcYell": { - "opcode": 183, + "opcode": 806, "size": 32 }, "BattleTalk2": { - "opcode": 245, + "opcode": 751, "size": 40 }, "Countdown": { - "opcode": 240, + "opcode": 925, "size": 48 }, "CountdownCancel": { - "opcode": 196, + "opcode": 886, "size": 40 }, "ActorMove": { - "opcode": 216, + "opcode": 575, "size": 16 }, "ActorSetPos": { - "opcode": 997, + "opcode": 791, "size": 24 } } diff --git a/external_dependencies/SDK/Machina.FFXIV.dll b/external_dependencies/SDK/Machina.FFXIV.dll new file mode 100644 index 0000000..f180145 Binary files /dev/null and b/external_dependencies/SDK/Machina.FFXIV.dll differ diff --git a/external_dependencies/SDK/Machina.dll b/external_dependencies/SDK/Machina.dll new file mode 100644 index 0000000..afd6417 Binary files /dev/null and b/external_dependencies/SDK/Machina.dll differ diff --git a/machina b/machina deleted file mode 160000 index 46f0efa..0000000 --- a/machina +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 46f0efa6a1fb5d11e3a7e07eb0e7a47e65139f35