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

Add support for local dalamud injection #122

Merged
merged 2 commits into from
Mar 6, 2024
Merged
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
21 changes: 10 additions & 11 deletions src/XIVLauncher.Core/Components/MainPage/MainPage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -202,9 +202,8 @@ public async Task<bool> Login(string username, string password, bool isOtp, bool

private async Task<Launcher.LoginResult> TryLoginToGame(string username, string password, string otp, bool isSteam, LoginAction action)
{
bool? gateStatus = null;

#if !DEBUG
bool? gateStatus = null;
try
{
// TODO: Also apply the login status fix here
Expand Down Expand Up @@ -339,7 +338,7 @@ private async Task<bool> TryProcessLoginResult(Launcher.LoginResult loginResult,

return false;
}

#if !DEBUG
bool? gateStatus = null;
try
Expand Down Expand Up @@ -689,7 +688,7 @@ public async Task<Process> StartGameAndAddon(Launcher.LoginResult loginResult, b
System.Environment.SetEnvironmentVariable("LC_ALL", Program.CType);
System.Environment.SetEnvironmentVariable("LC_CTYPE", Program.CType);
}

// Hack: Strip out gameoverlayrenderer.so entries from LD_PRELOAD
if (App.Settings.FixLDP.Value)
{
Expand All @@ -711,7 +710,7 @@ public async Task<Process> StartGameAndAddon(Launcher.LoginResult loginResult, b
// If there's only one launch option (no %command%) figure out whether it's args or env variables.
if (launchOptions.Length == 1)
{
if(launchOptions[0].StartsWith('-'))
if (launchOptions[0].StartsWith('-'))
gameArgs = launchOptions[0];
else
launchEnv = launchOptions[0];
Expand Down Expand Up @@ -750,7 +749,7 @@ public async Task<Process> StartGameAndAddon(Launcher.LoginResult loginResult, b
else if (!Directory.Exists(App.Settings.WineBinaryPath))
throw new Exception("Custom wine binary path is invalid: no such directory.\n" +
"Check path carefully for typos: " + App.Settings.WineBinaryPath);
else if (!File.Exists(Path.Combine(App.Settings.WineBinaryPath,"wine64")))
else if (!File.Exists(Path.Combine(App.Settings.WineBinaryPath, "wine64")))
throw new Exception("Custom wine binary path is invalid: no wine64 found at that location.\n" +
"Check path carefully for typos: " + App.Settings.WineBinaryPath);
}
Expand Down Expand Up @@ -1202,11 +1201,11 @@ private async Task<bool> RepairGame(Launcher.LoginResult loginResult)
case PatchVerifier.VerifyState.Done:
// TODO: ask the user if they want to login or rerun after repair
App.ShowMessageBlocking(verify.NumBrokenFiles switch
{
0 => Loc.Localize("GameRepairSuccess0", "All game files seem to be valid."),
1 => Loc.Localize("GameRepairSuccess1", "XIVLauncher has successfully repaired 1 game file."),
_ => string.Format(Loc.Localize("GameRepairSuccessPlural", "XIVLauncher has successfully repaired {0} game files."), verify.NumBrokenFiles),
});
{
0 => Loc.Localize("GameRepairSuccess0", "All game files seem to be valid."),
1 => Loc.Localize("GameRepairSuccess1", "XIVLauncher has successfully repaired 1 game file."),
_ => string.Format(Loc.Localize("GameRepairSuccessPlural", "XIVLauncher has successfully repaired {0} game files."), verify.NumBrokenFiles),
});

doVerify = false;
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,57 @@ namespace XIVLauncher.Core.Components.SettingsPage.Tabs;

public class SettingsTabDalamud : SettingsTab
{
public override SettingsEntry[] Entries { get; } = {
new SettingsEntry<bool>("Enable Dalamud", "Enable the Dalamud plugin system", () => Program.Config.DalamudEnabled ?? true, b => Program.Config.DalamudEnabled = b),
public override string Title => "Dalamud";
public override SettingsEntry[] Entries { get; }
private SettingsEntry<bool> enableManualInjection;

new SettingsEntry<DalamudLoadMethod>("Load Method", "Choose how Dalamud is loaded.", () => Program.Config.DalamudLoadMethod ?? DalamudLoadMethod.DllInject, method => Program.Config.DalamudLoadMethod = method)
public SettingsTabDalamud()
{
this.Entries = new SettingsEntry[]
{
CheckValidity = x =>
{
if (x == DalamudLoadMethod.EntryPoint && !OperatingSystem.IsWindows())
return "Entry point injection is only supported on Windows.";

return null;
},
},
new SettingsEntry<bool>("Enable Dalamud", "Enable the Dalamud plugin system", () => Program.Config.DalamudEnabled ?? true, b => Program.Config.DalamudEnabled = b),

new NumericSettingsEntry("Injection Delay (ms)", "Choose how long to wait after the game has loaded before injecting.", () => Program.Config.DalamudLoadDelay, delay => Program.Config.DalamudLoadDelay = delay, 0, int.MaxValue, 1000),
};
new SettingsEntry<DalamudLoadMethod>("Load Method", "Choose how Dalamud is loaded.", () => Program.Config.DalamudLoadMethod ?? DalamudLoadMethod.DllInject, method => Program.Config.DalamudLoadMethod = method),

public override string Title => "Dalamud";
new NumericSettingsEntry("Injection Delay (ms)", "Choose how long to wait after the game has loaded before injecting.", () => Program.Config.DalamudLoadDelay, delay => Program.Config.DalamudLoadDelay = delay, 0, int.MaxValue, 1000),

enableManualInjection = new SettingsEntry<bool>("Enable Manual Injection", "Use a local build of Dalamud instead of the automatically provided one (For developers only!)", () => Program.Config.DalamudManualInjectionEnabled ?? false, (enabled) =>
{
Program.Config.DalamudManualInjectionEnabled = enabled;

if (!enabled)
{
Program.DalamudUpdater.RunnerOverride = null;
return;
}

if (Directory.Exists(Program.Config.DalamudManualInjectPath) && Directory.GetFiles(Program.Config.DalamudManualInjectPath).FirstOrDefault(x => x == "Dalamud.Injector.exe") is not null)
{
Program.DalamudUpdater.RunnerOverride = new FileInfo(Path.Combine(Program.Config.DalamudManualInjectPath, Program.DALAMUD_INJECTOR_NAME));
}
}),

new SettingsEntry<string>("Manual Injection Path", "The path to the local version of Dalamud where Dalamud.Injector.exe is located", () => Program.Config.DalamudManualInjectPath, (input) =>
{
Program.Config.DalamudManualInjectPath = input;
Program.DalamudUpdater.RunnerOverride = new FileInfo(Path.Combine(input, Program.DALAMUD_INJECTOR_NAME));
})
{
CheckVisibility = () => enableManualInjection.Value == true,
CheckValidity = input =>
{
if (!Directory.Exists(input))
{
return "There is no directory at that path.";
}
if (Directory.GetFiles(input).FirstOrDefault(x => x == Program.DALAMUD_INJECTOR_NAME) is not null)
{
return "Dalamud.Injector.exe was not found inside of the provided directory.";
}
return null;
},
},
};
}
}
2 changes: 2 additions & 0 deletions src/XIVLauncher.Core/Configuration/ILauncherConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ public interface ILauncherConfig
public bool? DalamudEnabled { get; set; }

public DalamudLoadMethod? DalamudLoadMethod { get; set; }
public bool? DalamudManualInjectionEnabled { get; set; }
public string? DalamudManualInjectPath { get; set; }

public int DalamudLoadDelay { get; set; }

Expand Down
81 changes: 54 additions & 27 deletions src/XIVLauncher.Core/Program.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System.Numerics;
using System.IO;
using CheapLoc;
using Config.Net;
using ImGuiNET;
Expand Down Expand Up @@ -59,7 +58,7 @@ class Program

private const string APP_NAME = "xlcore";

private static string[] mainargs;
private static string[] mainArgs;

private static uint invalidationFrames = 0;
private static Vector2 lastMousePosition;
Expand Down Expand Up @@ -114,7 +113,7 @@ private static void LoadConfig(Storage storage)
Config.PatchAcquisitionMethod ??= AcquisitionMethod.Aria;

Config.DalamudEnabled ??= true;
Config.DalamudLoadMethod = !OperatingSystem.IsWindows() ? DalamudLoadMethod.DllInject : DalamudLoadMethod.EntryPoint;
Config.DalamudLoadMethod ??= DalamudLoadMethod.EntryPoint;

Config.GlobalScale ??= 1.0f;

Expand All @@ -136,9 +135,43 @@ private static void LoadConfig(Storage storage)
public const uint STEAM_APP_ID = 39210;
public const uint STEAM_APP_ID_FT = 312060;

/// <summary>
/// The name of the Dalamud injector executable file.
/// </summary>
// TODO: move this somewhere better.
public const string DALAMUD_INJECTOR_NAME = "Dalamud.Injector.exe";

/// <summary>
/// Creates a new instance of the Dalamud updater.
/// </summary>
/// <remarks>
/// If <see cref="ILauncherConfig.DalamudManualInjectionEnabled"/> is true and there is an injector at <see cref="ILauncherConfig.DalamudManualInjectPath"/> then
/// manual injection will be used instead of a Dalamud branch.
/// </remarks>
/// <returns>A <see cref="DalamudUpdater"/> instance.</returns>
private static DalamudUpdater CreateDalamudUpdater()
{
if (Config.DalamudManualInjectionEnabled == true &&
Directory.Exists(Config.DalamudManualInjectPath) &&
Directory.GetFiles(Config.DalamudManualInjectPath).FirstOrDefault(f => f == DALAMUD_INJECTOR_NAME) is not null)
{
var updater = new DalamudUpdater(new DirectoryInfo(Config.DalamudManualInjectPath), storage.GetFolder("runtime"), storage.GetFolder("dalamudAssets"), storage.Root, null, null)
{
Overlay = DalamudLoadInfo,
};
DalamudUpdater.RunnerOverride = new FileInfo(Path.Combine(Config.DalamudManualInjectPath, DALAMUD_INJECTOR_NAME));
return updater;
}

return new DalamudUpdater(storage.GetFolder("dalamud"), storage.GetFolder("runtime"), storage.GetFolder("dalamudAssets"), storage.Root, null, null)
{
Overlay = DalamudLoadInfo,
};
}

private static void Main(string[] args)
{
mainargs = args;
mainArgs = args;
storage = new Storage(APP_NAME);

if (CoreEnvironmentSettings.ClearAll)
Expand All @@ -153,8 +186,8 @@ private static void Main(string[] args)
if (CoreEnvironmentSettings.ClearTools) ClearTools();
if (CoreEnvironmentSettings.ClearLogs) ClearLogs();
}
SetupLogging(mainargs);

SetupLogging(mainArgs);
LoadConfig(storage);

Secrets = GetSecretProvider(storage);
Expand Down Expand Up @@ -210,11 +243,9 @@ private static void Main(string[] args)
Log.Error(ex, "Steam couldn't load");
}

// Manual or auto injection setup.
DalamudLoadInfo = new DalamudOverlayInfoProxy();
DalamudUpdater = new DalamudUpdater(storage.GetFolder("dalamud"), storage.GetFolder("runtime"), storage.GetFolder("dalamudAssets"), storage.Root, null, null)
{
Overlay = DalamudLoadInfo
};
DalamudUpdater = CreateDalamudUpdater();
DalamudUpdater.Run();

CreateCompatToolsInstance();
Expand Down Expand Up @@ -354,17 +385,17 @@ private static ISecretProvider GetSecretProvider(Storage storage)
return new FileSecretProvider(storage.GetFile(secretsFilePath));

case "KEYRING":
{
var keyChain = new KeychainSecretProvider();

if (!keyChain.IsAvailable)
{
Log.Error("An org.freedesktop.secrets provider is not available - no secrets will be stored");
return new DummySecretProvider();
}
var keyChain = new KeychainSecretProvider();

return keyChain;
}
if (!keyChain.IsAvailable)
{
Log.Error("An org.freedesktop.secrets provider is not available - no secrets will be stored");
return new DummySecretProvider();
}

return keyChain;
}

case "NONE":
return new DummySecretProvider();
Expand Down Expand Up @@ -405,10 +436,7 @@ public static void ClearPlugins(bool tsbutton = false)
if (tsbutton)
{
DalamudLoadInfo = new DalamudOverlayInfoProxy();
DalamudUpdater = new DalamudUpdater(storage.GetFolder("dalamud"), storage.GetFolder("runtime"), storage.GetFolder("dalamudAssets"), storage.Root, null, null)
{
Overlay = DalamudLoadInfo
};
DalamudUpdater = CreateDalamudUpdater();
DalamudUpdater.Run();
}
}
Expand All @@ -425,14 +453,13 @@ public static void ClearLogs(bool tsbutton = false)
{
storage.GetFolder("logs").Delete(true);
storage.GetFolder("logs");
string[] logfiles = { "dalamud.boot.log", "dalamud.boot.old.log", "dalamud.log", "dalamud.injector.log"};
string[] logfiles = { "dalamud.boot.log", "dalamud.boot.old.log", "dalamud.log", "dalamud.injector.log" };
foreach (string logfile in logfiles)
if (storage.GetFile(logfile).Exists) storage.GetFile(logfile).Delete();
if (tsbutton)
SetupLogging(mainargs);

}
SetupLogging(mainArgs);

}
public static void ClearAll(bool tsbutton = false)
{
ClearSettings(tsbutton);
Expand Down
53 changes: 36 additions & 17 deletions src/XIVLauncher.Core/XIVLauncher.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,20 @@
<PublishSingleFile>true</PublishSingleFile>
<!-- <SelfContained>true</SelfContained> -->

<IsWindows Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Windows)))' == 'true'">true</IsWindows>
<IsOSX Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::OSX)))' == 'true'">true</IsOSX>
<IsLinux Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Linux)))' == 'true'">true</IsLinux>
<IsWindows
Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Windows)))' == 'true'">
true</IsWindows>
<IsOSX
Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::OSX)))' == 'true'">
true</IsOSX>
<IsLinux
Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Linux)))' == 'true'">
true</IsLinux>
</PropertyGroup>

