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