commit d4c4bb05c58255153f70d2d214b5ccf54bfc45ca
Author: casksteven <56806651+casksteven@users.noreply.github.com>
Date: Fri Feb 10 21:19:10 2023 -0500
Add files via upload
diff --git a/App.config b/App.config
new file mode 100644
index 0000000..04ee662
--- /dev/null
+++ b/App.config
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/App.xaml b/App.xaml
new file mode 100644
index 0000000..ada90f1
--- /dev/null
+++ b/App.xaml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+ pack://application:,,,/Launcher;component/Res/#remixicon
+
+
+
+
+
+
diff --git a/App.xaml.cs b/App.xaml.cs
new file mode 100644
index 0000000..fe07c8d
--- /dev/null
+++ b/App.xaml.cs
@@ -0,0 +1,103 @@
+using Launcher.Model;
+using Launcher.ViewModel;
+using Newtonsoft.Json;
+using System;
+using System.Globalization;
+using System.Net;
+using System.Threading;
+using System.Windows;
+using System.Windows.Navigation;
+
+namespace Launcher
+{
+ ///
+ /// App.xaml 的交互逻辑
+ ///
+ public partial class App : Application
+ {
+//#if DEBUG
+// private CultureInfo cultureOverride = new CultureInfo("en-US");
+//#endif
+ System.Threading.Mutex mutex;
+
+ protected override void OnStartup(StartupEventArgs e)
+ {
+
+
+ ServicePointManager.ServerCertificateValidationCallback += (s, cert, chain, sslPolicyErrors) => true;
+
+
+ AppDomain currentDomain = AppDomain.CurrentDomain;
+ // 当前作用域出现未捕获异常时,使用MyHandler函数响应事件
+
+#if !DEBUG
+ currentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyHandler);
+
+#endif
+
+
+ //单例
+ bool ret;
+ mutex = new System.Threading.Mutex(true, "ElectronicNeedleTherapySystem", out ret);
+
+
+ if (App.launcherConfig == null)
+ {
+
+ App.launcherConfig = LauncherConfig.Load("config.json");
+
+ if (!string.IsNullOrEmpty(App.launcherConfig.Language))
+ {
+ CultureInfo cultureOverride = new CultureInfo(App.launcherConfig.Language);
+ Thread.CurrentThread.CurrentCulture = cultureOverride;
+ Thread.CurrentThread.CurrentUICulture = cultureOverride;
+ }
+ }
+
+ if (!ret)
+ {
+ MessageBox.Show(Launcher.Properties.Resources.tip_alreadyrunning);
+ Environment.Exit(0);
+ }
+
+
+
+ base.OnStartup(e);
+
+ }
+
+ static void MyHandler(object sender, UnhandledExceptionEventArgs args)
+ {
+ Exception e = (Exception)args.ExceptionObject;
+
+ MessageBox.Show(e.Message + "\n" + "请吧程序目录下的 err.log 提交至项目issues!", Launcher.Properties.Resources.tip_crash_title);
+ System.IO.File.WriteAllText("err.log", e.Message + JsonConvert.SerializeObject(e));
+ Environment.Exit(0);
+
+ }
+
+ protected override void OnLoadCompleted(NavigationEventArgs e)
+ {
+ base.OnLoadCompleted(e);
+
+ }
+
+ protected override void OnExit(ExitEventArgs e)
+ {
+ try
+ {
+ launcherConfig.Save("config.json");
+
+ if (HomeVM.Instacne.proxyController!=null)
+ {
+ HomeVM.Instacne.proxyController.Stop();
+ }
+ }
+ catch { }
+
+ base.OnExit(e);
+ }
+
+ public static LauncherConfig launcherConfig;
+ }
+}
diff --git a/Common/EmbedFileManager.cs b/Common/EmbedFileManager.cs
new file mode 100644
index 0000000..9ac43f0
--- /dev/null
+++ b/Common/EmbedFileManager.cs
@@ -0,0 +1,140 @@
+using System;
+using System.IO;
+using System.Reflection;
+
+namespace Launcher.Common
+{
+ internal class EmbedFileManager
+ {
+ ///
+ /// 释放内嵌资源至指定位置
+ ///
+ /// 嵌入的资源,此参数写作:命名空间.文件夹名.文件名.扩展名
+ /// 释放到位置
+ public static void ExtractFile(string file, string path)
+ {
+ var resource = $"Launcher.{file}";
+ Assembly assembly = Assembly.GetExecutingAssembly();
+ BufferedStream input = new BufferedStream(assembly.GetManifestResourceStream(resource));
+ FileStream output = new FileStream(path, FileMode.Create);
+ byte[] data = new byte[1024];
+ int lengthEachRead;
+ while ((lengthEachRead = input.Read(data, 0, data.Length)) > 0)
+ {
+ output.Write(data, 0, lengthEachRead);
+ }
+ output.Flush();
+ output.Close();
+ }
+
+
+ }
+
+ public static class RawFileHelper
+ {
+ public static byte[] GetKey(string file)
+ {
+ Stream sr = null; ;
+ try
+ {
+ var _assembly = Assembly.GetExecutingAssembly();//获取当前执行代码的程序集
+ sr = _assembly.GetManifestResourceStream($"Launcher.RSAPatch.{file}");
+
+ }
+ catch
+ {
+ //AConsole.e(new Spectre.Console.Markup("访问资源错误"));
+ throw;
+ }
+
+ return streamToByteArray(sr);
+ }
+
+ private static byte[] streamToByteArray(Stream input)
+ {
+ MemoryStream ms = new MemoryStream();
+ input.CopyTo(ms);
+ return ms.ToArray();
+ }
+ }
+
+ public static class RSAPatchHelper
+ {
+ public static string TempFolder = Path.Combine(System.IO.Path.GetTempPath(),"com.launcher");
+
+ public static string WriteMhypbaseAllTo(Model.ServerItem item)
+ {
+ if (!Directory.Exists(TempFolder))
+ {
+ Directory.CreateDirectory(TempFolder);
+ }
+ var r = WriteDllTo(TempFolder);
+ WriteInITo(TempFolder, item);
+ return r;
+ }
+
+ public static void CleanTemp()
+ {
+ Directory.Delete(TempFolder, true);
+ }
+
+ public static string WriteDllTo(string folder)
+ {
+ string target_dll = Path.Combine(folder, "rsa.dll");
+ try
+ {
+ EmbedFileManager.ExtractFile("RSAPatch.RSAPatch.dll", target_dll);
+
+ }
+ catch
+ {
+ throw;
+ }
+ return target_dll;
+
+ }
+
+ public static void WriteInITo(string folder, Model.ServerItem item)
+ {
+ try
+ {
+
+
+ if (App.launcherConfig.DebugMode)
+ {
+ // debug
+ }
+
+
+
+ if (!string.IsNullOrEmpty(item.RSAPrivateKey))
+ {
+ File.WriteAllText(Path.Combine(folder,"PrivateKey.txt"), item.RSAPrivateKey);
+ }
+ if (!string.IsNullOrEmpty(item.RSAPublicKey))
+ {
+ File.WriteAllText(Path.Combine(folder, "PublicKey.txt"), item.RSAPublicKey);
+ }
+ else
+ {
+ // use default
+ File.WriteAllBytes(Path.Combine(folder, "PublicKey.txt"), RawFileHelper.GetKey("PublicKey.txt"));
+ }
+
+
+ }
+ catch
+ {
+ throw;
+ }
+
+ }
+
+ private static byte[] streamToByteArray(Stream input)
+ {
+ MemoryStream ms = new MemoryStream();
+ input.CopyTo(ms);
+ return ms.ToArray();
+ }
+ }
+}
diff --git a/Common/GameHelper.cs b/Common/GameHelper.cs
new file mode 100644
index 0000000..25dfae2
--- /dev/null
+++ b/Common/GameHelper.cs
@@ -0,0 +1,186 @@
+using CommunityToolkit.Mvvm.Input;
+using Launcher.Control;
+using Microsoft.Win32;
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Windows;
+
+namespace Launcher.Common
+{
+ internal class GameHelper
+ {
+ [DllImport("InjectorLib.dll", CallingConvention = CallingConvention.Cdecl)]
+ extern static bool Begin(string game_path, string dll_path);
+
+
+
+ public static void StartGame(string filePath,string target_dll)
+ {
+ string currentDir = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName);
+ string dll_file = Path.Combine(currentDir, "InjectorLib.dll");
+ if (File.Exists(filePath))
+ {
+ //if (!File.Exists("InjectorLib.dll"))
+ //{
+ // EmbedFileManager.ExtractFile("InjectorLib.dll", dll_file);
+ //}
+
+ target_dll =Path.Combine(currentDir, target_dll);
+ bool r=Begin(filePath, target_dll);
+
+ if (r)
+ {
+ SnackBar.Show("Inject Success!",null);
+ }
+ else
+ {
+ SnackBar.Show("Inject Failed!", null);
+
+ }
+ }
+ else
+ {
+
+ }
+ }
+
+ public static class GameRegReader
+ {
+ ///
+ /// 获取游戏目录,是静态方法
+ ///
+ ///
+ public static string GetGamePath()
+ {
+ try
+ {
+ string startpath = "";
+ string launcherpath = GetLauncherPath();
+ #region 获取游戏启动路径,和官方配置一致
+ string cfgPath = Path.Combine(launcherpath, "config.ini");
+ if (File.Exists(launcherpath) || File.Exists(cfgPath))
+ {
+ //获取游戏本体路径
+ using (StreamReader reader = new StreamReader(cfgPath))
+ {
+ string[] abc = reader.ReadToEnd().Split(new string[] { "\r\n" }, StringSplitOptions.None);
+ foreach (var item in abc)
+ {
+ //从官方获取更多配置
+ if (item.IndexOf("game_install_path") != -1)
+ {
+ startpath += item.Substring(item.IndexOf("=") + 1);
+ }
+ }
+ }
+ }
+ byte[] bytearr = Encoding.UTF8.GetBytes(startpath);
+ string path = Encoding.UTF8.GetString(bytearr);
+ return path;
+ }
+ catch
+ {
+ return null;
+ }
+ #endregion
+ }
+ ///
+ /// 启动器地址
+ ///
+ ///
+ public static string GetLauncherPath()
+ {
+ try
+ {
+ RegistryKey key = Registry.LocalMachine; //打开指定注册表根
+ //获取官方启动器路径
+ string launcherpath = "";
+ try
+ {
+ launcherpath = key.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\原神").GetValue("InstallPath").ToString();
+
+
+ }
+ catch (Exception)
+ {
+ launcherpath = key.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Genshin Impact").GetValue("InstallPath").ToString();
+
+ }
+
+ byte[] bytepath = Encoding.UTF8.GetBytes(launcherpath); //编码转换
+ string path = Encoding.UTF8.GetString(bytepath);
+ return path;
+
+ }
+ catch
+ {
+ return null;
+ }
+ }
+
+ public static string GetGameExePath()
+ {
+
+ var gamepath = GetGamePath();
+ if (gamepath == null)
+ {
+ return null;
+ }
+ var cnpath = gamepath + @"/YuanShen.exe";
+ var ospath = gamepath + @"/GenshinImpact.exe";
+
+ if (File.Exists(cnpath))
+ {
+ return cnpath;
+ }
+ else if (File.Exists(ospath))
+ {
+ return ospath;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+
+ }
+
+ public static class GameLocalReader
+ {
+
+ public static string GetGameExePath()
+ {
+ string Self = Process.GetCurrentProcess().MainModule.FileName;
+ var Folder = Path.GetDirectoryName(Self);
+ string ret;
+ string cn = Path.Combine(Folder, "YuanShen.exe");
+ string os = Path.Combine(Folder, "GenshinImpact.exe");
+ if (File.Exists(cn))
+ {
+ ret = Path.Combine(Folder, cn);
+ }
+ else if (File.Exists(os))
+ {
+ ret = Path.Combine(Folder, os);
+
+ }
+ else
+ {
+ throw new Exception("未能从当前路径找到原神游戏文件!");
+ }
+ return ret;
+ }
+
+ public static string GetGameExeFolder()
+ {
+ return Path.GetDirectoryName(GetGameExePath());
+ }
+
+
+ }
+ }
+}
diff --git a/Common/IProxy.cs b/Common/IProxy.cs
new file mode 100644
index 0000000..0db6e52
--- /dev/null
+++ b/Common/IProxy.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Launcher.Common
+{
+ public interface IProxyController
+ {
+ bool _IsRun { get; set; }
+
+ void Start();
+
+ void Stop();
+ }
+}
diff --git a/Common/IniHelper.cs b/Common/IniHelper.cs
new file mode 100644
index 0000000..6fe8525
--- /dev/null
+++ b/Common/IniHelper.cs
@@ -0,0 +1,43 @@
+using System.IO;
+
+namespace Launcher.Common
+{
+ public static class IniHelper
+ {
+ // 声明INI文件的写操作函数 WritePrivateProfileString()
+ [System.Runtime.InteropServices.DllImport("kernel32")]
+ private static extern long WritePrivateProfileString(string section, string key, string val, string filePath);
+
+ // 声明INI文件的读操作函数 GetPrivateProfileString()
+ [System.Runtime.InteropServices.DllImport("kernel32")]
+ private static extern int GetPrivateProfileString(string section, string key, string def, System.Text.StringBuilder retVal, int size, string filePath);
+
+
+ /// 写入INI的方法
+ public static void INIWrite(string section, string key, string value, string path)
+ {
+ // section=配置节点名称,key=键名,value=返回键值,path=路径
+ WritePrivateProfileString(section, key, value, path);
+ }
+
+ //读取INI的方法
+ public static string INIRead(string section, string key, string path)
+ {
+ // 每次从ini中读取多少字节
+ System.Text.StringBuilder temp = new System.Text.StringBuilder(255);
+
+ // section=配置节点名称,key=键名,temp=上面,path=路径
+ GetPrivateProfileString(section, key, "", temp, 255, path);
+ return temp.ToString();
+
+ }
+
+ //删除一个INI文件
+ public static void INIDelete(string FilePath)
+ {
+ File.Delete(FilePath);
+ }
+
+
+ }
+}
diff --git a/Common/ProcessWatcher.cs b/Common/ProcessWatcher.cs
new file mode 100644
index 0000000..33d6ee1
--- /dev/null
+++ b/Common/ProcessWatcher.cs
@@ -0,0 +1,40 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Launcher.Common
+{
+ internal class ProcessWatcher
+ {
+ public Process proc;
+ EventHandler pro_Exited;
+ public ProcessWatcher(EventHandler pro_Exited)
+ {
+ this.pro_Exited = pro_Exited;
+ }
+
+ public void Watch()
+ {
+ Process[] ps = Process.GetProcesses();
+
+ foreach (Process p in ps)
+ {
+ if (p.ProcessName== "GenshinImpact"||p.ProcessName== "YuanShen")
+ {
+ proc = p;
+ }
+ }
+
+ if (proc!=null)
+ {
+ proc.EnableRaisingEvents = true;
+ proc.Exited += new EventHandler(pro_Exited);
+ }
+ }
+
+
+ }
+}
diff --git a/Common/ProxyHelper.cs b/Common/ProxyHelper.cs
new file mode 100644
index 0000000..d82d00f
--- /dev/null
+++ b/Common/ProxyHelper.cs
@@ -0,0 +1,209 @@
+using Launcher.Model;
+using Microsoft.Win32;
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Net;
+using System.Threading.Tasks;
+using Titanium.Web.Proxy;
+using Titanium.Web.Proxy.EventArguments;
+using Titanium.Web.Proxy.Models;
+
+namespace Launcher.Common
+{
+ internal static class ProxyHelper
+ {
+
+ public static ProxyConfig GetCurrentProxy()
+ {
+ ProxyConfig proxyConfig = new ProxyConfig("127.0.0.1");
+
+ try
+ {
+ using (RegistryKey regkey = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Internet Settings"))
+ {
+ if (regkey.GetValue("ProxyEnable").ToString() == "1")
+ {
+ proxyConfig.ProxyEnable = true;
+ }
+ object ps = regkey.GetValue("ProxyServer");
+ if (ps != null)
+ {
+ proxyConfig.ProxyServer = ps.ToString();
+ }
+ else
+ {
+ ps = null;
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine(ex.Message);
+ }
+
+ return proxyConfig;
+ }
+
+ public static void Clear_Proxy()
+ {
+ using (RegistryKey regkey = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Internet Settings", true))
+ {
+ try
+ {
+ regkey.SetValue("ProxyEnable", 0);
+ regkey.DeleteValue("ProxyServer");
+ }
+ catch (Exception e)
+ {
+ Debug.Print(e.Message);
+ }
+ }
+ }
+
+ public class ProxyController
+ {
+ ProxyServer proxyServer;
+ ExplicitProxyEndPoint explicitEndPoint;
+ private string port;
+ private string fakeHost;
+ private bool usehttp;
+
+ public ProxyController(string port, string host, bool usehttp = false)
+ {
+ this.port = port;
+ this.fakeHost = host;
+ this.usehttp = usehttp;
+ }
+
+ private bool IsRun;
+
+ public bool _IsRun
+ {
+ get { return proxyServer.ProxyRunning; }
+ set { IsRun = value; }
+ }
+
+
+ public void Start()
+ {
+ if (GetCurrentProxy().ProxyEnable)
+ {
+ Clear_Proxy();
+ }
+
+ proxyServer = new ProxyServer();
+ var docp = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
+ var certp = Path.Combine(docp, "rootCert.pfx");
+ proxyServer.CertificateManager.PfxFilePath = certp;
+ proxyServer.CertificateManager.EnsureRootCertificate();
+
+
+
+ proxyServer.BeforeRequest += OnRequest;
+ proxyServer.ServerCertificateValidationCallback += OnCertificateValidation;
+ if (String.IsNullOrEmpty(port))
+ {
+ port = 11451.ToString(); ;
+ }
+
+ explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, int.Parse(port), true);
+
+ explicitEndPoint.BeforeTunnelConnectRequest += OnBeforeTunnelConnectRequest;
+
+ proxyServer.AddEndPoint(explicitEndPoint);
+ proxyServer.Start();
+
+
+ foreach (var endPoint in proxyServer.ProxyEndPoints)
+ Console.WriteLine("Listening on '{0}' endpoint at Ip {1} and port: {2} ",
+ endPoint.GetType().Name, endPoint.IpAddress, endPoint.Port);
+
+ proxyServer.SetAsSystemHttpProxy(explicitEndPoint);
+ proxyServer.SetAsSystemHttpsProxy(explicitEndPoint);
+
+ }
+
+
+
+ public void Stop()
+ {
+ try
+ {
+ explicitEndPoint.BeforeTunnelConnectRequest -= OnBeforeTunnelConnectRequest;
+ proxyServer.BeforeRequest -= OnRequest;
+ proxyServer.ServerCertificateValidationCallback -= OnCertificateValidation;
+
+
+ }
+ catch { }
+ finally
+ {
+ if (proxyServer != null && proxyServer.ProxyRunning)
+ {
+ proxyServer.Stop();
+
+ }
+ else
+ {
+ }
+
+ }
+
+ }
+
+ public void UninstallCertificate()
+ {
+
+ proxyServer.CertificateManager.RemoveTrustedRootCertificate();
+ proxyServer.CertificateManager.RemoveTrustedRootCertificateAsAdmin();
+
+
+ }
+
+
+ private async Task OnBeforeTunnelConnectRequest(object sender, TunnelConnectSessionEventArgs e)
+ {
+ string hostname = e.WebSession.Request.RequestUri.Host;
+ if (hostname.EndsWith(".yuanshen.com") |
+ hostname.EndsWith(".hoyoverse.com") |
+ hostname.EndsWith(".mihoyo.com") | hostname.EndsWith(fakeHost))
+ {
+ e.DecryptSsl = true;
+ }
+ else
+ {
+
+ e.DecryptSsl = false;
+ }
+ }
+
+
+ private async Task OnRequest(object sender, SessionEventArgs e)
+ {
+ string hostname = e.WebSession.Request.RequestUri.Host;
+ if (hostname.EndsWith(".yuanshen.com") |
+ hostname.EndsWith(".hoyoverse.com") |
+ hostname.EndsWith(".mihoyo.com"))
+ {
+ string oHost = e.WebSession.Request.RequestUri.Host;
+ e.HttpClient.Request.Url = e.HttpClient.Request.Url.Replace(oHost, fakeHost);
+ if (usehttp)
+ {
+ e.HttpClient.Request.Url = e.HttpClient.Request.Url.Replace("https", "http");
+
+ }
+
+ }
+ }
+
+ // Allows overriding default certificate validation logic
+ private Task OnCertificateValidation(object sender, CertificateValidationEventArgs e)
+ {
+ e.IsValid = true;
+ return Task.CompletedTask;
+ }
+
+ }
+ }
+}
diff --git a/Control/ServerEditControl.xaml b/Control/ServerEditControl.xaml
new file mode 100644
index 0000000..f1d7f84
--- /dev/null
+++ b/Control/ServerEditControl.xaml
@@ -0,0 +1,174 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Control/ServerEditControl.xaml.cs b/Control/ServerEditControl.xaml.cs
new file mode 100644
index 0000000..ad520ae
--- /dev/null
+++ b/Control/ServerEditControl.xaml.cs
@@ -0,0 +1,61 @@
+using Launcher.Model;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+
+namespace Launcher.Control
+{
+ ///
+ /// ServerEditControl.xaml 的交互逻辑
+ ///
+ public partial class ServerEditControl : UserControl
+ {
+ public static ServerEditControl instance;
+
+ public static void Show()
+ {
+ instance.Visibility =Visibility.Visible;
+ }
+
+ public ServerEditControl()
+ {
+ InitializeComponent();
+ instance = this;
+ }
+
+ private void Button_Click(object sender, RoutedEventArgs e)
+ {
+ Visibility = Visibility.Collapsed;
+
+ }
+
+ public ServerItem ServerItem
+ {
+ get { return (ServerItem)GetValue(ServerItemProperty); }
+ set { SetValue(ServerItemProperty, value); }
+ }
+
+ // Using a DependencyProperty as the backing store for ServerItem. This enables animation, styling, binding, etc...
+ public static readonly DependencyProperty ServerItemProperty =
+ DependencyProperty.Register("ServerItem", typeof(ServerItem), typeof(ServerEditControl), new PropertyMetadata(null));
+
+ private void Button_Click_1(object sender, RoutedEventArgs e)
+ {
+
+
+ Visibility = Visibility.Collapsed;
+
+ }
+ }
+}
diff --git a/Control/SnackBar.xaml b/Control/SnackBar.xaml
new file mode 100644
index 0000000..744e562
--- /dev/null
+++ b/Control/SnackBar.xaml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Control/SnackBar.xaml.cs b/Control/SnackBar.xaml.cs
new file mode 100644
index 0000000..c781970
--- /dev/null
+++ b/Control/SnackBar.xaml.cs
@@ -0,0 +1,96 @@
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Input;
+
+namespace Launcher.Control
+{
+ ///
+ /// SnackBar.xaml 的交互逻辑
+ ///
+ public partial class SnackBar : UserControl
+ {
+ public SnackBar()
+ {
+ InitializeComponent();
+ }
+
+ public static void Show(string Msg, ICommand Command, string ActionStr = "确定")
+ {
+ var sb = new SnackBar();
+ sb.Command = Command;
+ sb.ActionStr = ActionStr;
+ sb.Msg = Msg;
+
+ MainWindow.Instance.sb_container.Children.Add(sb);
+ }
+
+
+
+
+ public string Msg
+ {
+ get { return (string)GetValue(MsgProperty); }
+ set { SetValue(MsgProperty, value); }
+ }
+
+ // Using a DependencyProperty as the backing store for Msg. This enables animation, styling, binding, etc...
+ public static readonly DependencyProperty MsgProperty =
+ DependencyProperty.Register("Msg", typeof(string), typeof(SnackBar), new PropertyMetadata("这是一个 Snack Bar", (s, e) =>
+ {
+ var bar = s as SnackBar;
+ if (bar != null)
+ bar.msg_tb.Text = e.NewValue.ToString();
+
+ }));
+
+
+
+ public string ActionStr
+ {
+ get { return (string)GetValue(ActionStrProperty); }
+ set { SetValue(ActionStrProperty, value); }
+ }
+
+ // Using a DependencyProperty as the backing store for ActionStr. This enables animation, styling, binding, etc...
+ public static readonly DependencyProperty ActionStrProperty =
+ DependencyProperty.Register("ActionStr", typeof(string), typeof(SnackBar), new PropertyMetadata("确定", (s, e) =>
+ {
+ var bar = s as SnackBar;
+ if (bar != null)
+ bar.action_btn.Content = e.NewValue.ToString();
+
+ }));
+
+ private void action_btn_Click(object sender, RoutedEventArgs e)
+ {
+ if (Command != null)
+ {
+ Command.Execute(null);
+
+ }
+
+ this.Visibility = Visibility.Collapsed;
+
+ StackPanel stackPanel = this.Parent as StackPanel;
+ if (stackPanel != null)
+ {
+ stackPanel.Children.Remove(this);
+ }
+ }
+
+
+
+
+ public ICommand Command
+ {
+ get { return (ICommand)GetValue(CommandProperty); }
+ set { SetValue(CommandProperty, value); }
+ }
+
+ // Using a DependencyProperty as the backing store for Command. This enables animation, styling, binding, etc...
+ public static readonly DependencyProperty CommandProperty =
+ DependencyProperty.Register("Command", typeof(ICommand), typeof(SnackBar), new PropertyMetadata(null));
+
+
+ }
+}
diff --git a/Costura64/InjectorLib.dll b/Costura64/InjectorLib.dll
new file mode 100644
index 0000000..768d80e
Binary files /dev/null and b/Costura64/InjectorLib.dll differ
diff --git a/FodyWeavers.xml b/FodyWeavers.xml
new file mode 100644
index 0000000..943538d
--- /dev/null
+++ b/FodyWeavers.xml
@@ -0,0 +1,7 @@
+
+
+
+ InjectorLib
+
+
+
\ No newline at end of file
diff --git a/Launcher.csproj b/Launcher.csproj
new file mode 100644
index 0000000..f450fa7
--- /dev/null
+++ b/Launcher.csproj
@@ -0,0 +1,404 @@
+
+
+
+
+
+ Debug
+ AnyCPU
+ {D3AA2F83-0262-4994-928F-497847A6C8EC}
+ WinExe
+ Launcher
+ Launcher
+ v4.7.2
+ 512
+ {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ 4
+ true
+ true
+
+
+
+
+ AnyCPU
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ AnyCPU
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+ app.manifest
+
+
+ true
+ bin\x64\Debug\
+ DEBUG;TRACE
+ full
+ x64
+ 7.3
+ prompt
+ true
+
+
+ bin\x64\Release\
+ TRACE
+ true
+ pdbonly
+ x64
+ 7.3
+ prompt
+ true
+
+
+ 4.0
+ zh-CN
+ true
+ true
+
+
+
+ packages\Portable.BouncyCastle.1.8.8\lib\net40\BouncyCastle.Crypto.dll
+
+
+ packages\BrotliSharpLib.0.3.3\lib\net451\BrotliSharpLib.dll
+
+
+ packages\CommunityToolkit.Mvvm.8.0.0\lib\netstandard2.0\CommunityToolkit.Mvvm.dll
+
+
+ packages\Costura.Fody.5.7.0\lib\netstandard1.0\Costura.dll
+
+
+ .\InjectorLib.dll
+
+
+ packages\Microsoft.Bcl.AsyncInterfaces.6.0.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll
+
+
+ packages\Microsoft.Win32.Primitives.4.3.0\lib\net46\Microsoft.Win32.Primitives.dll
+ True
+ True
+
+
+ packages\Microsoft.Win32.Registry.5.0.0\lib\net461\Microsoft.Win32.Registry.dll
+
+
+ packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll
+
+
+ packages\Panuon.WPF.1.0.1\lib\net472\Panuon.WPF.dll
+
+
+ packages\Panuon.WPF.UI.1.1.6.5\lib\net472\Panuon.WPF.UI.dll
+
+
+
+ packages\System.AppContext.4.3.0\lib\net463\System.AppContext.dll
+ True
+ True
+
+
+ packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll
+
+
+ packages\System.ComponentModel.Annotations.5.0.0\lib\net461\System.ComponentModel.Annotations.dll
+
+
+
+
+ packages\System.Console.4.3.0\lib\net46\System.Console.dll
+ True
+ True
+
+
+
+ packages\System.Diagnostics.DiagnosticSource.4.3.0\lib\net46\System.Diagnostics.DiagnosticSource.dll
+
+
+ packages\System.Diagnostics.Tracing.4.3.0\lib\net462\System.Diagnostics.Tracing.dll
+ True
+ True
+
+
+ packages\System.Globalization.Calendars.4.3.0\lib\net46\System.Globalization.Calendars.dll
+ True
+ True
+
+
+ packages\System.IO.4.3.0\lib\net462\System.IO.dll
+ True
+ True
+
+
+ packages\System.IO.Compression.4.3.0\lib\net46\System.IO.Compression.dll
+ True
+ True
+
+
+
+ packages\System.IO.Compression.ZipFile.4.3.0\lib\net46\System.IO.Compression.ZipFile.dll
+ True
+ True
+
+
+ packages\System.IO.FileSystem.4.3.0\lib\net46\System.IO.FileSystem.dll
+ True
+ True
+
+
+ packages\System.IO.FileSystem.Primitives.4.3.0\lib\net46\System.IO.FileSystem.Primitives.dll
+ True
+ True
+
+
+ packages\System.Linq.4.3.0\lib\net463\System.Linq.dll
+ True
+ True
+
+
+ packages\System.Linq.Expressions.4.3.0\lib\net463\System.Linq.Expressions.dll
+ True
+ True
+
+
+ packages\System.Memory.4.5.5\lib\net461\System.Memory.dll
+
+
+ packages\System.Net.Http.4.3.0\lib\net46\System.Net.Http.dll
+ True
+ True
+
+
+ packages\System.Net.Sockets.4.3.0\lib\net46\System.Net.Sockets.dll
+ True
+ True
+
+
+
+ packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll
+
+
+ packages\System.Reflection.4.3.0\lib\net462\System.Reflection.dll
+ True
+ True
+
+
+ packages\System.Runtime.4.3.0\lib\net462\System.Runtime.dll
+ True
+ True
+
+
+ packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll
+
+
+ packages\System.Runtime.Extensions.4.3.0\lib\net462\System.Runtime.Extensions.dll
+ True
+ True
+
+
+ packages\System.Runtime.InteropServices.4.3.0\lib\net463\System.Runtime.InteropServices.dll
+ True
+ True
+
+
+ packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll
+ True
+ True
+
+
+ packages\System.Security.AccessControl.5.0.0\lib\net461\System.Security.AccessControl.dll
+
+
+ packages\System.Security.Cryptography.Algorithms.4.3.0\lib\net463\System.Security.Cryptography.Algorithms.dll
+ True
+ True
+
+
+ packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll
+ True
+ True
+
+
+ packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll
+ True
+ True
+
+
+ packages\System.Security.Cryptography.X509Certificates.4.3.0\lib\net461\System.Security.Cryptography.X509Certificates.dll
+ True
+ True
+
+
+ packages\System.Security.Principal.Windows.5.0.0\lib\net461\System.Security.Principal.Windows.dll
+
+
+ packages\System.Text.RegularExpressions.4.3.0\lib\net463\System.Text.RegularExpressions.dll
+ True
+ True
+
+
+ packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll
+
+
+
+
+
+
+
+ 4.0
+
+
+ packages\System.Xml.ReaderWriter.4.3.0\lib\net46\System.Xml.ReaderWriter.dll
+ True
+ True
+
+
+ packages\Titanium.Web.Proxy.3.2.0\lib\net461\Titanium.Web.Proxy.dll
+
+
+
+
+
+
+
+ MSBuild:Compile
+ Designer
+
+
+
+
+
+
+
+ ServerEditControl.xaml
+
+
+ SnackBar.xaml
+
+
+
+
+
+
+
+
+
+ About.xaml
+
+
+ Home.xaml
+
+
+ Setting.xaml
+
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
+
+ MSBuild:Compile
+ Designer
+
+
+ App.xaml
+ Code
+
+
+ MainWindow.xaml
+ Code
+
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
+
+
+
+ Code
+
+
+ True
+ True
+ Resources.resx
+
+
+ True
+ Settings.settings
+ True
+
+
+
+ PublicResXFileCodeGenerator
+ Resources.Designer.cs
+
+
+
+
+ SettingsSingleFileGenerator
+ Settings.Designer.cs
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 这台计算机上缺少此项目引用的 NuGet 程序包。使用“NuGet 程序包还原”可下载这些程序包。有关更多信息,请参见 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Launcher.sln b/Launcher.sln
new file mode 100644
index 0000000..efdc592
--- /dev/null
+++ b/Launcher.sln
@@ -0,0 +1,51 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.3.32901.215
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Launcher", "Launcher.csproj", "{D3AA2F83-0262-4994-928F-497847A6C8EC}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "InjectorLib", "..\InjectorLib\InjectorLib.vcxproj", "{6858E5BA-50F9-489C-98BB-69A785A6FF31}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|Any CPU = Release|Any CPU
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {D3AA2F83-0262-4994-928F-497847A6C8EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D3AA2F83-0262-4994-928F-497847A6C8EC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D3AA2F83-0262-4994-928F-497847A6C8EC}.Debug|x64.ActiveCfg = Debug|x64
+ {D3AA2F83-0262-4994-928F-497847A6C8EC}.Debug|x64.Build.0 = Debug|x64
+ {D3AA2F83-0262-4994-928F-497847A6C8EC}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {D3AA2F83-0262-4994-928F-497847A6C8EC}.Debug|x86.Build.0 = Debug|Any CPU
+ {D3AA2F83-0262-4994-928F-497847A6C8EC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D3AA2F83-0262-4994-928F-497847A6C8EC}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D3AA2F83-0262-4994-928F-497847A6C8EC}.Release|x64.ActiveCfg = Release|x64
+ {D3AA2F83-0262-4994-928F-497847A6C8EC}.Release|x64.Build.0 = Release|x64
+ {D3AA2F83-0262-4994-928F-497847A6C8EC}.Release|x86.ActiveCfg = Release|Any CPU
+ {D3AA2F83-0262-4994-928F-497847A6C8EC}.Release|x86.Build.0 = Release|Any CPU
+ {6858E5BA-50F9-489C-98BB-69A785A6FF31}.Debug|Any CPU.ActiveCfg = Debug|x64
+ {6858E5BA-50F9-489C-98BB-69A785A6FF31}.Debug|Any CPU.Build.0 = Debug|x64
+ {6858E5BA-50F9-489C-98BB-69A785A6FF31}.Debug|x64.ActiveCfg = Debug|x64
+ {6858E5BA-50F9-489C-98BB-69A785A6FF31}.Debug|x64.Build.0 = Debug|x64
+ {6858E5BA-50F9-489C-98BB-69A785A6FF31}.Debug|x86.ActiveCfg = Debug|Win32
+ {6858E5BA-50F9-489C-98BB-69A785A6FF31}.Debug|x86.Build.0 = Debug|Win32
+ {6858E5BA-50F9-489C-98BB-69A785A6FF31}.Release|Any CPU.ActiveCfg = Release|x64
+ {6858E5BA-50F9-489C-98BB-69A785A6FF31}.Release|Any CPU.Build.0 = Release|x64
+ {6858E5BA-50F9-489C-98BB-69A785A6FF31}.Release|x64.ActiveCfg = Release|x64
+ {6858E5BA-50F9-489C-98BB-69A785A6FF31}.Release|x64.Build.0 = Release|x64
+ {6858E5BA-50F9-489C-98BB-69A785A6FF31}.Release|x86.ActiveCfg = Release|Win32
+ {6858E5BA-50F9-489C-98BB-69A785A6FF31}.Release|x86.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {176C524C-E912-426F-A7B3-ADBCAF646C01}
+ EndGlobalSection
+EndGlobal
diff --git a/MainWindow.xaml b/MainWindow.xaml
new file mode 100644
index 0000000..630feeb
--- /dev/null
+++ b/MainWindow.xaml
@@ -0,0 +1,137 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/MainWindow.xaml.cs b/MainWindow.xaml.cs
new file mode 100644
index 0000000..fa3c0c1
--- /dev/null
+++ b/MainWindow.xaml.cs
@@ -0,0 +1,54 @@
+using Launcher.Model;
+using System;
+using System.Globalization;
+using System.Threading;
+using System.Windows;
+using System.Windows.Controls;
+
+namespace Launcher
+{
+ ///
+ /// MainWindow.xaml 的交互逻辑
+ ///
+ public partial class MainWindow : Window
+ {
+ public static MainWindow Instance { get; private set; }
+
+
+ public MainWindow()
+ {
+ InitializeComponent();
+ Instance = this;
+
+ }
+
+ protected override void OnSourceInitialized(EventArgs e)
+ {
+ base.OnSourceInitialized(e);
+
+ }
+
+ private void Button_Click(object sender, RoutedEventArgs e)
+ {
+ Close();
+ }
+
+ private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
+ {
+ var lb = sender as ListBox;
+
+ if (rootFrame == null)
+ {
+ return;
+ }
+ switch (lb.SelectedIndex)
+ {
+ case 0: rootFrame.Navigate(new Uri("View/Home.xaml", UriKind.Relative)); break;
+ case 1: rootFrame.Navigate(new Uri("View/Setting.xaml", UriKind.Relative)); break;
+ case 2: rootFrame.Navigate(new Uri("View/About.xaml", UriKind.Relative)); break;
+ default:
+ break;
+ }
+ }
+ }
+}
diff --git a/Model/GameInfo.cs b/Model/GameInfo.cs
new file mode 100644
index 0000000..9120379
--- /dev/null
+++ b/Model/GameInfo.cs
@@ -0,0 +1,79 @@
+using System.IO;
+
+namespace Launcher.Model
+{
+ //public enum GameVer
+ //{
+ // OSRELWin3_2_0,
+ // CNRELWin3_2_0
+ //}
+
+ public class GameInfo
+ {
+ public string GameExeFolder
+ {
+ get
+ {
+ return Path.GetDirectoryName(GameExePath);
+ }
+ }
+
+ public string GetGameDataFolder()
+ {
+ var dataDirName = string.Empty;
+ switch (GetGameType())
+ {
+ case GameType.CN:
+ dataDirName = "YuanShen_Data";
+ break;
+ case GameType.OS:
+ dataDirName = "GenshinImpact_Data";
+
+ break;
+ default:
+ break;
+ }
+ return Path.Combine(GameExeFolder, dataDirName);
+ }
+
+ //public GameVer? Version { get; set; }
+
+ public GameInfo(string gameExePath)
+ {
+ GameExePath = gameExePath;
+
+ //Version = null;
+ //GameExeFolder = Path.GetDirectoryName(gameExePath);
+
+
+ }
+
+
+
+ public enum GameType
+ {
+ CN,
+ OS,
+ UnKnown,
+ }
+
+ public GameType GetGameType()
+ {
+ GameType gameType = GameType.UnKnown;
+
+ if (Directory.Exists(Path.Combine(GameExeFolder, "YuanShen_Data")))
+ {
+ gameType = GameType.CN;
+ }
+ else if (Directory.Exists(Path.Combine(GameExeFolder, "GenshinImpact_Data")))
+ {
+ gameType = GameType.OS;
+ }
+
+ return gameType;
+ }
+
+ public string GameExePath { get; set; }
+
+ }
+}
diff --git a/Model/LauncherConfig.cs b/Model/LauncherConfig.cs
new file mode 100644
index 0000000..6333f50
--- /dev/null
+++ b/Model/LauncherConfig.cs
@@ -0,0 +1,92 @@
+using CommunityToolkit.Mvvm.ComponentModel;
+using Newtonsoft.Json;
+using Panuon.WPF;
+using System.Collections.ObjectModel;
+using System.IO;
+using static Org.BouncyCastle.Math.EC.ECCurve;
+
+namespace Launcher.Model
+{
+ public enum ProxyType
+ {
+ OFFICIAL,
+ PRIVATE,
+ PROXY_ONLY
+ }
+
+
+ public partial class LauncherConfig : ObservableObject
+ {
+
+
+
+ public static LauncherConfig Load(string file)
+ {
+ if (File.Exists(file))
+ {
+ var content = File.ReadAllText(file);
+ return JsonConvert.DeserializeObject(content) ?? new LauncherConfig();
+ }
+ else
+ {
+ return new LauncherConfig();
+ }
+ }
+
+ public void Save(string file)
+ {
+ File.WriteAllText(file, JsonConvert.SerializeObject(this));
+ }
+
+
+
+ //public GameInfo GameInfo { get; set; }
+ //public ProxyType ProxyType { get; set; }
+ //public ObservableCollection Servers { get; set; }
+
+ public bool DebugMode { get; set; }
+
+ public string Language { get; set; }
+
+
+ public string BgUrl { get; set; } = "https://i0.hdslb.com/bfs/new_dyn/be2c9d48dfa1e57161609e693b48982a401742377.png";
+
+ private GameInfo gameInfo;
+
+ private ProxyType pType;
+
+ public ProxyType ProxyType
+ {
+ get { return pType; }
+ set { SetProperty(ref pType, value); }
+ }
+
+
+ public GameInfo GameInfo
+ {
+ get { return gameInfo; }
+ set { SetProperty(ref gameInfo, value); }
+ }
+
+ private int selectedSrvIndex;
+
+ public int SelectedSrvIndex
+ {
+ get { return selectedSrvIndex; }
+ set { SetProperty(ref selectedSrvIndex , value); }
+ }
+
+
+ private ObservableCollection servers = new ObservableCollection();
+
+ public ObservableCollection Servers
+ {
+ get { return servers; }
+ set { SetProperty(ref servers, value); }
+ }
+
+
+
+
+ }
+}
diff --git a/Model/PkgVersionItem.cs b/Model/PkgVersionItem.cs
new file mode 100644
index 0000000..813267e
--- /dev/null
+++ b/Model/PkgVersionItem.cs
@@ -0,0 +1,22 @@
+using System;
+
+namespace Launcher.Model
+{
+ [Obsolete]
+ public class PkgVersionItem
+ {
+ ///
+ ///
+ ///
+ public string remoteName { get; set; }
+ ///
+ ///
+ ///
+ public string md5 { get; set; }
+ ///
+ ///
+ ///
+ public int fileSize { get; set; }
+
+ }
+}
diff --git a/Model/ProxyConfig.cs b/Model/ProxyConfig.cs
new file mode 100644
index 0000000..6c8a48e
--- /dev/null
+++ b/Model/ProxyConfig.cs
@@ -0,0 +1,21 @@
+namespace Launcher.Model
+{
+ public class ProxyConfig
+ {
+
+ public ProxyConfig(string proxyServer, bool usehttp = false, string proxyPort = "25565")
+ {
+ ProxyServer = proxyServer;
+ UseHttp = usehttp;
+ ProxyPort = proxyPort;
+ }
+
+ public string ProxyServer { get; set; }
+
+ public string ProxyPort { get; set; }
+
+ public bool UseHttp { get; set; }
+ public bool ProxyEnable { get; internal set; }
+
+ }
+}
diff --git a/Model/ServerItem.cs b/Model/ServerItem.cs
new file mode 100644
index 0000000..a751962
--- /dev/null
+++ b/Model/ServerItem.cs
@@ -0,0 +1,14 @@
+namespace Launcher.Model
+{
+ public class ServerItem
+ {
+ public string Name { get; set; }
+ public string Description { get; set; }
+
+ public ProxyConfig proxy { get; set; }
+
+ public string RSAPublicKey { get; set; }
+
+ public string RSAPrivateKey { get; set; }
+ }
+}
diff --git a/MultilingualResources/Launcher.en.xlf b/MultilingualResources/Launcher.en.xlf
new file mode 100644
index 0000000..66ebacb
--- /dev/null
+++ b/MultilingualResources/Launcher.en.xlf
@@ -0,0 +1,201 @@
+
+
+
+
+
+
+
+
+ About
+
+
+
+ Home
+
+
+
+ Settings
+
+
+
+ + Supported versions: 3.1, 3.2, 3.2.50, 3.3, Synchronized with gc toolkit/RSAPatch.
+
+
+
+ Auto Detect
+
+
+
+ Manual
+
+
+
+ Enable DebugMode
+
+
+
+ About
+
+
+
+ Development
+
+
+
+ General
+
+
+
+ [appreciate]:https://github.com/34736384/RSAPatch
+
+
+
+ [Source Code]:https://github.com/gc-toolkit/Launcher
+
+
+
+ Official Mode
+
+
+
+ Private Mode
+
+
+
+ Proxy Only
+
+
+
+ Background Image
+
+
+
+ GamePath
+
+
+
+ Select a server
+
+
+
+ Running
+
+
+
+ Play
+
+
+
+ StartProxy
+
+
+
+ StopProxy
+
+
+
+ Add
+
+
+
+ Delete
+
+
+
+ Edit
+
+
+
+ Export to Clipboard
+
+
+
+ Import from clipboard
+
+
+
+ Available servers:
+
+
+
+ Please set the correct game path!
+
+
+
+ Export succeeded!
+
+
+
+ Import failed!
+
+
+
+ Import succeeded!
+
+
+
+ Can't start the game now!
+
+
+
+ Please add and select at least one server!
+
+
+
+ Please select a server!
+
+
+
+ Please set the game directory and game version first!
+
+
+
+ Use HTTP
+
+
+
+ Server Profile Edit
+
+
+
+ Detect failed, there is no relevant information in the registry!
+
+
+
+ Found game file at {0}!
+ Please verify the translation’s accuracy as the source string was updated after it was translated.
+
+
+
+ Server Name
+
+
+
+ Advanced
+
+
+
+ Apply
+
+
+
+ PrivateKey: If it is empty, it will be disabled.
+
+
+
+ PublicKey: If it is empty, it will use grasscutter's ley.
+
+
+
+ An instance is already running
+
+
+
+ Crashed
+
+
+
+
+
\ No newline at end of file
diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..324d404
--- /dev/null
+++ b/Properties/AssemblyInfo.cs
@@ -0,0 +1,53 @@
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Windows;
+
+// 有关程序集的一般信息由以下
+// 控制。更改这些特性值可修改
+// 与程序集关联的信息。
+[assembly: AssemblyTitle("Launcher")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Launcher")]
+[assembly: AssemblyCopyright("Copyright © 2022")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// 将 ComVisible 设置为 false 会使此程序集中的类型
+//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
+//请将此类型的 ComVisible 特性设置为 true。
+[assembly: ComVisible(false)]
+
+//若要开始生成可本地化的应用程序,请设置
+//.csproj 文件中的 CultureYouAreCodingWith
+//例如,如果您在源文件中使用的是美国英语,
+//使用的是美国英语,请将 设置为 en-US。 然后取消
+//对以下 NeutralResourceLanguage 特性的注释。 更新
+//以下行中的“en-US”以匹配项目文件中的 UICulture 设置。
+
+//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
+
+
+[assembly: ThemeInfo(
+ ResourceDictionaryLocation.None, //主题特定资源词典所处位置
+ //(未在页面中找到资源时使用,
+ //或应用程序资源字典中找到时使用)
+ ResourceDictionaryLocation.SourceAssembly //常规资源词典所处位置
+ //(未在页面中找到资源时使用,
+ //、应用程序或任何主题专用资源字典中找到时使用)
+)]
+
+
+// 程序集的版本信息由下列四个值组成:
+//
+// 主版本
+// 次版本
+// 生成号
+// 修订号
+//
+//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
+//通过使用 "*",如下所示:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/Properties/Resources.Designer.cs b/Properties/Resources.Designer.cs
new file mode 100644
index 0000000..0dcc418
--- /dev/null
+++ b/Properties/Resources.Designer.cs
@@ -0,0 +1,486 @@
+//------------------------------------------------------------------------------
+//
+// 此代码由工具生成。
+// 运行时版本:4.0.30319.42000
+//
+// 对此文件的更改可能会导致不正确的行为,并且如果
+// 重新生成代码,这些更改将会丢失。
+//
+//------------------------------------------------------------------------------
+
+namespace Launcher.Properties {
+ using System;
+
+
+ ///
+ /// 一个强类型的资源类,用于查找本地化的字符串等。
+ ///
+ // 此类是由 StronglyTypedResourceBuilder
+ // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
+ // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
+ // (以 /str 作为命令选项),或重新生成 VS 项目。
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ public class Resources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources() {
+ }
+
+ ///
+ /// 返回此类使用的缓存的 ResourceManager 实例。
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ public static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Launcher.Properties.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// 重写当前线程的 CurrentUICulture 属性,对
+ /// 使用此强类型资源类的所有资源查找执行重写。
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ public static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ ///
+ /// 查找类似 + 支持的版本:3.1, 3.2, 3.2.50, 3.3, 与 gc-toolkit/RSAPatch 保持同步。 的本地化字符串。
+ ///
+ public static string about_desp {
+ get {
+ return ResourceManager.GetString("about_desp", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 正在运行 的本地化字符串。
+ ///
+ public static string btn_running {
+ get {
+ return ResourceManager.GetString("btn_running", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 自动搜索 的本地化字符串。
+ ///
+ public static string btn_searchgame {
+ get {
+ return ResourceManager.GetString("btn_searchgame", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 手动选择 的本地化字符串。
+ ///
+ public static string btn_selectgame {
+ get {
+ return ResourceManager.GetString("btn_selectgame", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 开始游戏 的本地化字符串。
+ ///
+ public static string btn_startgame {
+ get {
+ return ResourceManager.GetString("btn_startgame", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 开启代理 的本地化字符串。
+ ///
+ public static string btn_startproxy {
+ get {
+ return ResourceManager.GetString("btn_startproxy", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 关闭代理 的本地化字符串。
+ ///
+ public static string btn_stopproxy {
+ get {
+ return ResourceManager.GetString("btn_stopproxy", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 开启调试 的本地化字符串。
+ ///
+ public static string cb_enabledebug {
+ get {
+ return ResourceManager.GetString("cb_enabledebug", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 使用http 的本地化字符串。
+ ///
+ public static string cb_usehttp {
+ get {
+ return ResourceManager.GetString("cb_usehttp", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 添加 的本地化字符串。
+ ///
+ public static string cm_add {
+ get {
+ return ResourceManager.GetString("cm_add", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 删除 的本地化字符串。
+ ///
+ public static string cm_del {
+ get {
+ return ResourceManager.GetString("cm_del", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 编辑 的本地化字符串。
+ ///
+ public static string cm_edit {
+ get {
+ return ResourceManager.GetString("cm_edit", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 导出到剪贴板 的本地化字符串。
+ ///
+ public static string cm_export {
+ get {
+ return ResourceManager.GetString("cm_export", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 从剪贴板导入 的本地化字符串。
+ ///
+ public static string cm_import {
+ get {
+ return ResourceManager.GetString("cm_import", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 关于 的本地化字符串。
+ ///
+ public static string h_about {
+ get {
+ return ResourceManager.GetString("h_about", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 开发 的本地化字符串。
+ ///
+ public static string h_develop {
+ get {
+ return ResourceManager.GetString("h_develop", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 常规 的本地化字符串。
+ ///
+ public static string h_general {
+ get {
+ return ResourceManager.GetString("h_general", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 服务器编辑 的本地化字符串。
+ ///
+ public static string h_serveredit {
+ get {
+ return ResourceManager.GetString("h_serveredit", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 可用服务器: 的本地化字符串。
+ ///
+ public static string h_servers {
+ get {
+ return ResourceManager.GetString("h_servers", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 关于 的本地化字符串。
+ ///
+ public static string nav_about {
+ get {
+ return ResourceManager.GetString("nav_about", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 主页 的本地化字符串。
+ ///
+ public static string nav_home {
+ get {
+ return ResourceManager.GetString("nav_home", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 设置 的本地化字符串。
+ ///
+ public static string nav_setting {
+ get {
+ return ResourceManager.GetString("nav_setting", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 [感谢]:https://github.com/34736384/RSAPatch 的本地化字符串。
+ ///
+ public static string repo1 {
+ get {
+ return ResourceManager.GetString("repo1", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 [开源地址]:https://github.com/gc-toolkit/Launcher 的本地化字符串。
+ ///
+ public static string repoinfo {
+ get {
+ return ResourceManager.GetString("repoinfo", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 高级 的本地化字符串。
+ ///
+ public static string t_advanced {
+ get {
+ return ResourceManager.GetString("t_advanced", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 官方 的本地化字符串。
+ ///
+ public static string tab_official {
+ get {
+ return ResourceManager.GetString("tab_official", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 私有 的本地化字符串。
+ ///
+ public static string tab_private {
+ get {
+ return ResourceManager.GetString("tab_private", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 仅代理 的本地化字符串。
+ ///
+ public static string tab_proxyonly {
+ get {
+ return ResourceManager.GetString("tab_proxyonly", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 确定 的本地化字符串。
+ ///
+ public static string tb_ok {
+ get {
+ return ResourceManager.GetString("tb_ok", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 背景图片 的本地化字符串。
+ ///
+ public static string tbtip_bgurl {
+ get {
+ return ResourceManager.GetString("tbtip_bgurl", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 游戏路径 的本地化字符串。
+ ///
+ public static string tbtip_gamepath {
+ get {
+ return ResourceManager.GetString("tbtip_gamepath", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 已经有一个启动器在运行 的本地化字符串。
+ ///
+ public static string tip_alreadyrunning {
+ get {
+ return ResourceManager.GetString("tip_alreadyrunning", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 请设置正确的游戏路径! 的本地化字符串。
+ ///
+ public static string tip_correctgamepath {
+ get {
+ return ResourceManager.GetString("tip_correctgamepath", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 崩溃了 的本地化字符串。
+ ///
+ public static string tip_crash_title {
+ get {
+ return ResourceManager.GetString("tip_crash_title", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 导出成功! 的本地化字符串。
+ ///
+ public static string tip_exp_succ {
+ get {
+ return ResourceManager.GetString("tip_exp_succ", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 导入失败! 的本地化字符串。
+ ///
+ public static string tip_imp_err {
+ get {
+ return ResourceManager.GetString("tip_imp_err", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 导入成功! 的本地化字符串。
+ ///
+ public static string tip_imp_succ {
+ get {
+ return ResourceManager.GetString("tip_imp_succ", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 现在不能开始游戏! 的本地化字符串。
+ ///
+ public static string tip_nostart {
+ get {
+ return ResourceManager.GetString("tip_nostart", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 PrivateKey,为空则禁用 的本地化字符串。
+ ///
+ public static string tip_privatekey {
+ get {
+ return ResourceManager.GetString("tip_privatekey", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 PublicKey,为空则选择割草机的key 的本地化字符串。
+ ///
+ public static string tip_publickey {
+ get {
+ return ResourceManager.GetString("tip_publickey", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 请至少添加并选择一个服务器! 的本地化字符串。
+ ///
+ public static string tip_reqaddone {
+ get {
+ return ResourceManager.GetString("tip_reqaddone", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 请选择一个服务器! 的本地化字符串。
+ ///
+ public static string tip_reqselectone {
+ get {
+ return ResourceManager.GetString("tip_reqselectone", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 搜索失败,注册表中没有相关信息! 的本地化字符串。
+ ///
+ public static string tip_search_err {
+ get {
+ return ResourceManager.GetString("tip_search_err", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 选择一个服务器 的本地化字符串。
+ ///
+ public static string tip_selectone {
+ get {
+ return ResourceManager.GetString("tip_selectone", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 已找到位于{0}的游戏文件! 的本地化字符串。
+ ///
+ public static string tip_serach_succ {
+ get {
+ return ResourceManager.GetString("tip_serach_succ", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 请先设置 游戏目录 和 游戏版本! 的本地化字符串。
+ ///
+ public static string tip_setcfg {
+ get {
+ return ResourceManager.GetString("tip_setcfg", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 服务器名称 的本地化字符串。
+ ///
+ public static string tip_srvname {
+ get {
+ return ResourceManager.GetString("tip_srvname", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/Properties/Resources.en.resx b/Properties/Resources.en.resx
new file mode 100644
index 0000000..3e01ea7
--- /dev/null
+++ b/Properties/Resources.en.resx
@@ -0,0 +1,150 @@
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ About
+
+
+ Home
+
+
+ Settings
+
+
+ + Supported versions: 3.1, 3.2, 3.2.50, 3.3, Synchronized with gc toolkit/RSAPatch.
+
+
+ Auto Detect
+
+
+ Manual
+
+
+ Enable DebugMode
+
+
+ About
+
+
+ Development
+
+
+ General
+
+
+ [appreciate]:https://github.com/34736384/RSAPatch
+
+
+ [Source Code]:https://github.com/gc-toolkit/Launcher
+
+
+ Official Mode
+
+
+ Private Mode
+
+
+ Proxy Only
+
+
+ Background Image
+
+
+ GamePath
+
+
+ Select a server
+
+
+ Running
+
+
+ Play
+
+
+ StartProxy
+
+
+ StopProxy
+
+
+ Add
+
+
+ Delete
+
+
+ Edit
+
+
+ Export to Clipboard
+
+
+ Import from clipboard
+
+
+ Available servers:
+
+
+ Please set the correct game path!
+
+
+ Export succeeded!
+
+
+ Import failed!
+
+
+ Import succeeded!
+
+
+ Can't start the game now!
+
+
+ Please add and select at least one server!
+
+
+ Please select a server!
+
+
+ Please set the game directory and game version first!
+
+
+ Use HTTP
+
+
+ Server Profile Edit
+
+
+ Detect failed, there is no relevant information in the registry!
+
+
+ Found game file at {0}!
+
+
+ Server Name
+
+
+ Advanced
+
+
+ Apply
+
+
+ PrivateKey: If it is empty, it will be disabled.
+
+
+ PublicKey: If it is empty, it will use grasscutter's ley.
+
+
\ No newline at end of file
diff --git a/Properties/Resources.resx b/Properties/Resources.resx
new file mode 100644
index 0000000..554657a
--- /dev/null
+++ b/Properties/Resources.resx
@@ -0,0 +1,261 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ + 支持的版本:3.1, 3.2, 3.2.50, 3.3, 与 gc-toolkit/RSAPatch 保持同步。
+
+
+ 正在运行
+
+
+ 自动搜索
+
+
+ 手动选择
+
+
+ 开始游戏
+
+
+ 开启代理
+
+
+ 关闭代理
+
+
+ 开启调试
+
+
+ 使用http
+
+
+ 添加
+
+
+ 删除
+
+
+ 编辑
+
+
+ 导出到剪贴板
+
+
+ 从剪贴板导入
+
+
+ 关于
+
+
+ 开发
+
+
+ 常规
+
+
+ 服务器编辑
+
+
+ 可用服务器:
+
+
+ 关于
+
+
+ 主页
+
+
+ 设置
+
+
+ [感谢]:https://github.com/34736384/RSAPatch
+
+
+ [开源地址]:https://github.com/gc-toolkit/Launcher
+
+
+ 官方
+
+
+ 私有
+
+
+ 仅代理
+
+
+ 背景图片
+
+
+ 游戏路径
+
+
+ 确定
+
+
+ 已经有一个启动器在运行
+
+
+ 请设置正确的游戏路径!
+
+
+ 崩溃了
+
+
+ 导出成功!
+
+
+ 导入失败!
+
+
+ 导入成功!
+
+
+ 现在不能开始游戏!
+
+
+ PrivateKey,为空则禁用
+
+
+ PublicKey,为空则选择割草机的key
+
+
+ 请至少添加并选择一个服务器!
+
+
+ 请选择一个服务器!
+
+
+ 搜索失败,注册表中没有相关信息!
+
+
+ 选择一个服务器
+
+
+ 已找到位于{0}的游戏文件!
+
+
+ 请先设置 游戏目录 和 游戏版本!
+
+
+ 服务器名称
+
+
+ 高级
+
+
\ No newline at end of file
diff --git a/Properties/Settings.Designer.cs b/Properties/Settings.Designer.cs
new file mode 100644
index 0000000..2ae0089
--- /dev/null
+++ b/Properties/Settings.Designer.cs
@@ -0,0 +1,30 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace Launcher.Properties
+{
+
+
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
+ internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
+ {
+
+ private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
+
+ public static Settings Default
+ {
+ get
+ {
+ return defaultInstance;
+ }
+ }
+ }
+}
diff --git a/Properties/Settings.settings b/Properties/Settings.settings
new file mode 100644
index 0000000..033d7a5
--- /dev/null
+++ b/Properties/Settings.settings
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..ad2aab7
--- /dev/null
+++ b/README.md
@@ -0,0 +1,32 @@
+# Launcher
+> 新一代的游戏启动器
+
+
+# ✨ 功能
++ 提供 http / https 代理转向
++ 防止游戏出现4214错误 (多种key切换,支持 publickey 和 privatekey)
++ 多服务器支持
++ 不需更改客户端内任何文件
++ 多种启动方式支持 [官方| 割草机| 仅代理]
+
+
+# 🖼️预览
+![image](https://user-images.githubusercontent.com/68674499/206622660-9c1590d3-8adb-4d1f-aed9-17639eca9c67.png)
+
+![image](https://user-images.githubusercontent.com/68674499/206622695-99204b8e-047d-45e3-be9b-d9aed97fd72d.png)
+
+
+# 🎁使用
+
+1. 前往 [Release](https://github.com/gc-toolkit/Launcher/releases) 下载
+2. 放到到任意目录
+3. 双击运行
+
+# 🐛常见问题
+
+前往 [Issues](https://github.com/gc-toolkit/Launcher/issues) 具体描述你遇到的问题
+
+# 🙇感谢
+
+[https://github.com/34736384/RSAPatch](https://github.com/34736384/RSAPatch)
+[akebi](/)
diff --git a/RSAPatch/PublicKey.txt b/RSAPatch/PublicKey.txt
new file mode 100644
index 0000000..8777005
--- /dev/null
+++ b/RSAPatch/PublicKey.txt
@@ -0,0 +1 @@
+xbbx2m1feHyrQ7jP+8mtDF/pyYLrJWKWAdEv3wZrOtjOZzeLGPzsmkcgncgoRhX4dT+1itSMR9j9m0/OwsH2UoF6U32LxCOQWQD1AMgIZjAkJeJvFTrtn8fMQ1701CkbaLTVIjRMlTw8kNXvNA/A9UatoiDmi4TFG6mrxTKZpIcTInvPEpkK2A7Qsp1E4skFK8jmysy7uRhMaYHtPTsBvxP0zn3lhKB3W+HTqpneewXWHjCDfL7Nbby91jbz5EKPZXWLuhXIvR1Cu4tiruorwXJxmXaP1HQZonytECNU/UOzP6GNLdq0eFDE4b04Wjp396551G99YiFP2nqHVJ5OMQ==AQAB
\ No newline at end of file
diff --git a/RSAPatch/RSAPatch.dll b/RSAPatch/RSAPatch.dll
new file mode 100644
index 0000000..a980fc3
Binary files /dev/null and b/RSAPatch/RSAPatch.dll differ
diff --git a/RSAPatch/rsa.dll.bak b/RSAPatch/rsa.dll.bak
new file mode 100644
index 0000000..433241b
Binary files /dev/null and b/RSAPatch/rsa.dll.bak differ
diff --git a/Res/remixicon.ttf b/Res/remixicon.ttf
new file mode 100644
index 0000000..c461f40
Binary files /dev/null and b/Res/remixicon.ttf differ
diff --git a/Style/IconButtonStyle.xaml b/Style/IconButtonStyle.xaml
new file mode 100644
index 0000000..825650e
--- /dev/null
+++ b/Style/IconButtonStyle.xaml
@@ -0,0 +1,4 @@
+
+
+
\ No newline at end of file
diff --git a/Style/NavigationItemContainerStyle.xaml b/Style/NavigationItemContainerStyle.xaml
new file mode 100644
index 0000000..baabf3a
--- /dev/null
+++ b/Style/NavigationItemContainerStyle.xaml
@@ -0,0 +1,87 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/View/About.xaml b/View/About.xaml
new file mode 100644
index 0000000..fc4a8c2
--- /dev/null
+++ b/View/About.xaml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/View/About.xaml.cs b/View/About.xaml.cs
new file mode 100644
index 0000000..129c660
--- /dev/null
+++ b/View/About.xaml.cs
@@ -0,0 +1,35 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+
+namespace Launcher.View
+{
+ ///
+ /// About.xaml 的交互逻辑
+ ///
+ public partial class About : Page
+ {
+ public About()
+ {
+ InitializeComponent();
+ }
+
+ private void TextBlock_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
+ {
+ var tb = sender as TextBlock;
+ Process.Start("explorer.exe", tb.Tag.ToString());
+ }
+ }
+}
diff --git a/View/Home.xaml b/View/Home.xaml
new file mode 100644
index 0000000..896aa9a
--- /dev/null
+++ b/View/Home.xaml
@@ -0,0 +1,300 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Styles are the visual aspects of a UI that give it a distinct look and feel.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/View/Home.xaml.cs b/View/Home.xaml.cs
new file mode 100644
index 0000000..7744ef4
--- /dev/null
+++ b/View/Home.xaml.cs
@@ -0,0 +1,43 @@
+using System.Windows.Controls;
+
+namespace Launcher.View
+{
+ ///
+ /// Home.xaml 的交互逻辑
+ ///
+ public partial class Home : Page
+ {
+ public Home()
+ {
+ InitializeComponent();
+ DataContext = ViewModel.HomeVM.Instacne;
+ pt.SelectedIndex = (int)ViewModel.HomeVM.Instacne.LauncherConfig.ProxyType;
+ }
+
+ private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
+ {
+ var list = (ListBox)sender;
+
+
+ ViewModel.HomeVM.Instacne.LauncherConfig.ProxyType = (Model.ProxyType)list.SelectedIndex;
+
+ switch (ViewModel.HomeVM.Instacne.LauncherConfig.ProxyType)
+ {
+ case Model.ProxyType.OFFICIAL:
+ ViewModel.HomeVM.Instacne.StartBtn_txt = Properties.Resources.btn_startgame;
+ break;
+ case Model.ProxyType.PRIVATE:
+
+ ViewModel.HomeVM.Instacne.StartBtn_txt = Properties.Resources.btn_startgame;
+
+ break;
+ case Model.ProxyType.PROXY_ONLY:
+ ViewModel.HomeVM.Instacne.StartBtn_txt = Properties.Resources.btn_startproxy;
+
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
diff --git a/View/Setting.xaml b/View/Setting.xaml
new file mode 100644
index 0000000..3fbb225
--- /dev/null
+++ b/View/Setting.xaml
@@ -0,0 +1,136 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/View/Setting.xaml.cs b/View/Setting.xaml.cs
new file mode 100644
index 0000000..817be6e
--- /dev/null
+++ b/View/Setting.xaml.cs
@@ -0,0 +1,21 @@
+using System.Windows.Controls;
+
+namespace Launcher.View
+{
+ ///
+ /// Setting.xaml 的交互逻辑
+ ///
+ public partial class Setting : Page
+ {
+ public Setting()
+ {
+ InitializeComponent();
+ DataContext = ViewModel.SettingVM.Instacne;
+
+
+
+ //Visibility = Visibility.Hidden;
+ }
+
+ }
+}
diff --git a/ViewModel/HomeVM.cs b/ViewModel/HomeVM.cs
new file mode 100644
index 0000000..0d24e8d
--- /dev/null
+++ b/ViewModel/HomeVM.cs
@@ -0,0 +1,347 @@
+using CommunityToolkit.Mvvm.ComponentModel;
+using CommunityToolkit.Mvvm.Input;
+using Launcher.Model;
+using System.Diagnostics;
+using System;
+using System.IO;
+using System.Windows;
+using Launcher.Common;
+using static Launcher.Common.ProxyHelper;
+using System.Net.Http.Headers;
+using Launcher.Control;
+using System.Windows.Input;
+using System.Linq;
+using static System.Net.Mime.MediaTypeNames;
+using Newtonsoft.Json;
+using System.Text;
+
+namespace Launcher.ViewModel
+{
+ internal class HomeVM : ObservableObject
+ {
+ public static HomeVM Instacne = new HomeVM();
+
+ public LauncherConfig LauncherConfig
+ {
+ get { return App.launcherConfig; }
+ set { SetProperty(ref App.launcherConfig, value); }
+ }
+
+ public HomeVM()
+ {
+ if (LauncherConfig == null)
+ {
+ LauncherConfig = new LauncherConfig();
+
+ LauncherConfig.Servers.Add(new ServerItem()
+ {
+ Name = "TestServer",
+ Description = "Styles are the visual aspects of a UI that give it a distinct look and feel.",
+
+ proxy = new ProxyConfig("127.0.0.1", true, "25566")
+ });
+ }
+ }
+
+ public RelayCommand StartGameCommand => new RelayCommand(StartGame);
+
+ public ProxyController proxyController;
+
+ private string startBtn_txt = Properties.Resources.btn_startgame;
+
+ public string StartBtn_txt
+ {
+ get { return startBtn_txt; }
+ set { SetProperty(ref startBtn_txt, value); }
+ }
+ bool CanStart = true;
+
+ private bool canChangeProxyType = true;
+
+ public bool CanChangeProxyType
+ {
+ get { return canChangeProxyType; }
+ set { SetProperty(ref canChangeProxyType,value); }
+ }
+
+ #region 启动游戏
+
+ private void StartGame()
+ {
+
+ if (!CanStart)
+ {
+
+ SnackBar.Show(Properties.Resources.tip_nostart,null);
+
+ return;
+ }
+
+ if (LauncherConfig.GameInfo==null||
+ LauncherConfig.GameInfo.GameExePath == null )
+ //LauncherConfig.GameInfo.Version == null
+
+ {
+ SnackBar.Show(Properties.Resources.tip_setcfg,new RelayCommand(() =>
+ {
+ //MainWindow.Instance.rootFrame.Navigate(new Uri("/View/Setting.xaml", UriKind.Relative));
+ MainWindow.Instance.nav.SelectedIndex = 1;
+ }));
+ return;
+ }
+ var fp = LauncherConfig.GameInfo.GameExePath;
+ try
+ {
+
+ fp = Path.GetFullPath(fp);
+ }
+ catch (Exception ex)
+ {
+ SnackBar.Show(ex.Message, new RelayCommand(() =>
+ {
+ MainWindow.Instance.nav.SelectedIndex = 1;
+ }));
+ return;
+ }
+ var fd = LauncherConfig.GameInfo.GameExeFolder;
+ if (!File.Exists(fp)&&LauncherConfig.ProxyType!=ProxyType.PROXY_ONLY)
+ {
+
+ SnackBar.Show(Properties.Resources.tip_correctgamepath, new RelayCommand(() =>
+ {
+ //MainWindow.Instance.rootFrame.Navigate(new Uri("/View/Setting.xaml", UriKind.Relative));
+ MainWindow.Instance.nav.SelectedIndex = 1;
+ }));
+ return;
+ }
+
+
+ switch (LauncherConfig.ProxyType)
+ {
+ case ProxyType.OFFICIAL:
+ ProcessStartInfo startInfo = new ProcessStartInfo()
+ {
+ CreateNoWindow = true,
+ FileName = fp,
+ UseShellExecute = true,
+ };
+ try
+ {
+ Process.Start(startInfo);
+
+ StartBtn_txt = Properties.Resources.btn_running;
+
+ CanStart = false;
+
+ CanChangeProxyType = false;
+
+ new ProcessWatcher(new EventHandler(pro_Exited)).Watch();
+
+
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show(ex.Message);
+ }
+ break;
+ case ProxyType.PRIVATE:
+ {
+ if (LauncherConfig.Servers.Count==0)
+ {
+ SnackBar.Show(Properties.Resources.tip_reqaddone, null);
+ return;
+ }
+ if (SelectedSrv==null)
+ {
+ SnackBar.Show(Properties.Resources.tip_reqselectone, null);
+ return;
+ }
+ var SelectedProxy_C = SelectedSrv.proxy;
+ proxyController = new ProxyController(SelectedProxy_C.ProxyPort, SelectedProxy_C.ProxyServer,SelectedProxy_C.UseHttp);
+ proxyController.Start();
+
+
+
+ var dll = RSAPatchHelper.WriteMhypbaseAllTo(SelectedSrv); ;
+ if (dll != null)
+ {
+ GameHelper.StartGame(fp, dll);
+ }
+ CanChangeProxyType = false;
+ CanStart = false;
+ StartBtn_txt = Properties.Resources.btn_running;
+ new ProcessWatcher(new EventHandler(pro_Exited)).Watch();
+
+ break;
+ }
+ case ProxyType.PROXY_ONLY:
+ {
+ if (LauncherConfig.Servers.Count == 0||SelectedSrv==null)
+ {
+ SnackBar.Show(Properties.Resources.tip_reqaddone, null);
+ return;
+ }
+ var SelectedProxy_C = SelectedSrv.proxy;
+
+
+ if (proxyController!=null&&proxyController._IsRun)
+ {
+ CanChangeProxyType = true;
+
+ proxyController.Stop();
+
+ StartBtn_txt = Properties.Resources.btn_startproxy;
+ }
+ else
+ {
+ CanChangeProxyType = false;
+
+ proxyController = new ProxyController(SelectedProxy_C.ProxyPort, SelectedProxy_C.ProxyServer, SelectedProxy_C.UseHttp);
+
+ proxyController.Start();
+
+ StartBtn_txt = Properties.Resources.btn_stopproxy;
+
+ }
+ }
+
+
+
+ break;
+ default:
+ break;
+ }
+ }
+
+
+ private void pro_Exited(object sender, EventArgs e)
+ {
+ //MessageBox.Show("游戏退出!");
+
+
+ CanStart = true;
+
+ switch (LauncherConfig.ProxyType)
+ {
+ case ProxyType.OFFICIAL:
+ StartBtn_txt = Properties.Resources.btn_startgame;
+
+ CanChangeProxyType = true;
+ break;
+ case ProxyType.PRIVATE:
+
+ StartBtn_txt = Properties.Resources.btn_startgame;
+
+ proxyController.Stop();
+
+ CanChangeProxyType = true;
+
+ //var inif = System.IO.Path.Combine(LauncherConfig.GameInfo.GameExeFolder, "mhypbase.ini");
+
+ //if (File.Exists(inif))
+ //{
+ // File.Delete(inif);
+ //}
+
+ break;
+ case ProxyType.PROXY_ONLY:
+
+ default:
+ break;
+ }
+ }
+ #endregion
+
+ public ICommand AddCommand => new RelayCommand(Add);
+ public ICommand DeleteCommand => new RelayCommand(Delete);
+ public ICommand EditCommand => new RelayCommand(Edit);
+ public ICommand ImportCommand => new RelayCommand(Import);
+ public ICommand ExportCommand => new RelayCommand(Export);
+
+ private void Export()
+ {
+ if (SelectedSrv!=null)
+ {
+ byte[] bytes = Encoding.Default.GetBytes(JsonConvert.SerializeObject(SelectedSrv));
+ string str = Convert.ToBase64String(bytes);
+ Clipboard.SetDataObject(str, true);
+ SnackBar.Show(Properties.Resources.tip_exp_succ, null);
+
+ }
+ }
+
+ private void Import()
+ {
+ try
+ {
+ IDataObject data = Clipboard.GetDataObject();
+ string srv = (string)data.GetData(typeof(string));
+ byte[] outputb = Convert.FromBase64String(srv);
+ string orgStr = Encoding.Default.GetString(outputb);
+ LauncherConfig.Servers.Add(JsonConvert.DeserializeObject(orgStr));
+
+ SnackBar.Show(Properties.Resources.tip_imp_succ, null);
+
+ }
+ catch (Exception ex)
+ {
+ SnackBar.Show(Properties.Resources.tip_imp_err, null);
+ }
+ }
+
+ private ServerItem selectedSrv;
+
+ public ServerItem SelectedSrv
+ {
+ get { return selectedSrv; }
+ set { SetProperty(ref selectedSrv , value); }
+ }
+
+
+
+ private void Add()
+ {
+
+ var item = new ServerItem()
+ {
+ proxy = new ProxyConfig("127.0.0.1")
+ };
+
+ ServerEditControl.instance.ServerItem = item;
+ ServerEditControl.Show();
+
+ LauncherConfig.Servers.Add(item);
+
+
+ }
+
+ private void Delete()
+ {
+ if (SelectedSrv==null)
+ {
+ return;
+ }
+ LauncherConfig.Servers.Remove(SelectedSrv);
+
+ if (LauncherConfig.SelectedSrvIndex>0)
+ {
+ LauncherConfig.SelectedSrvIndex -= 1;
+ }
+
+ }
+
+ private void Edit()
+ {
+ if (SelectedSrv == null)
+ {
+ return;
+ }
+
+ ServerEditControl.instance.ServerItem = SelectedSrv;
+ ServerEditControl.Show();
+
+ }
+
+
+ }
+}
diff --git a/ViewModel/SettingVM.cs b/ViewModel/SettingVM.cs
new file mode 100644
index 0000000..a605817
--- /dev/null
+++ b/ViewModel/SettingVM.cs
@@ -0,0 +1,67 @@
+using CommunityToolkit.Mvvm.ComponentModel;
+using CommunityToolkit.Mvvm.Input;
+using Launcher.Common;
+using Launcher.Model;
+using Microsoft.Win32;
+using System.IO;
+using System.Windows;
+using System.Windows.Input;
+
+namespace Launcher.ViewModel
+{
+ internal class SettingVM : ObservableObject
+ {
+ public static SettingVM Instacne = new SettingVM();
+
+
+ public SettingVM()
+ {
+ if (LauncherConfig == null)
+ {
+ LauncherConfig = new LauncherConfig();
+ }
+ }
+
+
+ public LauncherConfig LauncherConfig
+ {
+ get { return App.launcherConfig; }
+ set { SetProperty(ref App.launcherConfig, value); }
+ }
+
+ public ICommand SearchGameFileCommand => new RelayCommand(SearchGameFile);
+
+ public ICommand SetGameExePathCommand => new RelayCommand(SetGameExePath);
+
+
+
+ public void SearchGameFile()
+ {
+ LauncherConfig.GameInfo = new GameInfo(GameHelper.GameRegReader.GetGameExePath());
+ if (File.Exists(LauncherConfig.GameInfo.GameExePath))
+ {
+ MessageBox.Show(string.Format(Properties.Resources.tip_serach_succ,LauncherConfig.GameInfo.GameExeFolder));
+ }
+ else
+ {
+ MessageBox.Show(Properties.Resources.tip_search_err);
+
+ }
+
+ }
+
+ private void SetGameExePath()
+ {
+ OpenFileDialog openFileDialog = new OpenFileDialog();
+ openFileDialog.Filter = "原神游戏程序(YuanShen.exe)|YuanShen.exe|原神游戏程序(GenshinImpact.exe)|GenshinImpact.exe";
+ openFileDialog.Multiselect = false;
+ if (openFileDialog.ShowDialog() == true)
+ {
+
+ LauncherConfig.GameInfo = new GameInfo(openFileDialog.FileName);
+
+ }
+
+ }
+ }
+}
diff --git a/app.manifest b/app.manifest
new file mode 100644
index 0000000..6e0c850
--- /dev/null
+++ b/app.manifest
@@ -0,0 +1,81 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/favicon.ico b/favicon.ico
new file mode 100644
index 0000000..3e3cf7e
Binary files /dev/null and b/favicon.ico differ
diff --git a/key/GC-Dispatch.txt b/key/GC-Dispatch.txt
new file mode 100644
index 0000000..ac2c5e9
--- /dev/null
+++ b/key/GC-Dispatch.txt
@@ -0,0 +1 @@
+xbbx2m1feHyrQ7jP+8mtDF/pyYLrJWKWAdEv3wZrOtjOZzeLGPzsmkcgncgoRhX4dT+1itSMR9j9m0/OwsH2UoF6U32LxCOQWQD1AMgIZjAkJeJvFTrtn8fMQ1701CkbaLTVIjRMlTw8kNXvNA/A9UatoiDmi4TFG6mrxTKZpIcTInvPEpkK2A7Qsp1E4skFK8jmysy7uRhMaYHtPTsBvxP0zn3lhKB3W+HTqpneewXWHjCDfL7Nbby91jbz5EKPZXWLuhXIvR1Cu4tiruorwXJxmXaP1HQZonytECNU/UOzP6GNLdq0eFDE4b04Wjp396551G99YiFP2nqHVJ5OMQ==AQAB
\ No newline at end of file
diff --git a/packages.config b/packages.config
new file mode 100644
index 0000000..21b9549
--- /dev/null
+++ b/packages.config
@@ -0,0 +1,68 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file