<PropertyGroup>
<DefineConstants Condition=" '$(ExtraDefineConstants)' != '' ">$(DefineConstants);$(ExtraDefineConstants)</DefineConstants>
<DefineConstants Condition=" '$(ExtraDefineConstants)' != '' ">
$(DefineConstants);$(ExtraDefineConstants)</DefineConstants>
</PropertyGroup>

<PropertyGroup Condition="'$(IsWindows)'=='true'">
Expand All @@ -42,10 +49,14 @@
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="../XIVLauncher.VersionGenerator/XIVLauncher.VersionGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
<ProjectReference Include="..\..\lib\FFXIVQuickLauncher\src\XIVLauncher.Common.Unix\XIVLauncher.Common.Unix.csproj" />
<ProjectReference Include="..\..\lib\FFXIVQuickLauncher\src\XIVLauncher.Common.Windows\XIVLauncher.Common.Windows.csproj" />
<ProjectReference Include="..\..\lib\FFXIVQuickLauncher\src\XIVLauncher.Common\XIVLauncher.Common.csproj" />
<ProjectReference Include="../XIVLauncher.VersionGenerator/XIVLauncher.VersionGenerator.csproj"
OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
<ProjectReference
Include="..\..\lib\FFXIVQuickLauncher\src\XIVLauncher.Common.Unix\XIVLauncher.Common.Unix.csproj" />
<ProjectReference
Include="..\..\lib\FFXIVQuickLauncher\src\XIVLauncher.Common.Windows\XIVLauncher.Common.Windows.csproj" />
<ProjectReference
Include="..\..\lib\FFXIVQuickLauncher\src\XIVLauncher.Common\XIVLauncher.Common.csproj" />
</ItemGroup>

