diff --git a/ServerSelector/PathUtil.cs b/ServerSelector/PathUtil.cs
new file mode 100644
index 0000000..f384fb5
--- /dev/null
+++ b/ServerSelector/PathUtil.cs
@@ -0,0 +1,99 @@
+using System;
+using System.IO;
+
+namespace ServerSelector;
+
+public class PathUtil
+{
+ public bool LauncherExists { get; private set; }
+ public string? LauncherBasePath { get; set; }
+ public string GameBasePath { get; set; }
+ public string? SystemHostsFile
+ {
+ get
+ {
+ if (OperatingSystem.IsWindows())
+ {
+ return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "Drivers\\etc\\hosts");
+ }
+ else if (OperatingSystem.IsLinux())
+ {
+ return "/etc/hosts";
+ }
+ else throw new NotImplementedException("Unsupported operating system");
+ }
+ }
+
+ public string? WineHostsFile => GameBasePath + "../../wine_prefix/drive_c/windows/system32/drivers/etc/hosts";
+
+ public string? LauncherCertificatePath
+ {
+ get
+ {
+ if (LauncherBasePath == null) return null;
+
+ string path = Path.Combine(LauncherBasePath, "intl_service/intl_cacert.pem");
+
+ if (!File.Exists(path))
+ {
+ // Older game/SDK version
+ path = Path.Combine(LauncherBasePath, "intl_service/cacert.pem");
+ }
+ return path;
+ }
+ }
+
+ public string GamePluginsDirectory => Path.Combine(GameBasePath ?? throw new InvalidOperationException("Game path not assigned"), "nikke_Data/Plugins/x86_64/");
+ public string? GameCertificatePath
+ {
+ get
+ {
+ string path = Path.Combine(GamePluginsDirectory, "intl_cacert.pem");
+
+ if (!File.Exists(path))
+ {
+ // Older game/SDK version
+ path = Path.Combine(GamePluginsDirectory, "cacert.pem");
+ }
+
+ return path;
+ }
+ }
+
+ public string? GameSodiumPath => Path.Combine(GamePluginsDirectory, "sodium.dll");
+ public string? GameSodiumBackupPath => Path.Combine(GamePluginsDirectory, "sodium.dll.bak");
+
+ ///
+ /// Sets the directory where the (game name) and Launcher directories are located
+ ///
+ /// directory where the (game name) and Launcher directories are located
+ /// Return (bool, string) where if the operation is successful, true is returned. If it fails, the string contains more details.
+ public (bool, string?) SetBasePath(string basePath)
+ {
+ GameBasePath = Path.Combine(basePath, "NIKKE", "game");
+ LauncherBasePath = Path.Combine(basePath, "Launcher");
+
+ // Various sanity checks
+ if (!Directory.Exists(GameBasePath))
+ {
+ return (false, $"Directory \"{GameBasePath}\" does not exist");
+ }
+
+ LauncherExists = Directory.Exists(LauncherBasePath);
+
+ if (LauncherExists)
+ {
+ if (!File.Exists(Path.Combine(LauncherBasePath, "nikke_launcher.exe")))
+ {
+ return (false, "Game path is invalid. Make sure that nikke_launcher.exe exists in the /launcher folder");
+ }
+ }
+
+ if (!File.Exists(GameCertificatePath))
+ {
+ return (false, $"Path is invalid. File \"{GameCertificatePath}\" does not exist.");
+ }
+
+ return (true, null);
+ }
+}
diff --git a/ServerSelector/SearchReplace.cs b/ServerSelector/SearchReplace.cs
deleted file mode 100644
index fdb6f96..0000000
--- a/ServerSelector/SearchReplace.cs
+++ /dev/null
@@ -1,164 +0,0 @@
-// From: https://github.com/Ninka-Rex/CSharp-Search-and-Replace/blob/main/SearchReplace.cs
-
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-
-namespace ServerSelector;
-
-public static class PatchUtility
-{
- public static bool CanFindOffset(string filePath, string[] searchPatterns)
- {
- // Check if the file exists
- if (!File.Exists(filePath)) { Console.WriteLine("[ERROR] File not found: " + filePath); return false; }
-
- // Read the binary data from the file as an array of bytes
- byte[] fileData = File.ReadAllBytes(filePath);
-
- for (int k = 0; k < searchPatterns.Length; k++)
- {
- // Convert the hexadecimal strings to byte arrays using a helper method
- byte[] searchBytes = HexStringToBytes(searchPatterns[k]);
-
- // Find the index of the first occurrence of the search pattern in the file data using another helper method
- List results = FindPatternIndex(fileData, searchBytes);
- if (results.Count <= 1) return false;
-
- Console.WriteLine("offset: " + results[1].ToString("X"));
-
- // If the index is -1, it means the pattern was not found, so we return false and log an error message
- if (results[1] == -1)
- {
- Console.WriteLine("[ERROR] Search pattern not found: " + searchPatterns[k]);
- return false;
- }
- }
- return true;
- }
- // This method searches and replaces binary patterns in a given file
- // It takes three parameters:
- // - filePath: the path of the file to be patched
- // - searchPatterns: an array of hexadecimal strings representing the patterns to be searched for
- // - replacePatterns: an array of hexadecimal strings representing the patterns to be replaced with
- // It returns true if the patching was successful, or false if there was an error or a pattern was not found
- public static bool SearchAndReplace(string filePath, string[] searchPatterns, string[] replacePatterns)
- {
- try
- {
- // Check if the file exists
- if (!File.Exists(filePath)) { Console.WriteLine("[ERROR] File not found: " + filePath); return false; }
-
- // Read the binary data from the file as an array of bytes
- byte[] fileData = File.ReadAllBytes(filePath);
-
- // Backup the original file by copying it to a new file with a .bak extension
- string backupFilePath = filePath + ".bak";
- if (!File.Exists(backupFilePath))
- {
- File.Copy(filePath, backupFilePath);
- }
-
- // Loop through each pair of search and replace patterns and apply them to the file data
- for (int k = 0; k < searchPatterns.Length; k++)
- {
- // Convert the hexadecimal strings to byte arrays using a helper method
- byte[] searchBytes = HexStringToBytes(searchPatterns[k]);
- byte[] replaceBytes = HexStringToBytes(replacePatterns[k]);
-
- // Find the index of the first occurrence of the search pattern in the file data using another helper method
-
- // Note: game versions 124 - 133 have 2 matches, 2nd one is the correct one
- // game version 134 - ? has 1 match which is correct
- int index = -1;
- List indexes = FindPatternIndex(fileData, searchBytes);
- if (indexes.Count == 1)
- index = indexes[0];
- else index = indexes[1];
-
- Console.WriteLine("Found offset: " + index.ToString("X"));
-
- // If the index is -1, it means the pattern was not found, so we return false and log an error message
- if (index == -1)
- {
- Console.WriteLine("[ERROR] Search pattern not found: " + searchPatterns[k]);
- return false;
- }
-
- // Replace the pattern at the found index with the replace pattern, preserving original values when wildcards are encountered
- // A wildcard is represented by either 00 or FF in the replace pattern, meaning that we keep the original value at that position
- for (int i = 0; i < replaceBytes.Length; i++)
- {
- if (replaceBytes[i] != 0x00 && replaceBytes[i] != 0xFF)
- {
- fileData[index + i] = replaceBytes[i];
- }
- else if (replaceBytes[i] == 0x00)
- {
- fileData[index + i] = 0x00;
- }
- }
-
- // Log a success message with the offset and file name where the patch was applied
- string exeName = Path.GetFileName(filePath);
- Console.WriteLine($"[Patch] Apply patch success at 0x{index:X} in {exeName}");
- }
-
- // Write the modified data back to the file, overwriting the original content
- File.WriteAllBytes(filePath, fileData);
-
- return true;
- }
- catch (Exception ex)
- {
- // If any exception occurs during the patching process, we return false and log an error message with the exception details
- Console.WriteLine("[ERROR] An error occurred while writing the file: " + ex.Message);
- return false;
- }
- }
-
- // This helper method converts a hexadecimal string to a byte array
- // It takes one parameter:
- // - hex: a string of hexadecimal digits, optionally separated by spaces or question marks
- // It returns a byte array corresponding to the hexadecimal values in the string
- private static byte[] HexStringToBytes(string hex)
- {
- hex = hex.Replace(" ", "").Replace("??", "FF"); // Replace ?? with FF for wildcards
- return [.. Enumerable.Range(0, hex.Length)
- .Where(x => x % 2 == 0) // Take every second character in the string
- .Select(x => Convert.ToByte(hex.Substring(x, 2), 16))]; // Convert the result to an array of bytes
- }
-
- // This helper method finds the index of the first occurrence of a pattern in a data array
- // It takes two parameters:
- // - data: an array of bytes representing the data to be searched in
- // - pattern: an array of bytes representing the pattern to be searched for
- // It returns an integer representing the index where the pattern was found, or -1 if it was not found
- private static List FindPatternIndex(byte[] data, byte[] pattern)
- {
- List points = [];
- // Loop through each possible position in the data array where the pattern could start
- for (int i = 0; i < data.Length - pattern.Length + 1; i++)
- {
- bool found = true; // Assume that the pattern is found until proven otherwise
- // Loop through each byte in the pattern and compare it with the corresponding byte in the data array
- for (int j = 0; j < pattern.Length; j++)
- {
- // If the pattern byte is not FF (wildcard) and it does not match the data byte, then the pattern is not found at this position
- if (pattern[j] != 0xFF && data[i + j] != pattern[j])
- {
- found = false;
- break;
- }
- }
- // If the pattern was found at this position, return the index
- if (found)
- {
- points.Add(i);
- }
- }
- // If the pattern was not found in the entire data array, return -1
- return points;
- }
-}
\ No newline at end of file
diff --git a/ServerSelector/ServerSwitcher.cs b/ServerSelector/ServerSwitcher.cs
index b438272..3ba0b1f 100644
--- a/ServerSelector/ServerSwitcher.cs
+++ b/ServerSelector/ServerSwitcher.cs
@@ -4,210 +4,174 @@ using System.IO;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
-namespace ServerSelector
+namespace ServerSelector;
+
+public class ServerSwitcher
{
- public class ServerSwitcher
+ private const string HostsStartMarker = "# begin ServerSelector entries";
+ private const string HostsEndMarker = "# end ServerSelector entries";
+
+ private static PathUtil util = new();
+
+ public static bool IsUsingLocalServer()
{
- private const string HostsStartMarker = "# begin ServerSelector entries";
- private const string HostsEndMarker = "# end ServerSelector entries";
+ return File.ReadAllText(util.SystemHostsFile).Contains("global-lobby.nikke-kr.com");
+ }
- public static bool IsUsingOfficalServer()
+ public static bool IsOffline()
+ {
+ return File.ReadAllText(util.SystemHostsFile).Contains("cloud.nikke-kr.com");
+ }
+
+ public static (bool, string?) SetBasePath(string basePath)
+ {
+ return util.SetBasePath(basePath);
+ }
+
+ public static async Task CheckIntegrity()
+ {
+ if (!IsUsingLocalServer())
+ return "Official server";
+
+ if (File.Exists(util.LauncherCertificatePath))
{
- string hostsFile = File.ReadAllText(OperatingSystem.IsWindows() ? "C:\\Windows\\System32\\drivers\\etc\\hosts" : "/etc/hosts");
- return !hostsFile.Contains("global-lobby.nikke-kr.com");
+ string certList1 = await File.ReadAllTextAsync(util.LauncherCertificatePath);
+
+ if (!certList1.Contains("Good SSL Ca"))
+ return "SSL Cert Patch missing Launcher";
}
- public static bool IsOffline()
+ if (File.Exists(util.GameCertificatePath))
{
- string hostsFile = File.ReadAllText(OperatingSystem.IsWindows() ? "C:\\Windows\\System32\\drivers\\etc\\hosts" : "/etc/hosts");
- return hostsFile.Contains("cloud.nikke-kr.com");
+ string certList2 = await File.ReadAllTextAsync(util.GameCertificatePath);
+
+ if (!certList2.Contains("Good SSL Ca"))
+ return "SSL Cert Patch missing Game";
}
- public static async Task CheckIntegrity(string gamePath, string launcherPath)
+ // TODO: Check sodium lib
+ // TODO: check hosts file
+
+ return "OK";
+ }
+
+ public static async Task RevertHostsFile(string hostsFilePath)
+ {
+ string txt = await File.ReadAllTextAsync(hostsFilePath);
+
+ // remove stuff
+ try
{
- if (IsUsingOfficalServer())
- return "Official server";
- if (!Directory.Exists(gamePath))
+ int startIdx = txt.IndexOf(HostsStartMarker);
+ int endIdx;
+ if (startIdx == -1)
{
- return "Game path does not exist";
+ startIdx = txt.IndexOf("cloud.nikke-kr.com");
}
- if (!Directory.Exists(launcherPath))
+ string endIndexStr = HostsEndMarker;
+ if (!txt.Contains(endIndexStr))
{
- return "Launcher path does not exist";
- }
-
- if (!File.Exists(Path.Combine(launcherPath, "nikke_launcher.exe")))
- {
- return "Launcher path is invalid. Make sure that the game executable exists in the launcher folder";
- }
-
-
- // TODO fix this mess
- string launcherCertList = launcherPath + "/intl_service/intl_cacert.pem";
- if (!File.Exists(launcherCertList))
- launcherCertList = launcherPath + "/intl_service/cacert.pem"; // older INTL sdk versions
- string gameCertList = gamePath + "/nikke_Data/Plugins/x86_64/intl_cacert.pem";
- if (!File.Exists(gameCertList))
- gameCertList = gamePath + "/nikke_Data/Plugins/x86_64/cacert.pem"; // older INTL sdk versions
-
- if (File.Exists(launcherCertList))
- {
- string certList1 = await File.ReadAllTextAsync(launcherCertList);
-
- if (!certList1.Contains("Good SSL Ca"))
- return "SSL Cert Patch missing";
- }
-
- if (File.Exists(gameCertList))
- {
- string certList2 = await File.ReadAllTextAsync(gameCertList);
-
- if (!certList2.Contains("Good SSL Ca"))
- return "SSL Cert Patch missing";
- }
-
- // TODO: Check sodium lib
- // TODO: check hosts file
-
- return "OK";
- }
-
- public static async Task RevertHostsFile(string hostsFilePath)
- {
- string txt = await File.ReadAllTextAsync(hostsFilePath);
-
- // remove stuff
- try
- {
-
- int startIdx = txt.IndexOf(HostsStartMarker);
- int endIdx;
- if (startIdx == -1)
+ // old code, find new line character before start index
+ for (int i = startIdx - 1; i >= 0; i--)
{
- startIdx = txt.IndexOf("cloud.nikke-kr.com");
- }
-
- string endIndexStr = HostsEndMarker;
- if (!txt.Contains(endIndexStr))
- {
- // old code, find new line character before start index
- for (int i = startIdx - 1; i >= 0; i--)
+ char c = txt[i];
+ if (c == '\n')
{
- char c = txt[i];
- if (c == '\n')
- {
- startIdx = i + 1;
- break;
- }
- }
-
- endIndexStr = "y.io";
- endIdx = txt.IndexOf(endIndexStr) + endIndexStr.Length;
- }
- else
- {
- // add/subtract 2 to take into account newline
- startIdx = txt.IndexOf(HostsStartMarker) - 2;
- endIdx = txt.IndexOf(endIndexStr) + endIndexStr.Length;
- }
-
- txt = string.Concat(txt.AsSpan(0, startIdx), txt.AsSpan(endIdx));
-
-
- await File.WriteAllTextAsync(hostsFilePath, txt);
- }
- catch
- {
-
- }
- }
-
- public static async Task SaveCfg(bool useOffical, string gamePath, string? launcherPath, string ip, bool offlineMode)
- {
- string sodiumLib = AppDomain.CurrentDomain.BaseDirectory + "sodium.dll";
- string gameSodium = gamePath + "/nikke_Data/Plugins/x86_64/sodium.dll";
- string gameAssembly = gamePath + "/GameAssembly.dll";
- string sodiumBackup = gameSodium + ".bak";
- string hostsFilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "drivers/etc/hosts");
- string CAcert = await File.ReadAllTextAsync(AppDomain.CurrentDomain.BaseDirectory + "myCA.pem");
-
- string launcherCertList = launcherPath + "/intl_service/intl_cacert.pem";
- if (!File.Exists(launcherCertList))
- launcherCertList = launcherPath + "/intl_service/cacert.pem"; // older INTL sdk versions
- string gameCertList = gamePath + "/nikke_Data/Plugins/x86_64/intl_cacert.pem";
- if (!File.Exists(gameCertList))
- gameCertList = gamePath + "/nikke_Data/Plugins/x86_64/cacert.pem"; // older INTL sdk versions
- bool supported = true;
-
- if (OperatingSystem.IsLinux())
- {
- // for wine
- hostsFilePath = gamePath + "/../../../windows/system32/drivers/etc/hosts";
- }
-
- if (useOffical)
- {
- await RevertHostsFile(hostsFilePath);
- if (OperatingSystem.IsLinux())
- {
- await RevertHostsFile("/etc/hosts");
- }
-
- try
- {
- // remove cert
- if (OperatingSystem.IsWindows())
- {
- X509Store store = new(StoreName.Root, StoreLocation.LocalMachine);
- store.Open(OpenFlags.ReadWrite);
- store.Remove(new X509Certificate2(X509Certificate.CreateFromCertFile(AppDomain.CurrentDomain.BaseDirectory + "myCA.pfx")));
- store.Close();
+ startIdx = i + 1;
+ break;
}
}
- catch
- {
- // may not be installed
- }
- // restore sodium
- if (!File.Exists(sodiumBackup))
- {
- throw new Exception("sodium backup does not exist. Repair the game in the launcher and switch to local server and back to official.");
- }
- File.Copy(sodiumBackup, gameSodium, true);
-
- if (File.Exists(launcherCertList))
- {
- string certList = await File.ReadAllTextAsync(launcherCertList);
-
- int goodSslIndex1 = certList.IndexOf("Good SSL Ca");
- if (goodSslIndex1 != -1)
- await File.WriteAllTextAsync(launcherCertList, certList[..goodSslIndex1]);
- }
-
- if (File.Exists(gameCertList))
- {
- string certList = await File.ReadAllTextAsync(gameCertList);
-
- int newCertIndex = certList.IndexOf("Good SSL Ca");
- if (newCertIndex != -1)
- await File.WriteAllTextAsync(gameCertList, certList[..newCertIndex]);
- }
+ endIndexStr = "y.io";
+ endIdx = txt.IndexOf(endIndexStr) + endIndexStr.Length;
}
else
{
- // add to hosts file
- string hosts = $@"{HostsStartMarker}
+ // add/subtract 2 to take into account newline
+ startIdx = txt.IndexOf(HostsStartMarker) - 2;
+ endIdx = txt.IndexOf(endIndexStr) + endIndexStr.Length;
+ }
+
+ txt = string.Concat(txt.AsSpan(0, startIdx), txt.AsSpan(endIdx));
+
+
+ await File.WriteAllTextAsync(hostsFilePath, txt);
+ }
+ catch
+ {
+
+ }
+ }
+
+ public static async Task SaveCfg(bool useOffical, string ip, bool offlineMode)
+ {
+ string CAcert = await File.ReadAllTextAsync(AppDomain.CurrentDomain.BaseDirectory + "myCA.pem");
+ string sodiumLib = AppDomain.CurrentDomain.BaseDirectory + "sodium.dll";
+
+ bool supported = true;
+ if (useOffical)
+ {
+ await RevertHostsFile(util.SystemHostsFile);
+ if (OperatingSystem.IsLinux())
+ {
+ await RevertHostsFile(util.WineHostsFile);
+ }
+
+ try
+ {
+ // remove cert
+ if (OperatingSystem.IsWindows())
+ {
+ X509Store store = new(StoreName.Root, StoreLocation.LocalMachine);
+ store.Open(OpenFlags.ReadWrite);
+ store.Remove(new X509Certificate2(X509Certificate.CreateFromCertFile(AppDomain.CurrentDomain.BaseDirectory + "myCA.pfx")));
+ store.Close();
+ }
+ }
+ catch
+ {
+ // may not be installed
+ }
+
+ // restore sodium
+ if (!File.Exists(util.GameSodiumBackupPath))
+ {
+ throw new Exception("sodium backup does not exist. Repair the game in the launcher and switch to local server and back to official.");
+ }
+ File.Copy(util.GameSodiumBackupPath, util.GameSodiumPath, true);
+
+ if (util.LauncherCertificatePath != null && File.Exists(util.LauncherCertificatePath))
+ {
+ string certList = await File.ReadAllTextAsync(util.LauncherCertificatePath);
+
+ int goodSslIndex1 = certList.IndexOf("Good SSL Ca");
+ if (goodSslIndex1 != -1)
+ await File.WriteAllTextAsync(util.LauncherCertificatePath, certList[..goodSslIndex1]);
+ }
+
+ if (File.Exists(util.GameCertificatePath))
+ {
+ string certList = await File.ReadAllTextAsync(util.GameCertificatePath);
+
+ int newCertIndex = certList.IndexOf("Good SSL Ca");
+ if (newCertIndex != -1)
+ await File.WriteAllTextAsync(util.GameCertificatePath, certList[..newCertIndex]);
+ }
+ }
+ else
+ {
+ // add to hosts file
+ string hosts = $@"{HostsStartMarker}
{ip} global-lobby.nikke-kr.com
";
- if (offlineMode)
- {
- hosts += $"{ip} cloud.nikke-kr.com" + Environment.NewLine;
- }
+ if (offlineMode)
+ {
+ hosts += $"{ip} cloud.nikke-kr.com" + Environment.NewLine;
+ }
- hosts += $@"{ip} jp-lobby.nikke-kr.com
+ hosts += $@"{ip} jp-lobby.nikke-kr.com
{ip} us-lobby.nikke-kr.com
{ip} kr-lobby.nikke-kr.com
{ip} sea-lobby.nikke-kr.com
@@ -224,94 +188,92 @@ namespace ServerSelector
255.255.221.21 sentry.io
{HostsEndMarker}";
- await RevertHostsFile(hostsFilePath);
+ await RevertHostsFile(util.SystemHostsFile);
- try
+ try
+ {
+ FileInfo fi = new(util.SystemHostsFile);
+ if (fi.IsReadOnly)
{
- FileInfo fi = new(hostsFilePath);
- if (fi.IsReadOnly)
- {
- // try to remove readonly flag
- fi.IsReadOnly = false;
- }
-
- if (!(await File.ReadAllTextAsync(hostsFilePath)).Contains("global-lobby.nikke-kr.com"))
- {
- using StreamWriter w = File.AppendText(hostsFilePath);
- w.WriteLine();
- w.Write(hosts);
- }
- }
- catch
- {
- throw new Exception("cannot modify C:\\Windows\\System32\\drivers\\etc\\hosts file to redirect to server, check your antivirus software");
+ // try to remove readonly flag
+ fi.IsReadOnly = false;
}
- // Also change /etc/hosts if running on linux
- if (OperatingSystem.IsLinux())
+ if (!(await File.ReadAllTextAsync(util.SystemHostsFile)).Contains("global-lobby.nikke-kr.com"))
{
- hostsFilePath = "/etc/hosts";
- await RevertHostsFile(hostsFilePath);
- if (!(await File.ReadAllTextAsync(hostsFilePath)).Contains("global-lobby.nikke-kr.com"))
- {
- using StreamWriter w = File.AppendText(hostsFilePath);
- w.WriteLine();
- w.Write(hosts);
- }
+ using StreamWriter w = File.AppendText(util.SystemHostsFile);
+ w.WriteLine();
+ w.Write(hosts);
}
+ }
+ catch
+ {
+ throw new Exception($"cannot modify \"{util.SystemHostsFile}\" file to redirect to server, check your antivirus software");
+ }
- // trust CA. TODO is this needed?
- try
+ // Also change hosts file in wineprefix if running on linux
+ if (OperatingSystem.IsLinux())
+ {
+ await RevertHostsFile(util.WineHostsFile);
+ if (!(await File.ReadAllTextAsync(util.WineHostsFile)).Contains("global-lobby.nikke-kr.com"))
{
- if (OperatingSystem.IsWindows())
- {
- X509Store store = new(StoreName.Root, StoreLocation.LocalMachine);
- store.Open(OpenFlags.ReadWrite);
- store.Add(new X509Certificate2(X509Certificate2.CreateFromCertFile(AppDomain.CurrentDomain.BaseDirectory + "myCA.pfx")));
- store.Close();
- }
+ using StreamWriter w = File.AppendText(util.WineHostsFile);
+ w.WriteLine();
+ w.Write(hosts);
}
- catch { }
+ }
- if (!File.Exists(gameSodium))
+ // trust CA. TODO is this needed?
+ try
+ {
+ if (OperatingSystem.IsWindows())
{
- throw new Exception("expected sodium library to exist at path " + gameSodium);
+ X509Store store = new(StoreName.Root, StoreLocation.LocalMachine);
+ store.Open(OpenFlags.ReadWrite);
+ store.Add(new X509Certificate2(X509Certificate2.CreateFromCertFile(AppDomain.CurrentDomain.BaseDirectory + "myCA.pfx")));
+ store.Close();
}
+ }
+ catch { }
- // copy backup if sodium size is correct
- byte[] sod = await File.ReadAllBytesAsync(gameSodium);
- if (sod.Length <= 307200) // TODO this is awful
- {
- // orignal file size, copy backup
- await File.WriteAllBytesAsync(sodiumBackup, sod);
- }
+ if (!File.Exists(util.GameSodiumPath))
+ {
+ throw new Exception("expected sodium library to exist at path " + util.GameSodiumPath);
+ }
- // write new sodium library
- await File.WriteAllBytesAsync(gameSodium, await File.ReadAllBytesAsync(sodiumLib));
+ // copy backup if sodium size is correct
+ byte[] sod = await File.ReadAllBytesAsync(util.GameSodiumPath);
+ if (sod.Length <= 307200) // TODO this is awful
+ {
+ // orignal file size, copy backup
+ await File.WriteAllBytesAsync(util.GameSodiumBackupPath, sod);
+ }
- // Add generated CA certificate to launcher/game curl certificate list
- if (launcherPath != null)
- {
- await File.WriteAllTextAsync(launcherCertList,
- await File.ReadAllTextAsync(launcherCertList)
- + "\nGood SSL Ca\n===============================\n"
- + CAcert);
- }
+ // write new sodium library
+ await File.WriteAllBytesAsync(util.GameSodiumPath, await File.ReadAllBytesAsync(sodiumLib));
- await File.WriteAllTextAsync(gameCertList,
- await File.ReadAllTextAsync(gameCertList)
+ // Add generated CA certificate to launcher/game curl certificate list
+ if (util.LauncherCertificatePath != null)
+ {
+ await File.WriteAllTextAsync(util.LauncherCertificatePath,
+ await File.ReadAllTextAsync(util.LauncherCertificatePath)
+ "\nGood SSL Ca\n===============================\n"
+ CAcert);
}
- return new ServerSwitchResult(true, null, supported);
+ await File.WriteAllTextAsync(util.GameCertificatePath,
+ await File.ReadAllTextAsync(util.GameCertificatePath)
+ + "\nGood SSL Ca\n===============================\n"
+ + CAcert);
}
- }
- public class ServerSwitchResult(bool ok, Exception? exception, bool isSupported)
- {
- public bool Ok { get; set; } = ok;
- public Exception? Exception { get; set; } = exception;
- public bool IsSupported { get; set; } = isSupported;
+ return new ServerSwitchResult(true, null, supported);
}
}
+
+public class ServerSwitchResult(bool ok, Exception? exception, bool isSupported)
+{
+ public bool Ok { get; set; } = ok;
+ public Exception? Exception { get; set; } = exception;
+ public bool IsSupported { get; set; } = isSupported;
+}
diff --git a/ServerSelector/Views/MainView.axaml b/ServerSelector/Views/MainView.axaml
index 0e791cd..a54e6a5 100644
--- a/ServerSelector/Views/MainView.axaml
+++ b/ServerSelector/Views/MainView.axaml
@@ -116,7 +116,7 @@
Game root path:
C:\NIKKE\
-
+
Server:
@@ -144,7 +144,7 @@
-
+
diff --git a/ServerSelector/Views/MainView.axaml.cs b/ServerSelector/Views/MainView.axaml.cs
index 99cc9e1..d41f8df 100644
--- a/ServerSelector/Views/MainView.axaml.cs
+++ b/ServerSelector/Views/MainView.axaml.cs
@@ -14,9 +14,9 @@ public partial class MainView : UserControl
public MainView()
{
InitializeComponent();
- CmbServerSelection.SelectedIndex = ServerSwitcher.IsUsingOfficalServer() ? 0 : 1;
+ CmbServerSelection.SelectedIndex = ServerSwitcher.IsUsingLocalServer() ? 1 : 0;
- TxtIpAddress.IsEnabled = !ServerSwitcher.IsUsingOfficalServer();
+ TxtIpAddress.IsEnabled = !ServerSwitcher.IsUsingLocalServer();
ChkOffline.IsChecked = ServerSwitcher.IsOffline();
if (OperatingSystem.IsWindows() && !new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator))
@@ -57,25 +57,17 @@ public partial class MainView : UserControl
}
}
- private string? GamePath
+ private string? BasePath
{
get
{
if (txtGamePath.Text == null) return null;
- return Path.Combine(txtGamePath.Text, "NIKKE", "game");
- }
- }
- private string? LauncherPath
- {
- get
- {
- if (txtGamePath.Text == null) return null;
- return Path.Combine(txtGamePath.Text, "Launcher");
+ return txtGamePath.Text;
}
}
private bool ValidatePaths(bool showMessage)
{
- if (string.IsNullOrEmpty(txtGamePath.Text) || LauncherPath == null)
+ if (string.IsNullOrEmpty(BasePath))
{
SetGamePathValid(false);
if (showMessage)
@@ -83,20 +75,21 @@ public partial class MainView : UserControl
return false;
}
- if (!Directory.Exists(GamePath))
+ if (!Directory.Exists(BasePath))
{
SetGamePathValid(false);
if (showMessage)
- ShowWarningMsg("game folder does not exist in the game root folder", "Error");
+ ShowWarningMsg("Game path does not exist", "Error");
return false;
}
- if (!File.Exists(Path.Combine(LauncherPath, "nikke_launcher.exe")))
+ var result = ServerSwitcher.SetBasePath(BasePath);
+
+ if (!result.Item1)
{
SetGamePathValid(false);
if (showMessage)
- ShowWarningMsg("Game path is invalid. Make sure that nikke_launcher.exe exists in the /launcher folder", "Error");
-
+ ShowWarningMsg(result.Item2, "Error");
return false;
}
@@ -107,11 +100,11 @@ public partial class MainView : UserControl
private async void UpdateIntegrityLabel()
{
- if (!ValidatePaths(false) || txtGamePath.Text == null || GamePath == null || LauncherPath == null)
+ if (!ValidatePaths(false) || txtGamePath.Text == null || BasePath == null)
return;
SetLoadingScreenVisible(true);
- LblStatus.Text = "Status: " + await ServerSwitcher.CheckIntegrity(GamePath, LauncherPath);
+ LblStatus.Text = "Status: " + await ServerSwitcher.CheckIntegrity();
SetLoadingScreenVisible(false);
}
@@ -131,7 +124,7 @@ public partial class MainView : UserControl
private async void Save_Click(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
{
- if (!ValidatePaths(true) || txtGamePath.Text == null || GamePath == null || LauncherPath == null)
+ if (!ValidatePaths(true) || txtGamePath.Text == null || BasePath == null)
return;
if (CmbServerSelection.SelectedIndex == 1 && !IPAddress.TryParse(TxtIpAddress.Text, out _))
@@ -150,7 +143,7 @@ public partial class MainView : UserControl
SetLoadingScreenVisible(true);
try
{
- ServerSwitchResult res = await ServerSwitcher.SaveCfg(CmbServerSelection.SelectedIndex == 0, GamePath, LauncherPath, TxtIpAddress.Text, ChkOffline.IsChecked ?? false);
+ ServerSwitchResult res = await ServerSwitcher.SaveCfg(CmbServerSelection.SelectedIndex == 0, TxtIpAddress.Text, ChkOffline.IsChecked ?? false);
if (!res.IsSupported)
{