Skip to content
Open
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
44 changes: 42 additions & 2 deletions src/XIVLauncher.Common.Unix/Compatibility/CompatibilityTools.cs
Original file line number Diff line number Diff line change
Expand Up @@ -236,14 +236,54 @@ public int GetUnixProcessId(int winePid)
{
var wineDbg = RunInPrefix("winedbg --command \"info procmap\"", redirectOutput: true);
var output = wineDbg.StandardOutput.ReadToEnd();
if (output.Contains("syntax error\n"))
return 0;
if (output.Contains("syntax error\n") || output.Contains("Exception c0000005")) // valve wine changed the error message
{
var processName = GetProcessName(winePid);
return GetUnixProcessIdByName(processName);
}
var matchingLines = output.Split('\n', StringSplitOptions.RemoveEmptyEntries).Skip(1).Where(
l => int.Parse(l.Substring(1, 8), System.Globalization.NumberStyles.HexNumber) == winePid);
var unixPids = matchingLines.Select(l => int.Parse(l.Substring(10, 8), System.Globalization.NumberStyles.HexNumber)).ToArray();
return unixPids.FirstOrDefault();
}

private string GetProcessName(int winePid)
{
var wineDbg = RunInPrefix("winedbg --command \"info proc\"", redirectOutput: true);
var output = wineDbg.StandardOutput.ReadToEnd();
var matchingLines = output.Split('\n', StringSplitOptions.RemoveEmptyEntries).Skip(1).Where(
l => int.Parse(l.Substring(1, 8), System.Globalization.NumberStyles.HexNumber) == winePid);
var processNames = matchingLines.Select(l => l.Substring(20).Trim('\'')).ToArray();
return processNames.FirstOrDefault();
}

private int GetUnixProcessIdByName(string executableName)
{
int closest = 0;
int early = 0;
var currentProcess = Process.GetCurrentProcess(); // Gets XIVLauncher.Core's process
bool nonunique = false;
foreach (var process in Process.GetProcessesByName(executableName))
{
if (process.Id < currentProcess.Id)
{
early = process.Id;
continue; // Process was launched before XIVLauncher.Core
}
// Assume that the closest PID to XIVLauncher.Core's is the correct one. But log an error if more than one is found.
if ((closest - currentProcess.Id) > (process.Id - currentProcess.Id) || closest == 0)
{
if (closest != 0) nonunique = true;
closest = process.Id;
}
if (nonunique) Log.Error($"More than one {executableName} found! Selecting the most likely match with process id {closest}.");
}
// Deal with rare edge-case where pid rollover causes the ffxiv pid to be lower than XLCore's.
if (closest == 0 && early != 0) closest = early;
if (closest != 0) Log.Verbose($"Process for {executableName} found using fallback method: {closest}. XLCore pid: {currentProcess.Id}");
return closest;
}

public string UnixToWinePath(string unixPath)
{
var launchArguments = new string[] { "winepath", "--windows", unixPath };
Expand Down
31 changes: 23 additions & 8 deletions src/XIVLauncher.Common.Unix/UnixDalamudRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,28 @@ public UnixDalamudRunner(CompatibilityTools compatibility, DirectoryInfo dotnetR
launchArguments.Add(gameArgs);

var dalamudProcess = compatibility.RunInPrefix(string.Join(" ", launchArguments), environment: environment, redirectOutput: true, writeLog: true);
var output = dalamudProcess.StandardOutput.ReadLine();

if (output == null)
throw new DalamudRunnerException("An internal Dalamud error has occured");
DalamudConsoleOutput dalamudConsoleOutput = null;
int invalidJsonCount = 0;

Console.WriteLine(output);
// Keep checking for valid json output, but only 5 times. If it's still erroring out at that point, give up.
while (dalamudConsoleOutput == null && invalidJsonCount < 5)
{
var output = dalamudProcess.StandardOutput.ReadLine();
if (output == null)
throw new DalamudRunnerException("An internal Dalamud error has occured");
Console.WriteLine(output);

try
{
dalamudConsoleOutput = JsonConvert.DeserializeObject<DalamudConsoleOutput>(output);
}
catch (Exception ex)
{
Log.Warning(ex, $"Couldn't parse Dalamud output: {output}");
}
invalidJsonCount++;
}

new Thread(() =>
{
Expand All @@ -94,22 +110,21 @@ public UnixDalamudRunner(CompatibilityTools compatibility, DirectoryInfo dotnetR

try
{
var dalamudConsoleOutput = JsonConvert.DeserializeObject<DalamudConsoleOutput>(output);
var unixPid = compatibility.GetUnixProcessId(dalamudConsoleOutput.Pid);

if (unixPid == 0)
{
Log.Error("Could not retrive Unix process ID, this feature currently requires a patched wine version");
Log.Error("Could not retrieve Unix process ID");
return null;
}

var gameProcess = Process.GetProcessById(unixPid);
Log.Verbose($"Got game process handle {gameProcess.Handle} with Unix pid {gameProcess.Id} and Wine pid {dalamudConsoleOutput.Pid}");
return gameProcess;
}
catch (JsonReaderException ex)
catch (Exception ex)
{
Log.Error(ex, $"Couldn't parse Dalamud output: {output}");
Log.Error(ex, $"Could not retrieve game Process information");
return null;
}
}
Expand Down
Loading