<ItemGroup>
Expand All @@ -72,17 +83,22 @@
<ItemGroup>
<EmbeddedResource Include="Shaders/GLSL/imgui-vertex.glsl" LogicalName="imgui-vertex.glsl" />
<EmbeddedResource Include="Shaders/GLSL/imgui-frag.glsl" LogicalName="imgui-frag.glsl" />
<EmbeddedResource Include="Shaders/HLSL/imgui-vertex.hlsl.bytes" LogicalName="imgui-vertex.hlsl.bytes" />
<EmbeddedResource Include="Shaders/HLSL/imgui-frag.hlsl.bytes" LogicalName="imgui-frag.hlsl.bytes" />
<EmbeddedResource Include="Shaders/HLSL/imgui-vertex.hlsl.bytes"
LogicalName="imgui-vertex.hlsl.bytes" />
<EmbeddedResource Include="Shaders/HLSL/imgui-frag.hlsl.bytes"
LogicalName="imgui-frag.hlsl.bytes" />
<EmbeddedResource Include="Shaders/SPIR-V/imgui-vertex.spv" LogicalName="imgui-vertex.spv" />
<EmbeddedResource Include="Shaders/SPIR-V/imgui-frag.spv" LogicalName="imgui-frag.spv" />
<EmbeddedResource Include="Shaders/Metal/imgui-vertex.metallib" LogicalName="imgui-vertex.metallib" />
<EmbeddedResource Include="Shaders/Metal/imgui-vertex.metallib"
LogicalName="imgui-vertex.metallib" />
<EmbeddedResource Include="Shaders/Metal/imgui-frag.metallib" LogicalName="imgui-frag.metallib" />
</ItemGroup>

