Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Patch and use the Machina library bundled in FFXIV_ACT_Plugin #77

Closed
wants to merge 9 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -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
4 changes: 3 additions & 1 deletion FetchDependencies/Costura.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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";
}

Expand Down
8 changes: 6 additions & 2 deletions FetchDependencies/FetchDependencies.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.IO.Compression;
using Dalamud.Plugin.Services;

namespace FetchDependencies;

Expand All @@ -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()
Expand Down Expand Up @@ -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)
Expand Down
7 changes: 7 additions & 0 deletions FetchDependencies/FetchDependencies.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@
<DalamudLibPath>$(HOME)/Library/Application Support/XIV on Mac/dalamud/Hooks/dev/</DalamudLibPath>
</PropertyGroup>

<ItemGroup>
<Reference Include="Dalamud">
<HintPath>$(DalamudLibPath)Dalamud.dll</HintPath>
<Private>false</Private>
</Reference>
</ItemGroup>

<ItemGroup>
<Reference Include="Mono.Cecil">
<HintPath>$(DalamudLibPath)Mono.Cecil.dll</HintPath>
Expand Down
113 changes: 112 additions & 1 deletion FetchDependencies/Patcher.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Dalamud.Plugin.Services;
using Mono.Cecil;
using Mono.Cecil.Cil;

Expand All @@ -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()
Expand Down Expand Up @@ -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<string, TypeDefinition>
{
{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();
}
}
4 changes: 0 additions & 4 deletions IINACT.sln
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
11 changes: 9 additions & 2 deletions IINACT/IINACT.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,9 @@

<ItemGroup>
<ProjectReference Include="..\FetchDependencies\FetchDependencies.csproj" />
<ProjectReference Include="..\machina\Machina.FFXIV\Machina.FFXIV.csproj" />
<ProjectReference Include="..\machina\Machina\Machina.csproj" />
<ProjectReference Include="..\NotACT\NotACT.csproj" />
<ProjectReference Include="..\OverlayPlugin.Core\OverlayPlugin.Core.csproj" />
<ProjectReference Include="..\Machina.FFXIV.Dalamud\Machina.FFXIV.Dalamud.csproj" />
</ItemGroup>

<ItemGroup>
Expand Down Expand Up @@ -109,6 +108,14 @@
<HintPath>..\external_dependencies\SDK\FFXIV_ACT_Plugin.Resource.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Machina">
<HintPath>..\external_dependencies\SDK\Machina.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Machina.FFXIV">
<HintPath>..\external_dependencies\SDK\Machina.FFXIV.dll</HintPath>
<Private>False</Private>
</Reference>
</ItemGroup>

<ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion IINACT/Plugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down
142 changes: 67 additions & 75 deletions IINACT/packages.lock.json
Original file line number Diff line number Diff line change
@@ -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=="
}
}
}
}
Loading
Loading