<ItemGroup>
<EmbeddedResource Include="Resources/FontAwesome5FreeSolid.otf" LogicalName="FontAwesome5FreeSolid.otf" />
<EmbeddedResource Include="Resources/NotoSansCJKjp-Regular.otf" LogicalName="NotoSansCJKjp-Regular.otf" />
<EmbeddedResource Include="Resources/FontAwesome5FreeSolid.otf"
LogicalName="FontAwesome5FreeSolid.otf" />
<EmbeddedResource Include="Resources/NotoSansCJKjp-Regular.otf"
LogicalName="NotoSansCJKjp-Regular.otf" />

<EmbeddedResource Include="Resources/logo.png" LogicalName="logo.png" />

Expand All @@ -91,7 +107,8 @@

<EmbeddedResource Include="Resources/steamdeck_fts.png" LogicalName="steamdeck_fts.png" />
<EmbeddedResource Include="Resources/steamdeck_fterror.png" LogicalName="steamdeck_fterror.png" />
<EmbeddedResource Include="Resources/steamdeck_switchprompt.png" LogicalName="steamdeck_switchprompt.png" />
<EmbeddedResource Include="Resources/steamdeck_switchprompt.png"
LogicalName="steamdeck_switchprompt.png" />
<EmbeddedResource Include="Resources/xlcore_updatewarn.png" LogicalName="xlcore_updatewarn.png" />
</ItemGroup>

Expand All @@ -109,7 +126,8 @@
<VerFile>$(IntermediateOutputPath)gitver</VerFile>
</PropertyGroup>
<!-- write the hash to the temp file.-->
<Exec Command="git -C &quot;$(ProjectDir.Replace('\','\\'))&quot; describe --long --always --dirty &gt; $(VerFile)" />
<Exec
Command="git -C &quot;$(ProjectDir.Replace('\','\\'))&quot; describe --long --always --dirty &gt; $(VerFile)" />
<!-- read the version into the GitVersion itemGroup-->
<ReadLinesFromFile File="$(VerFile)">
<Output TaskParameter="Lines" ItemName="GitVersion" />
Expand Down Expand Up @@ -141,7 +159,8 @@
</AssemblyAttributes>
</ItemGroup>
<!-- writes the attribute to the customAssemblyInfo file -->
<WriteCodeFragment Language="C#" OutputFile="$(CustomAssemblyInfoFile)" AssemblyAttributes="@(AssemblyAttributes)" />
<WriteCodeFragment Language="C#" OutputFile="$(CustomAssemblyInfoFile)"
AssemblyAttributes="@(AssemblyAttributes)" />
</Target>

</Project>
</Project>
Loading