Compare commits

..

No commits in common. "master" and "1.2.0" have entirely different histories.

20 changed files with 305 additions and 595 deletions

View file

@ -6,24 +6,19 @@ on:
jobs: jobs:
build: build:
runs-on: windows-latest runs-on: windows-latest
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Setup .NET - name: Setup .NET
uses: actions/setup-dotnet@v4 uses: actions/setup-dotnet@v4
with: with:
dotnet-version: '9.0.x' dotnet-version: '7.0.x'
- name: Build
# Build with --self-contained false run: dotnet publish --configuration Release --self-contained false --runtime win-x64 /p:PublishSingleFile=true
- name: Build Rusty Hearts Launcher (No Self-Contained) - name: Zip output file
run: dotnet publish ./RHLauncher.sln --configuration Release --self-contained false --runtime win-x64 /p:PublishSingleFile=true /p:PublishDir=./publish/RustyHearts-Launcher_framework-dependent run: Compress-Archive -Path ./bin/Release/net7.0-windows7.0/win-x64/publish/Launcher.exe -DestinationPath Launcher.zip
- name: Zip output files (No Self-Contained)
run: Compress-Archive -Path "./publish/RustyHearts-Launcher_framework-dependent" -DestinationPath RustyHearts-Launcher.zip
- name: Upload Artifact - name: Upload Artifact
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: Launcher name: Launcher
path: RustyHearts-Launcher.zip path: Launcher.zip

View file

@ -3,50 +3,42 @@ on:
workflow_dispatch: workflow_dispatch:
release: release:
types: [created] types: [created]
jobs: jobs:
build: build:
runs-on: windows-latest runs-on: windows-latest
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Setup .NET - name: Setup .NET
uses: actions/setup-dotnet@v4 uses: actions/setup-dotnet@v4
with: with:
dotnet-version: '9.0.x' dotnet-version: '7.0.x'
- name: Get version from .csproj file
# Build with --self-contained false
- name: Build Rusty Hearts Launcher (No Self-Contained)
run: dotnet publish ./RHLauncher.sln --configuration Release --self-contained false --runtime win-x64 /p:PublishSingleFile=true /p:PublishDir=./publish/RustyHearts-Launcher_framework-dependent
- name: Zip output files (No Self-Contained)
run: Compress-Archive -Path "./publish/RustyHearts-Launcher_framework-dependent" -DestinationPath RustyHearts-Launcher-Framework-Dependent.zip
# Build with --self-contained true
- name: Build Rusty Hearts Launcher (Self-Contained)
run: dotnet publish ./RHLauncher.sln --configuration Release --self-contained true --runtime win-x64 /p:PublishSingleFile=false /p:PublishDir=./publish/RustyHearts-Launcher_self-contained
- name: Zip output files (Self-Contained)
run: Compress-Archive -Path "./publish/RustyHearts-Launcher_self-contained" -DestinationPath RustyHearts-Launcher-SelfContained.zip
- name: Get version from compiled assembly
id: version id: version
run: |
$version = (Get-Command "./publish/RustyHearts-Launcher_self-contained/Launcher.dll").FileVersionInfo.FileVersion
echo "::set-output name=version::$version"
# Create Release and Upload Assets using softprops/action-gh-release run: |
- name: Create GitHub Release and Upload Assets echo "::set-output name=version::$(grep -m1 -o '<FileVersion>[^<]*' RHLauncher.csproj | sed 's/<FileVersion>//')"
uses: softprops/action-gh-release@v2 - name: Build
run: dotnet publish --configuration Release --self-contained false --runtime win-x64 /p:PublishSingleFile=true
- name: Zip output file
run: Compress-Archive -Path ./bin/Release/net7.0-windows7.0/win-x64/publish/Launcher.exe -DestinationPath Launcher.zip
- name: Create Release
id: create_release
uses: actions/create-release@v1
with: with:
tag_name: v${{ steps.version.outputs.version }} tag_name: ${{ steps.version.outputs.version }}
body: Automated pre-release created by GitHub Actions. release_name: v${{ steps.version.outputs.version }}
draft: true body: Automated release created by GitHub Actions.
prerelease: true draft: false
files: | prerelease: false
./RustyHearts-Launcher-Framework-Dependent.zip env:
./RustyHearts-Launcher-SelfContained.zip GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Upload Release Asset
uses: actions/upload-release-asset@v1
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./Launcher.zip
asset_name: Launcher.zip
asset_content_type: application/zip
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View file

@ -23,8 +23,10 @@ Rusty Hearts Launcher is a custom launcher for the Rusty Hearts game client. It
* [Prerequisites for Building Locally/Development](#prerequisites-for-building-locallydevelopment) * [Prerequisites for Building Locally/Development](#prerequisites-for-building-locallydevelopment)
* [System Requirements for Ready-to-use build](#system-requirements-for-ready-to-use-build) * [System Requirements for Ready-to-use build](#system-requirements-for-ready-to-use-build)
* [License](#license) * [License](#license)
* [Building](#building) * [Contributing](#contributing)
* [FAQ](#faq)
* [Credits](#credits) * [Credits](#credits)
* [Support](#support)
## Features ## Features
* Game Download: The launcher can download and install the client. * Game Download: The launcher can download and install the client.
@ -42,9 +44,8 @@ In order for the launcher to work it need to be conected to the api. To change t
The default URL for the api can be changed on IniFile.cs The default URL for the api can be changed on IniFile.cs
### Client region ### Client region
The client region can be set on Config.ini or in the Config menu The client region can be set on Service on Config.ini
* **Jpn** (SEGA) - Full api support
* **usa** (PWE) - Full api support * **usa** (PWE) - Full api support
* **chn** (Xunlei) - Only launcher support * **chn** (Xunlei) - Only launcher support
@ -72,37 +73,36 @@ If you want to add a new language create a LocalizedStrings.<language>.resx with
If you want to change the text on the buttons/images used in the launcher you can use the Photoshop .psd files included in the PSD Resources.rar If you want to change the text on the buttons/images used in the launcher you can use the Photoshop .psd files included in the PSD Resources.rar
## Prerequisites for Development ## Prerequisites for Building Locally/Development
* Visual Studio 2022 (Any Edition - 17.12 or later) The launcher is built in .NET 7 and as such, the packages listed below are required to create a local and development build of the launcher. Furthermore, it uses many submodules and packages outside of this, which will automatically be loaded when the user sets up a local environment of the application.
* Windows 10 SDK or Windows 11 SDK via Visual Studio Installer * Visual Studio 2022 (Any Edition - 17.4 or later)
* .NET Core 9 SDK (9.0.100 or later) * Windows 10 SDK (10.0.19043.0) or Windows 11 SDK (10.0.22000.0) via Visual Studio Installer
* .NET: [.NET Core 7 SDK (7.0.100 or later)](https://dotnet.microsoft.com/en-us/download/dotnet/7.0)
## Building ## System Requirements for Ready-to-use build
* OS: Windows 10 1809 Update (build 17763) or later / Windows 11 (Any builds)
If you wish to build the project yourself, follow these steps: * Architecture: x64/AMD64
### Step 1
Install the [.NET 9.0 (or higher) SDK](https://dotnet.microsoft.com/download/dotnet/9.0).
Make sure your SDK version is higher or equal to the required version specified.
### Step 2
Either use `git clone https://github.com/JuniorDark/RustyHearts-Launcher` on the command line to clone the repository or use Code --> Download zip button to get the files.
### Step 3
To build Rusty Hearts Launcher, open a command prompt inside the project directory.
You can quickly access it on Windows by holding shift in File Explorer, then right clicking and selecting `Open command window here`.
Then type the following command: `dotnet build -c Release`.
The built files will be found in the newly created `bin` build directory.
## License ## License
This project is licensed under the terms found in [`LICENSE-0BSD`](LICENSE). This project is licensed under the terms found in [`LICENSE-0BSD`](LICENSE).
## Contributing
Contributions from the community are welcome! If you encounter a bug or have a feature request, please submit an issue on GitHub. If you would like to contribute code, please fork the repository and submit a pull request.
## FAQ
* Q: How do I report a bug?
* A: Please submit an issue on GitHub with a detailed description of the bug and steps to reproduce it.
* Q: How do I request a new feature?
* A: Please submit an issue on GitHub with a detailed description of the feature and why it would be useful.
* Q: How do I contribute code?
* A: Please fork the repository, make your changes, and submit a pull request.
## Credits ## Credits
The following third-party libraries, tools, and resources are used in this project: The following third-party libraries, tools, and resources are used in this project:
* [DotNetZip](https://www.nuget.org/packages/DotNetZip)
* [Microsoft.Web.WebView2](https://www.nuget.org/packages/Microsoft.Web.WebView2) * [Microsoft.Web.WebView2](https://www.nuget.org/packages/Microsoft.Web.WebView2)
* [Newtonsoft.Json](https://www.nuget.org/packages/Newtonsoft.Json) * [Newtonsoft.Json](https://www.nuget.org/packages/Newtonsoft.Json)
* [WindowsAPICodePack](https://www.nuget.org/packages/WindowsAPICodePack) * [WindowsAPICodePack](https://www.nuget.org/packages/WindowsAPICodePack)
## Support
If you need help with the launcher, please submit an issue on GitHub.

View file

@ -1,5 +1,4 @@
using Newtonsoft.Json; using RHLauncher.RHLauncher.Helper;
using RHLauncher.RHLauncher.Helper;
using RHLauncher.RHLauncher.i8n; using RHLauncher.RHLauncher.i8n;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
@ -9,10 +8,10 @@ namespace RHLauncher
{ {
private RegistryHandler registryHandler = new(); private RegistryHandler registryHandler = new();
private readonly string SendPasswordCodeUrl = Configuration.Default.SendPasswordCodeUrl; public string SendPasswordCodeUrl = Configuration.Default.SendPasswordCodeUrl;
private readonly string VerifyCodeUrl = Configuration.Default.VerifyCodeUrl; public string VerifyCodeUrl = Configuration.Default.VerifyCodeUrl;
private readonly string ChangePasswordUrl = Configuration.Default.ChangePasswordUrl; public string ChangePasswordUrl = Configuration.Default.ChangePasswordUrl;
private readonly string Lang = Configuration.Default.Lang; public string Lang = Configuration.Default.Lang;
private List<Button>? buttons; private List<Button>? buttons;
private List<ImageList>? imageLists; private List<ImageList>? imageLists;
private Dictionary<string, List<ImageList>>? languageImageLists; private Dictionary<string, List<ImageList>>? languageImageLists;
@ -55,16 +54,16 @@ namespace RHLauncher
private void LoadLocalizedStrings() private void LoadLocalizedStrings()
{ {
// Initialize buttons and image lists // Initialize buttons and image lists
buttons = [ContinueButtonS1, SendEmailButton, OkButtonS2]; buttons = new List<Button> { ContinueButtonS1, SendEmailButton, OkButtonS2 };
imageLists = [imageListContinueBtn, imageListSendEmailBtn, imageListOKBtn]; imageLists = new List<ImageList> { imageListContinueBtn, imageListSendEmailBtn, imageListOKBtn };
// Initialize language-specific image lists // Initialize language-specific image lists
languageImageLists = new Dictionary<string, List<ImageList>> languageImageLists = new Dictionary<string, List<ImageList>>
{ {
{ "en", new List<ImageList> { imageListContinueBtn, imageListSendEmailBtn, imageListOKBtn } }, // English image lists { "en", new List<ImageList> { imageListContinueBtn, imageListSendEmailBtn, imageListOKBtn } }, // English image lists
{ "ko", new List<ImageList> { imageListContinueBtn_ko, imageListSendEmailBtn_ko, imageListOKBtn_ko } }, // Korean image lists { "ko", new List<ImageList> { imageListContinueBtn_ko, imageListSendEmailBtn_ko, imageListOKBtn_ko } }, // Korean image lists
// Add other languages and their respective image lists here // Add other languages and their respective image lists here
}; };
// Load the appropriate resource file based on the selected language // Load the appropriate resource file based on the selected language
LocalizationHelper.LoadLocalizedStrings(Lang, buttons, imageLists, languageImageLists); LocalizationHelper.LoadLocalizedStrings(Lang, buttons, imageLists, languageImageLists);
@ -92,12 +91,12 @@ namespace RHLauncher
private async Task<string> SendEmailRequestAsync() private async Task<string> SendEmailRequestAsync()
{ {
using HttpClient client = new(); using HttpClient client = new();
using HttpResponseMessage response = await client.PostAsync(SendPasswordCodeUrl, new FormUrlEncodedContent( using HttpResponseMessage response = await client.PostAsync(SendPasswordCodeUrl, new FormUrlEncodedContent(new[]
[ {
new KeyValuePair<string, string>("email", EmailTextBox.Text), new KeyValuePair<string, string>("email", EmailTextBox.Text),
])); }));
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync(); return await response.Content.ReadAsStringAsync();
} }
@ -105,59 +104,45 @@ namespace RHLauncher
{ {
Invoke((MethodInvoker)(() => Invoke((MethodInvoker)(() =>
{ {
try switch (response)
{ {
HttpResponse? httpResponse = JsonConvert.DeserializeObject<HttpResponse>(response); case "EmailSent":
SendEmailButton.Enabled = false;
if (httpResponse == null) resendTimer.Start();
{ break;
MsgBoxForm.Show(LocalizedStrings.Error + $": {LocalizedStrings.HttpResponseNull}", LocalizedStrings.Error); case "ValidVerificationCode":
// Hide the firs panel and show the second panel
Stage1Panel.Visible = false;
Stage2Panel.Visible = true;
EmailLabelS2.Text = EmailTextBox.Text;
CodeDescLabel.Text = "";
CodePictureBox.Image = imageListTips.Images[1];
break;
case "PasswordChanged":
MsgBoxForm.Show(LocalizedStrings.PasswordChanged, LocalizedStrings.Success);
OnPasswordChanged();
break;
case "SamePassword":
MsgBoxForm.Show(LocalizedStrings.SamePassword, LocalizedStrings.Failed);
break;
case "AccountNotFound":
EmailDescLabel.Text = LocalizedStrings.AccountNotFound;
EmailDescLabel.ForeColor = Color.Red;
EmailPictureBox.Image = imageListTips.Images[0];
return; return;
} case "InvalidVerificationCode":
CodeDescLabel.Text = LocalizedStrings.InvalidVerificationCode;
switch (httpResponse.Result) CodeDescLabel.ForeColor = Color.Red;
{ CodePictureBox.Image = imageListTips.Images[0];
case "EmailSent": return;
SendEmailButton.Enabled = false; case "ExpiredVerificationCode":
resendTimer.Start(); CodeDescLabel.Text = LocalizedStrings.ExpiredVerificationCode;
break; CodeDescLabel.ForeColor = Color.Red;
case "ValidVerificationCode": CodePictureBox.Image = imageListTips.Images[0];
Stage1Panel.Visible = false; return;
Stage2Panel.Visible = true; default:
EmailLabelS2.Text = EmailTextBox.Text; MsgBoxForm.Show("Error:" + response, LocalizedStrings.Error);
CodeDescLabel.Text = ""; break;
CodePictureBox.Image = imageListTips.Images[1];
break;
case "PasswordChanged":
MsgBoxForm.Show(LocalizedStrings.PasswordChanged, LocalizedStrings.Success);
OnPasswordChanged();
break;
case "SamePassword":
MsgBoxForm.Show(LocalizedStrings.SamePassword, LocalizedStrings.Failed);
break;
case "AccountNotFound":
EmailDescLabel.Text = LocalizedStrings.AccountNotFound;
EmailDescLabel.ForeColor = Color.Red;
EmailPictureBox.Image = imageListTips.Images[0];
break;
case "InvalidVerificationCode":
CodeDescLabel.Text = LocalizedStrings.InvalidVerificationCode;
CodeDescLabel.ForeColor = Color.Red;
CodePictureBox.Image = imageListTips.Images[0];
break;
case "ExpiredVerificationCode":
CodeDescLabel.Text = LocalizedStrings.ExpiredVerificationCode;
CodeDescLabel.ForeColor = Color.Red;
CodePictureBox.Image = imageListTips.Images[0];
break;
default:
MsgBoxForm.Show($"{LocalizedStrings.Error}: " + httpResponse.Message, LocalizedStrings.Error);
break;
}
}
catch (JsonException)
{
MsgBoxForm.Show(LocalizedStrings.Error + $": {LocalizedStrings.HttpResponseParseError}", LocalizedStrings.Error);
} }
})); }));
} }
@ -182,28 +167,28 @@ namespace RHLauncher
private async Task<string> VerifyCodeSendRequestAsync() private async Task<string> VerifyCodeSendRequestAsync()
{ {
using HttpClient client = new(); using HttpClient client = new();
using HttpResponseMessage response = await client.PostAsync(VerifyCodeUrl, new FormUrlEncodedContent( using HttpResponseMessage response = await client.PostAsync(VerifyCodeUrl, new FormUrlEncodedContent(new[]
[ {
new KeyValuePair<string, string>("email", EmailTextBox.Text), new KeyValuePair<string, string>("email", EmailTextBox.Text),
new KeyValuePair<string, string>("verificationCode", CodeTextBox.Text), new KeyValuePair<string, string>("verification_code", CodeTextBox.Text),
new KeyValuePair<string, string>("verificationCodeType", "Password"), new KeyValuePair<string, string>("verification_code_type", "Password"),
}));
]));
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync(); return await response.Content.ReadAsStringAsync();
} }
private async Task<string> ChangePasswordSendRequestAsync() private async Task<string> ChangePasswordSendRequestAsync()
{ {
using HttpClient client = new(); using HttpClient client = new();
using HttpResponseMessage response = await client.PostAsync(ChangePasswordUrl, new FormUrlEncodedContent( using HttpResponseMessage response = await client.PostAsync(ChangePasswordUrl, new FormUrlEncodedContent(new[]
[ {
new KeyValuePair<string, string>("email", EmailTextBox.Text), new KeyValuePair<string, string>("email", EmailTextBox.Text),
new KeyValuePair<string, string>("password", PasswordTextBox.Text), new KeyValuePair<string, string>("password", PasswordTextBox.Text),
new KeyValuePair<string, string>("verificationCode", CodeTextBox.Text), new KeyValuePair<string, string>("verification_code", CodeTextBox.Text),
}));
]));
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync(); return await response.Content.ReadAsStringAsync();
} }
@ -340,7 +325,7 @@ namespace RHLauncher
string password = PasswordTextBox.Text; string password = PasswordTextBox.Text;
// Check for minimum length and maximum length // Check for minimum length and maximum length
if (password.Length < 8 || password.Length > 16) if (password.Length < 6 || password.Length > 16)
{ {
PwdDescLabel.Text = LocalizedStrings.PwdDescLabelSize; PwdDescLabel.Text = LocalizedStrings.PwdDescLabelSize;
PwdDescLabel.ForeColor = Color.Red; PwdDescLabel.ForeColor = Color.Red;

View file

@ -40,8 +40,6 @@
OkButton = new Button(); OkButton = new Button();
VersionLabel = new Label(); VersionLabel = new Label();
toolTip = new ToolTip(components); toolTip = new ToolTip(components);
ServiceLabel = new Label();
cbLauncherService = new ComboBox();
SuspendLayout(); SuspendLayout();
// //
// CloseButton // CloseButton
@ -90,7 +88,7 @@
TitleLabel.AutoEllipsis = true; TitleLabel.AutoEllipsis = true;
TitleLabel.AutoSize = true; TitleLabel.AutoSize = true;
TitleLabel.BackColor = Color.Transparent; TitleLabel.BackColor = Color.Transparent;
TitleLabel.Font = new Font("Segoe UI", 11F, FontStyle.Bold); TitleLabel.Font = new Font("Segoe UI", 11F, FontStyle.Bold, GraphicsUnit.Point);
TitleLabel.ForeColor = Color.White; TitleLabel.ForeColor = Color.White;
TitleLabel.ImageAlign = ContentAlignment.TopRight; TitleLabel.ImageAlign = ContentAlignment.TopRight;
TitleLabel.ImeMode = ImeMode.NoControl; TitleLabel.ImeMode = ImeMode.NoControl;
@ -127,7 +125,7 @@
LanguageLabel.AutoEllipsis = true; LanguageLabel.AutoEllipsis = true;
LanguageLabel.AutoSize = true; LanguageLabel.AutoSize = true;
LanguageLabel.BackColor = Color.Transparent; LanguageLabel.BackColor = Color.Transparent;
LanguageLabel.Font = new Font("Segoe UI", 11F, FontStyle.Bold); LanguageLabel.Font = new Font("Segoe UI", 11F, FontStyle.Bold, GraphicsUnit.Point);
LanguageLabel.ForeColor = Color.White; LanguageLabel.ForeColor = Color.White;
LanguageLabel.ImageAlign = ContentAlignment.TopRight; LanguageLabel.ImageAlign = ContentAlignment.TopRight;
LanguageLabel.ImeMode = ImeMode.NoControl; LanguageLabel.ImeMode = ImeMode.NoControl;
@ -163,7 +161,7 @@
VersionLabel.AutoSize = true; VersionLabel.AutoSize = true;
VersionLabel.BackColor = Color.Transparent; VersionLabel.BackColor = Color.Transparent;
VersionLabel.Cursor = Cursors.Hand; VersionLabel.Cursor = Cursors.Hand;
VersionLabel.Font = new Font("Segoe UI", 10F, FontStyle.Bold); VersionLabel.Font = new Font("Segoe UI", 10F, FontStyle.Bold, GraphicsUnit.Point);
VersionLabel.ForeColor = Color.White; VersionLabel.ForeColor = Color.White;
VersionLabel.Location = new Point(5, 248); VersionLabel.Location = new Point(5, 248);
VersionLabel.Name = "VersionLabel"; VersionLabel.Name = "VersionLabel";
@ -173,34 +171,6 @@
toolTip.SetToolTip(VersionLabel, "Click to open github repository"); toolTip.SetToolTip(VersionLabel, "Click to open github repository");
VersionLabel.Click += VersionLabel_Click; VersionLabel.Click += VersionLabel_Click;
// //
// ServiceLabel
//
ServiceLabel.Anchor = AnchorStyles.None;
ServiceLabel.AutoEllipsis = true;
ServiceLabel.AutoSize = true;
ServiceLabel.BackColor = Color.Transparent;
ServiceLabel.Font = new Font("Segoe UI", 11F, FontStyle.Bold);
ServiceLabel.ForeColor = Color.White;
ServiceLabel.ImageAlign = ContentAlignment.TopRight;
ServiceLabel.ImeMode = ImeMode.NoControl;
ServiceLabel.Location = new Point(294, 119);
ServiceLabel.Name = "ServiceLabel";
ServiceLabel.Size = new Size(59, 20);
ServiceLabel.TabIndex = 18;
ServiceLabel.Text = "Service";
ServiceLabel.TextAlign = ContentAlignment.MiddleCenter;
//
// cbLauncherService
//
cbLauncherService.DropDownStyle = ComboBoxStyle.DropDownList;
cbLauncherService.FormattingEnabled = true;
cbLauncherService.Items.AddRange(new object[] { "JPN", "USA", "CHN", "JPN_BETA", "USA_BETA", "CHN_BETA" });
cbLauncherService.Location = new Point(254, 142);
cbLauncherService.Name = "cbLauncherService";
cbLauncherService.Size = new Size(145, 23);
cbLauncherService.TabIndex = 17;
cbLauncherService.SelectedIndexChanged += CbLauncherService_SelectedIndexChanged;
//
// ConfigForm // ConfigForm
// //
AutoScaleDimensions = new SizeF(7F, 15F); AutoScaleDimensions = new SizeF(7F, 15F);
@ -208,8 +178,6 @@
BackColor = Color.Magenta; BackColor = Color.Magenta;
BackgroundImage = (Image)resources.GetObject("$this.BackgroundImage"); BackgroundImage = (Image)resources.GetObject("$this.BackgroundImage");
ClientSize = new Size(646, 272); ClientSize = new Size(646, 272);
Controls.Add(ServiceLabel);
Controls.Add(cbLauncherService);
Controls.Add(VersionLabel); Controls.Add(VersionLabel);
Controls.Add(OkButton); Controls.Add(OkButton);
Controls.Add(LanguageLabel); Controls.Add(LanguageLabel);
@ -242,7 +210,5 @@
private Button OkButton; private Button OkButton;
private Label VersionLabel; private Label VersionLabel;
private ToolTip toolTip; private ToolTip toolTip;
private Label ServiceLabel;
private ComboBox cbLauncherService;
} }
} }

View file

@ -1,36 +1,27 @@
using RHLauncher.RHLauncher.i8n; using RHLauncher.RHLauncher.i8n;
using RHLauncher.RHLauncher.Helper; using RHLauncher.RHLauncher.Helper;
using System.Diagnostics; using System.Diagnostics;
using System.Text;
namespace RHLauncher namespace RHLauncher
{ {
public partial class ConfigForm : Form public partial class ConfigForm : Form
{ {
private readonly RegistryHandler registryHandler = new(); public string Url = "https://github.com/JuniorDark/RustyHearts-Launcher";
private readonly string? installDirectory;
private readonly string Url = "https://github.com/JuniorDark/RustyHearts-Launcher";
private bool languageChanged = false; private bool languageChanged = false;
readonly string currentLanguageCode = Configuration.Default.Lang; readonly string currentLanguageCode = Configuration.Default.Lang;
private bool serviceChanged = false;
readonly string currentService = Configuration.Default.Service;
public ConfigForm() public ConfigForm()
{ {
InitializeComponent(); InitializeComponent();
installDirectory = registryHandler.GetInstallDirectory();
string currentVersion = GetLauncherVersion.GetVersion(); string currentVersion = GetLauncherVersion.GetVersion();
cbLauncherLanguage.SelectedItem = GetLanguageName(currentLanguageCode); cbLauncherLanguage.SelectedItem = GetLanguageName(currentLanguageCode);
cbLauncherService.SelectedItem = GetServiceName(currentService);
VersionLabel.Text = $"{LocalizedStrings.Version}: {currentVersion}"; VersionLabel.Text = $"{LocalizedStrings.Version}: {currentVersion}";
Text = LocalizedStrings.ConfigFormTitle; Text = LocalizedStrings.ConfigFormTitle;
TitleLabel.Text = LocalizedStrings.Settings; TitleLabel.Text = LocalizedStrings.Settings;
LanguageLabel.Text = LocalizedStrings.LauncherLanguage; LanguageLabel.Text = LocalizedStrings.LauncherLanguage;
ServiceLabel.Text = LocalizedStrings.Service;
} }
@ -70,7 +61,7 @@ namespace RHLauncher
{ {
"English" => "en", "English" => "en",
"한국어" => "ko", "한국어" => "ko",
_ => "en", _ => "en", // default to English if not found
}; };
} }
@ -80,140 +71,40 @@ namespace RHLauncher
{ {
"en" => "English", "en" => "English",
"ko" => "한국어", "ko" => "한국어",
_ => "English", _ => "English", // default to English if not found
}; };
} }
#endregion #endregion
#region Service Methods
private void CbLauncherService_SelectedIndexChanged(object sender, EventArgs e)
{
if (cbLauncherService.SelectedItem is string selectedItem)
{
string selectedServiceCode = GetServiceCode(selectedItem);
if (selectedServiceCode != currentService)
{
serviceChanged = true;
}
else
{
serviceChanged = false;
}
}
}
private static string GetServiceCode(string? service)
{
return service switch
{
"USA" => "usa",
"JPN" => "jpn",
"CHN" => "chn",
"USA_BETA" => "usa_beta",
"JPN_BETA" => "jpn_beta",
"CHN_BETA" => "chn_beta",
_ => "jpn",
};
}
private static string GetServiceName(string service)
{
return service switch
{
"usa" => "USA",
"jpn" => "JPN",
"chn" => "CHN",
"usa_beta" => "USA_BETA",
"jpn_beta" => "JPN_BETA",
"chn_beta" => "CHN_BETA",
_ => "JPN",
};
}
private void UpdateServiceDatFile(string serviceCode)
{
if (string.IsNullOrEmpty(installDirectory))
return;
try
{
// Compute MD5 hash
byte[] inputBytes = Encoding.UTF8.GetBytes(serviceCode);
byte[] hashBytes = System.Security.Cryptography.MD5.HashData(inputBytes);
StringBuilder sb = new();
foreach (byte b in hashBytes)
{
sb.Append(b.ToString("x2")); // Lowercase hex
}
string hashString = sb.ToString();
string fileContent = $"{hashString}\r\n\r\nSTAIRWAY GAMES";
// Write to Service.dat
string filePath = Path.Combine(installDirectory, "Service.dat");
File.WriteAllText(filePath, fileContent);
}
catch (Exception ex)
{
MessageBox.Show($"Failed to update Service.dat: {ex.Message}", LocalizedStrings.Error, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
#endregion
#region Button Click Events #region Button Click Events
private void OkButton_Click(object sender, EventArgs e) private void OkButton_Click(object sender, EventArgs e)
{ {
try if (languageChanged)
{ {
if (languageChanged || serviceChanged) string? selectedLanguage = cbLauncherLanguage.SelectedItem.ToString();
string languageCode = GetLanguageCode(selectedLanguage);
if (languageCode != null)
{ {
string? selectedService = cbLauncherService.SelectedItem?.ToString(); // Update the language in the INI file
string serviceCode = GetServiceCode(selectedService); Configuration.Default.Lang = languageCode;
if (serviceCode != null) Configuration.Default.iniFile.WriteValue("Launcher", "Lang", languageCode);
DialogResult result = MsgBoxForm.ShowYN(LocalizedStrings.ChangeLanguageMessage, LocalizedStrings.Confirmation);
if (result == DialogResult.Yes)
{ {
// Update the service in the INI file Invoke((MethodInvoker)(() => Close()));
Configuration.Default.Service = serviceCode; Task.Delay(1000).ContinueWith(_ =>
Configuration.Default.iniFile.WriteValue("Info", "Service", serviceCode);
UpdateServiceDatFile(serviceCode);
}
string? selectedLanguage = cbLauncherLanguage.SelectedItem?.ToString();
string languageCode = GetLanguageCode(selectedLanguage);
if (languageCode != null)
{
// Update the language in the INI file
Configuration.Default.Lang = languageCode;
Configuration.Default.iniFile.WriteValue("Launcher", "Lang", languageCode);
DialogResult result = MsgBoxForm.ShowYN(LocalizedStrings.ChangeLanguageMessage, LocalizedStrings.Confirmation);
if (result == DialogResult.Yes)
{ {
Invoke((MethodInvoker)(() => Close())); Application.Restart();
Task.Delay(1000).ContinueWith(_ => });
{
Application.Restart();
});
}
} }
} }
else
{
Close();
}
} }
catch (Exception ex) else
{ {
MessageBox.Show($"{LocalizedStrings.Error}: {ex.Message}", LocalizedStrings.Error, MessageBoxButtons.OK, MessageBoxIcon.Error); Close();
} }
} }

View file

@ -125,7 +125,7 @@
AAEAAAD/////AQAAAAAAAAAMAgAAAEZTeXN0ZW0uV2luZG93cy5Gb3JtcywgQ3VsdHVyZT1uZXV0cmFs AAEAAAD/////AQAAAAAAAAAMAgAAAEZTeXN0ZW0uV2luZG93cy5Gb3JtcywgQ3VsdHVyZT1uZXV0cmFs
LCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAmU3lzdGVtLldpbmRvd3MuRm9ybXMu LCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAmU3lzdGVtLldpbmRvd3MuRm9ybXMu
SW1hZ2VMaXN0U3RyZWFtZXIBAAAABERhdGEHAgIAAAAJAwAAAA8DAAAA+jYAAAJNU0Z0AUkBTAIBAQMB SW1hZ2VMaXN0U3RyZWFtZXIBAAAABERhdGEHAgIAAAAJAwAAAA8DAAAA+jYAAAJNU0Z0AUkBTAIBAQMB
AAHwAQEB8AEBARkBAAEZAQAE/wEhAQAI/wFCAU0BNgcAATYDAAEoAwABZAMAARkDAAEBAQABIAUAARAB AAHQAQEB0AEBARkBAAEZAQAE/wEhAQAI/wFCAU0BNgcAATYDAAEoAwABZAMAARkDAAEBAQABIAUAARAB
JxIAARUCAAH/ARUCAAH/ARUCAAH/ARUCAAH/ARUCAAH/ARUCAAH/ARUCAAH/ARUCAAH/ARUCAAH/ARUC JxIAARUCAAH/ARUCAAH/ARUCAAH/ARUCAAH/ARUCAAH/ARUCAAH/ARUCAAH/ARUCAAH/ARUCAAH/ARUC
AAH/ARUCAAH/ARUCAAH/ARUCAAH/ARUCAAH/ARUCAAH/ARUCAAH/ARUCAAH/ARUCAAH/ARUCAAH/ARUC AAH/ARUCAAH/ARUCAAH/ARUCAAH/ARUCAAH/ARUCAAH/ARUCAAH/ARUCAAH/ARUCAAH/ARUCAAH/ARUC
AAH/ARUCAAH/ARUCAAH/ARUCAAH/ARUCAAH/ARUCAAH/ARUCAAH/ARUCAAH/ARUCAAH/ARUCAAH/ARUC AAH/ARUCAAH/ARUCAAH/ARUCAAH/ARUCAAH/ARUCAAH/ARUCAAH/ARUCAAH/ARUCAAH/ARUCAAH/ARUC
@ -370,7 +370,7 @@
AAEAAAD/////AQAAAAAAAAAMAgAAAEZTeXN0ZW0uV2luZG93cy5Gb3JtcywgQ3VsdHVyZT1uZXV0cmFs AAEAAAD/////AQAAAAAAAAAMAgAAAEZTeXN0ZW0uV2luZG93cy5Gb3JtcywgQ3VsdHVyZT1uZXV0cmFs
LCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAmU3lzdGVtLldpbmRvd3MuRm9ybXMu LCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAmU3lzdGVtLldpbmRvd3MuRm9ybXMu
SW1hZ2VMaXN0U3RyZWFtZXIBAAAABERhdGEHAgIAAAAJAwAAAA8DAAAAkGEBAAJNU0Z0AUkBTAIBAQMB SW1hZ2VMaXN0U3RyZWFtZXIBAAAABERhdGEHAgIAAAAJAwAAAA8DAAAAkGEBAAJNU0Z0AUkBTAIBAQMB
AAHgAQIB4AECAWcBAAElAQAE/wEhAQAI/wFCAU0BNgcAATYDAAEoAwABnAEBAgABJQMAAQEBAAEgBQAB AAHAAQIBwAECAWcBAAElAQAE/wEhAQAI/wFCAU0BNgcAATYDAAEoAwABnAEBAgABJQMAAQEBAAEgBQAB
MAHuEgABJwEHAQAB/wEnAQcBAAH/AScBBwEAAf8BJwEHAQAB/wEnAQcBAAH/AScBBwEAAf8BJwEHAQAB MAHuEgABJwEHAQAB/wEnAQcBAAH/AScBBwEAAf8BJwEHAQAB/wEnAQcBAAH/AScBBwEAAf8BJwEHAQAB
/wEnAQcBAAH/AScBBwEAAf8BJwEHAQAB/wEnAQcBAAH/AScBBwEAAf8BJwEHAQAB/wEnAQcBAAH/AScB /wEnAQcBAAH/AScBBwEAAf8BJwEHAQAB/wEnAQcBAAH/AScBBwEAAf8BJwEHAQAB/wEnAQcBAAH/AScB
BwEAAf8BJwEHAQAB/wEnAQcBAAH/AScBBwEAAf8BJwEHAQAB/wEnAQcBAAH/AScBBwEAAf8BJwEHAQAB BwEAAf8BJwEHAQAB/wEnAQcBAAH/AScBBwEAAf8BJwEHAQAB/wEnAQcBAAH/AScBBwEAAf8BJwEHAQAB
@ -1889,7 +1889,7 @@
AAEAAAD/////AQAAAAAAAAAMAgAAAEZTeXN0ZW0uV2luZG93cy5Gb3JtcywgQ3VsdHVyZT1uZXV0cmFs AAEAAAD/////AQAAAAAAAAAMAgAAAEZTeXN0ZW0uV2luZG93cy5Gb3JtcywgQ3VsdHVyZT1uZXV0cmFs
LCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAmU3lzdGVtLldpbmRvd3MuRm9ybXMu LCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAmU3lzdGVtLldpbmRvd3MuRm9ybXMu
SW1hZ2VMaXN0U3RyZWFtZXIBAAAABERhdGEHAgIAAAAJAwAAAA8DAAAAZGYBAAJNU0Z0AUkBTAIBAQMB SW1hZ2VMaXN0U3RyZWFtZXIBAAAABERhdGEHAgIAAAAJAwAAAA8DAAAAZGYBAAJNU0Z0AUkBTAIBAQMB
AAHoAQIB6AECAWcBAAElAQAE/wEhAQAI/wFCAU0BNgcAATYDAAEoAwABnAEBAgABJQMAAQEBAAEgBQAB AAHIAQIByAECAWcBAAElAQAE/wEhAQAI/wFCAU0BNgcAATYDAAEoAwABnAEBAgABJQMAAQEBAAEgBQAB
MAHuEgABJwEHAQAB/wEnAQcBAAH/AScBBwEAAf8BJwEHAQAB/wEnAQcBAAH/AScBBwEAAf8BJwEHAQAB MAHuEgABJwEHAQAB/wEnAQcBAAH/AScBBwEAAf8BJwEHAQAB/wEnAQcBAAH/AScBBwEAAf8BJwEHAQAB
/wEnAQcBAAH/AScBBwEAAf8BJwEHAQAB/wEnAQcBAAH/AScBBwEAAf8BJwEHAQAB/wEnAQcBAAH/AScB /wEnAQcBAAH/AScBBwEAAf8BJwEHAQAB/wEnAQcBAAH/AScBBwEAAf8BJwEHAQAB/wEnAQcBAAH/AScB
BwEAAf8BJwEHAQAB/wEnAQcBAAH/AScBBwEAAf8BJwEHAQAB/wEnAQcBAAH/AScBBwEAAf8BJwEHAQAB BwEAAf8BJwEHAQAB/wEnAQcBAAH/AScBBwEAAf8BJwEHAQAB/wEnAQcBAAH/AScBBwEAAf8BJwEHAQAB
@ -3427,7 +3427,7 @@
<data name="$this.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> <data name="$this.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value> <value>
iVBORw0KGgoAAAANSUhEUgAAAoYAAAEQCAIAAACiPyLtAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAL iVBORw0KGgoAAAANSUhEUgAAAoYAAAEQCAIAAACiPyLtAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAL
DgAACw4BQL7hQQAAJ5dJREFUeF7t3d2zXOV5pnFVZTCCJJXAluJ4QmypW1Bjhw8JBoT4sqfmOJkgnNRk EgAACxIB0t1+/AAAJ5dJREFUeF7t3d2zXOV5pnFVZTCCJJXAluJ4QmypW1Bjhw8JBoT4sqfmOJkgnNRk
bDAIpypnwY4NqTmfkyR/9KzevbV399a1Xt0XYffqg7vqKpX2T0sLzp5aq99Hfe1nH//77Tc++9Frn916 bDAIpypnwY4NqTmfkyR/9KzevbV399a1Xt0XYffqg7vqKpX2T0sLzp5aq99Hfe1nH//77Tc++9Frn916
7dOXfvKLv/zJP7w09eN/mH7zl3/1f3746qbpNxv/8b5P+NjP8NTPcHCTCQ95k0v/28Ob7P0Xv91NJjzk 7dOXfvKLv/zJP7w09eN/mH7zl3/1f3746qbpNxv/8b5P+NjP8NTPcHCTCQ95k0v/28Ob7P0Xv91NJjzk
TSakm5zht73J3sW7N7n0v33VN5nwP3eTMwxvMuEhb3Lpf3t4k73/4re7yYSHvMmEdJMz/LY32bt49yaX TSakm5zht73J3sW7N7n0v33VN5nwP3eTMwxvMuEhb3Lpf3t4k73/4re7yYSHvMmEdJMz/LY32bt49yaX

View file

@ -21,8 +21,8 @@ namespace RHLauncher
public partial class LauncherForm : Form public partial class LauncherForm : Form
{ {
private RegistryHandler registryHandler = new(); private RegistryHandler registryHandler = new();
private string? installDirectory; public string? installDirectory;
private string? tempInstallDirectory; public string? tempInstallDirectory;
private static readonly string DefaultIniFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.ini"); private static readonly string DefaultIniFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.ini");
private readonly IniFile _iniFile = new(DefaultIniFilePath); private readonly IniFile _iniFile = new(DefaultIniFilePath);
private readonly string _windyCode; private readonly string _windyCode;
@ -487,6 +487,10 @@ namespace RHLauncher
} }
} }
public class ServerStatusResponse
{
public string? Status { get; set; }
}
#endregion #endregion
#region Button Click Events #region Button Click Events
@ -662,6 +666,10 @@ namespace RHLauncher
{ {
Process.Start("explorer.exe", installDirectory); Process.Start("explorer.exe", installDirectory);
} }
else
{
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -853,15 +861,9 @@ namespace RHLauncher
switch (service.ToLower()) switch (service.ToLower())
{ {
case "usa": case "usa":
case "usa_beta":
arguments = "server=" + Configuration.Default.GateXMLUrl; arguments = "server=" + Configuration.Default.GateXMLUrl;
break; break;
case "jpn":
case "jpn_beta":
arguments = $"-serverurl{Configuration.Default.GateInfoUrl}";
break;
case "chn": case "chn":
case "chn_beta":
arguments = $"-serverurl{Configuration.Default.GateInfoUrl} id={_windyCode} password={_password}"; arguments = $"-serverurl{Configuration.Default.GateInfoUrl} id={_windyCode} password={_password}";
break; break;
default: default:
@ -929,7 +931,7 @@ namespace RHLauncher
{ {
foreach (FileInfo file in directoryInfo.GetFiles()) foreach (FileInfo file in directoryInfo.GetFiles())
{ {
if (!file.Name.Equals("launcher.exe", StringComparison.CurrentCultureIgnoreCase) && !file.Name.Equals("config.ini", StringComparison.CurrentCultureIgnoreCase)) if (file.Name.ToLower() != "launcher.exe" && file.Name.ToLower() != "config.ini")
{ {
file.Delete(); file.Delete();
} }
@ -1054,8 +1056,8 @@ namespace RHLauncher
private static Image[] LoadImages() private static Image[] LoadImages()
{ {
return return new Image[]
[ {
Properties.Resources.character_select_cut_angela, Properties.Resources.character_select_cut_angela,
Properties.Resources.character_select_cut_edgar, Properties.Resources.character_select_cut_edgar,
Properties.Resources.character_select_cut_frantz, Properties.Resources.character_select_cut_frantz,
@ -1065,7 +1067,7 @@ namespace RHLauncher
Properties.Resources.character_select_cut_natasha, Properties.Resources.character_select_cut_natasha,
Properties.Resources.character_select_cut_roselle, Properties.Resources.character_select_cut_roselle,
Properties.Resources.character_select_cut_tude Properties.Resources.character_select_cut_tude
]; };
} }
private static void HidePanel(Panel panel) private static void HidePanel(Panel panel)
@ -1091,7 +1093,6 @@ namespace RHLauncher
Exception newLogEx = new(errorLog, ex); Exception newLogEx = new(errorLog, ex);
ExceptionHandler.HandleException(newEx, newLogEx); ExceptionHandler.HandleException(newEx, newLogEx);
} }
#endregion #endregion
} }

View file

@ -10,10 +10,10 @@ namespace RHLauncher
{ {
private RegistryHandler registryHandler = new(); private RegistryHandler registryHandler = new();
private string windyCode = string.Empty; public string windyCode = string.Empty;
private string password = string.Empty; public string password = string.Empty;
private readonly string LoginUrl = Configuration.Default.LoginUrl; public string LoginUrl = Configuration.Default.LoginUrl;
private readonly string Lang = Configuration.Default.Lang; public string Lang = Configuration.Default.Lang;
private List<Button>? buttons; private List<Button>? buttons;
private List<ImageList>? imageLists; private List<ImageList>? imageLists;
private Dictionary<string, List<ImageList>>? languageImageLists; private Dictionary<string, List<ImageList>>? languageImageLists;
@ -42,8 +42,8 @@ namespace RHLauncher
private void LoadLocalizedStrings() private void LoadLocalizedStrings()
{ {
// Initialize buttons and image lists // Initialize buttons and image lists
buttons = [LoginButton, RegisterButton]; buttons = new List<Button> { LoginButton, RegisterButton };
imageLists = [imageListLogin, imageListRegister]; imageLists = new List<ImageList> { imageListLogin, imageListRegister };
// Initialize language-specific image lists // Initialize language-specific image lists
languageImageLists = new Dictionary<string, List<ImageList>> languageImageLists = new Dictionary<string, List<ImageList>>
@ -171,12 +171,12 @@ namespace RHLauncher
private async Task<string> SendLoginRequestAsync() private async Task<string> SendLoginRequestAsync()
{ {
using HttpClient client = new(); using HttpClient client = new();
using HttpResponseMessage response = await client.PostAsync(LoginUrl, new FormUrlEncodedContent( using HttpResponseMessage response = await client.PostAsync(LoginUrl, new FormUrlEncodedContent(new[]
[ {
new KeyValuePair<string, string>("account", UsernameTextBox.Text), new KeyValuePair<string, string>("account", UsernameTextBox.Text),
new KeyValuePair<string, string>("password", PasswordTextBox.Text) new KeyValuePair<string, string>("password", PasswordTextBox.Text)
])); }));
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync(); return await response.Content.ReadAsStringAsync();
} }
@ -184,63 +184,52 @@ namespace RHLauncher
{ {
try try
{ {
var loginResponse = JsonConvert.DeserializeObject<LoginResponse>(response); Dictionary<string, string>? loginResponse = JsonConvert.DeserializeObject<Dictionary<string, string>>(response);
if (loginResponse == null) if (loginResponse != null)
{ {
MsgBoxForm.Show(LocalizedStrings.Error + $": {LocalizedStrings.HttpResponseNull}", LocalizedStrings.Error); if (loginResponse.TryGetValue("Result", out var result))
return; {
switch (result)
{
case "LoginSuccess":
windyCode = loginResponse["WindyCode"];
password = loginResponse["Token"];
progressBarLogin.Visible = false;
Hide();
notifyIcon.Visible = false;
LauncherForm launcherForm = new(windyCode, password);
launcherForm.ShowDialog();
break;
case "InvalidCredentials":
MsgBoxForm.Show(LocalizedStrings.LoginInvalidCredentials, LocalizedStrings.LoginInfoTitle);
break;
case "InvalidUsernameFormat":
MsgBoxForm.Show(LocalizedStrings.LoginInvalidUsernameFormat, LocalizedStrings.LoginInfoTitle);
break;
case "AccountNotFound":
MsgBoxForm.Show(LocalizedStrings.LoginInvalidCredentials, LocalizedStrings.LoginInfoTitle);
break;
case "Locked":
MsgBoxForm.Show(LocalizedStrings.LoginLocked, LocalizedStrings.LoginInfoTitle);
break;
case "TooManyAttempts":
MsgBoxForm.Show(LocalizedStrings.LoginTooManyAttempts, LocalizedStrings.LoginInfoTitle);
break;
default:
MsgBoxForm.Show(LocalizedStrings.Error + result, LocalizedStrings.Error);
break;
}
}
else
{
MsgBoxForm.Show(LocalizedStrings.Error + "Response does not contain a Result field.", LocalizedStrings.Error);
}
} }
else
switch (loginResponse.Result)
{ {
case "LoginSuccess": MsgBoxForm.Show(LocalizedStrings.Error + "Failed to deserialize the response.", LocalizedStrings.Error);
if (!string.IsNullOrEmpty(loginResponse.WindyCode) && !string.IsNullOrEmpty(loginResponse.Token))
{
windyCode = loginResponse.WindyCode;
password = loginResponse.Token;
progressBarLogin.Visible = false;
Hide();
notifyIcon.Visible = false;
LauncherForm launcherForm = new(windyCode, password);
launcherForm.ShowDialog();
}
else
{
MsgBoxForm.Show(LocalizedStrings.Error + " Missing token or windyCode.", LocalizedStrings.Error);
}
break;
case "InvalidCredentials":
case "AccountNotFound":
MsgBoxForm.Show(LocalizedStrings.LoginInvalidCredentials, LocalizedStrings.LoginInfoTitle);
break;
case "Locked":
MsgBoxForm.Show(LocalizedStrings.LoginLocked, LocalizedStrings.LoginInfoTitle);
break;
case "TooManyAttempts":
MsgBoxForm.Show(LocalizedStrings.LoginTooManyAttempts, LocalizedStrings.LoginInfoTitle);
break;
case "InvalidRequest":
case "ServerError":
if (!string.IsNullOrEmpty(loginResponse.Message))
{
MsgBoxForm.Show(loginResponse.Message, LocalizedStrings.Error);
}
else
{
MsgBoxForm.Show(LocalizedStrings.Error + ": " + loginResponse.Result, LocalizedStrings.Error);
}
break;
default:
MsgBoxForm.Show(LocalizedStrings.Error + ": " + loginResponse.Result, LocalizedStrings.Error);
break;
} }
} }
catch (Exception ex) catch (Exception ex)
{ {

View file

@ -1,11 +1,9 @@
using RHLauncher.RHLauncher.i8n; using RHLauncher.RHLauncher.i8n;
using System.ComponentModel;
namespace RHLauncher namespace RHLauncher
{ {
public partial class MsgBoxForm : Form public partial class MsgBoxForm : Form
{ {
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public new DialogResult DialogResult { get; private set; } public new DialogResult DialogResult { get; private set; }
public MsgBoxForm() public MsgBoxForm()

View file

@ -1,5 +1,4 @@
using Newtonsoft.Json; using RHLauncher.RHLauncher.Helper;
using RHLauncher.RHLauncher.Helper;
using RHLauncher.RHLauncher.i8n; using RHLauncher.RHLauncher.i8n;
using System.Diagnostics; using System.Diagnostics;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
@ -8,11 +7,11 @@ namespace RHLauncher
{ {
public partial class RegisterForm : Form public partial class RegisterForm : Form
{ {
private readonly string SendCodeUrl = Configuration.Default.SendCodeUrl; public string SendCodeUrl = Configuration.Default.SendCodeUrl;
private readonly string AgreementUrl = Configuration.Default.AgreementUrl; public string AgreementUrl = Configuration.Default.AgreementUrl;
private readonly string VerifyCodeUrl = Configuration.Default.VerifyCodeUrl; public string VerifyCodeUrl = Configuration.Default.VerifyCodeUrl;
private readonly string RegisterUrl = Configuration.Default.RegisterUrl; public string RegisterUrl = Configuration.Default.RegisterUrl;
private readonly string Lang = Configuration.Default.Lang; public string Lang = Configuration.Default.Lang;
private List<Button>? buttons; private List<Button>? buttons;
private List<ImageList>? imageLists; private List<ImageList>? imageLists;
private Dictionary<string, List<ImageList>>? languageImageLists; private Dictionary<string, List<ImageList>>? languageImageLists;
@ -56,16 +55,16 @@ namespace RHLauncher
private void LoadLocalizedStrings() private void LoadLocalizedStrings()
{ {
// Initialize buttons and image lists // Initialize buttons and image lists
buttons = [ContinueButtonS1, SendEmailButton, ContinueButtonS2]; buttons = new List<Button> { ContinueButtonS1, SendEmailButton, ContinueButtonS2 };
imageLists = [imageListContinueBtn, imageListSendEmailBtn, imageListContinueBtn]; imageLists = new List<ImageList> { imageListContinueBtn, imageListSendEmailBtn, imageListContinueBtn };
// Initialize language-specific image lists // Initialize language-specific image lists
languageImageLists = new Dictionary<string, List<ImageList>> languageImageLists = new Dictionary<string, List<ImageList>>
{ {
{ "en", new List<ImageList> { imageListContinueBtn, imageListSendEmailBtn, imageListContinueBtn } }, // English image lists { "en", new List<ImageList> { imageListContinueBtn, imageListSendEmailBtn, imageListContinueBtn } }, // English image lists
{ "ko", new List<ImageList> { imageListContinueBtn_ko, imageListSendEmailBtn_ko, imageListContinueBtn_ko } }, // Korean image lists { "ko", new List<ImageList> { imageListContinueBtn_ko, imageListSendEmailBtn_ko, imageListContinueBtn_ko } }, // Korean image lists
// Add other languages and their respective image lists here // Add other languages and their respective image lists here
}; };
// Load the appropriate resource file based on the selected language // Load the appropriate resource file based on the selected language
LocalizationHelper.LoadLocalizedStrings(Lang, buttons, imageLists, languageImageLists); LocalizationHelper.LoadLocalizedStrings(Lang, buttons, imageLists, languageImageLists);
@ -89,26 +88,18 @@ namespace RHLauncher
private async Task<string> SendEmailRequestAsync() private async Task<string> SendEmailRequestAsync()
{ {
using HttpClient client = new(); using HttpClient client = new();
using HttpResponseMessage response = await client.PostAsync(SendCodeUrl, new FormUrlEncodedContent( using HttpResponseMessage response = await client.PostAsync(SendCodeUrl, new FormUrlEncodedContent(new[]
[ {
new KeyValuePair<string, string>("email", EmailTextBox.Text), new KeyValuePair<string, string>("email", EmailTextBox.Text),
])); }));
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync(); return await response.Content.ReadAsStringAsync();
} }
private void HandleSendEmailResponse(string response) private void HandleSendEmailResponse(string response)
{ {
HttpResponse? httpResponse = JsonConvert.DeserializeObject<HttpResponse>(response); switch (response)
if (httpResponse == null)
{
MsgBoxForm.Show(LocalizedStrings.Error + $": {LocalizedStrings.HttpResponseNull}", LocalizedStrings.Error);
return;
}
switch (httpResponse.Result)
{ {
case "EmailSent": case "EmailSent":
SendEmailButton.Enabled = false; SendEmailButton.Enabled = false;
@ -116,7 +107,6 @@ namespace RHLauncher
break; break;
case "AccountExists": case "AccountExists":
MsgBoxForm.Show(LocalizedStrings.AccountEmailExists, LocalizedStrings.Info); MsgBoxForm.Show(LocalizedStrings.AccountEmailExists, LocalizedStrings.Info);
ResetSendEmailButton();
break; break;
case "ValidVerificationCode": case "ValidVerificationCode":
// Hide the first panel and show the second panel // Hide the first panel and show the second panel
@ -151,65 +141,51 @@ namespace RHLauncher
// If the timer has finished counting down, stop the timer and enable the ResendEmailButton // If the timer has finished counting down, stop the timer and enable the ResendEmailButton
if (secondsLeft == 0) if (secondsLeft == 0)
{ {
ResetSendEmailButton(); resendTimer.Stop();
SendEmailButton.Enabled = true;
TimerLabel.Text = "";
} }
} }
private void ResetSendEmailButton()
{
resendTimer.Stop();
SendEmailButton.Enabled = true;
TimerLabel.Text = "";
}
private async Task<string> VerifyCodeSendRequestAsync() private async Task<string> VerifyCodeSendRequestAsync()
{ {
using HttpClient client = new(); using HttpClient client = new();
using HttpResponseMessage response = await client.PostAsync(VerifyCodeUrl, new FormUrlEncodedContent( using HttpResponseMessage response = await client.PostAsync(VerifyCodeUrl, new FormUrlEncodedContent(new[]
[ {
new KeyValuePair<string, string>("email", EmailTextBox.Text), new KeyValuePair<string, string>("email", EmailTextBox.Text),
new KeyValuePair<string, string>("verificationCode", CodeTextBox.Text), new KeyValuePair<string, string>("verification_code", CodeTextBox.Text),
new KeyValuePair<string, string>("verificationCodeType", "Account"), new KeyValuePair<string, string>("verification_code_type", "Account"),
}));
]));
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync(); return await response.Content.ReadAsStringAsync();
} }
private async Task<string> SendRequestAsync() private async Task<string> SendRequestAsync()
{ {
using HttpClient client = new(); using HttpClient client = new();
using HttpResponseMessage response = await client.PostAsync(RegisterUrl, new FormUrlEncodedContent( using HttpResponseMessage response = await client.PostAsync(RegisterUrl, new FormUrlEncodedContent(new[]
[ {
new KeyValuePair<string, string>("username", UsernameTextBox.Text), new KeyValuePair<string, string>("windyCode", UsernameTextBox.Text),
new KeyValuePair<string, string>("email", EmailTextBox.Text), new KeyValuePair<string, string>("email", EmailTextBox.Text),
new KeyValuePair<string, string>("password", PasswordTextBox.Text), new KeyValuePair<string, string>("password", PasswordTextBox.Text)
new KeyValuePair<string, string>("verificationCode", CodeTextBox.Text) }));
]));
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync(); return await response.Content.ReadAsStringAsync();
} }
private void HandleResponse(string response) private void HandleResponse(string response)
{ {
HttpResponse? accounResponse = JsonConvert.DeserializeObject<HttpResponse>(response); switch (response)
if (accounResponse == null)
{ {
MsgBoxForm.Show(LocalizedStrings.Error + $": {LocalizedStrings.HttpResponseNull}", LocalizedStrings.Error); case "Success":
return;
}
switch (accounResponse.Result)
{
case "AccountCreated":
MsgBoxForm.Show(LocalizedStrings.AccountCreateSuccess, LocalizedStrings.RegisterWindow); MsgBoxForm.Show(LocalizedStrings.AccountCreateSuccess, LocalizedStrings.RegisterWindow);
Close(); Close();
break; break;
case "EmailExists": case "AccountExists":
MsgBoxForm.Show(LocalizedStrings.AccountEmailExists, LocalizedStrings.Info); MsgBoxForm.Show(LocalizedStrings.AccountExists, LocalizedStrings.Info);
break; break;
case "UsernameExists": case "WindyCodeExists":
MsgBoxForm.Show(LocalizedStrings.WindyCodeExists, LocalizedStrings.Error); MsgBoxForm.Show(LocalizedStrings.WindyCodeExists, LocalizedStrings.Error);
break; break;
case "InvalidUserNameFormat": case "InvalidUserNameFormat":
@ -219,7 +195,7 @@ namespace RHLauncher
MsgBoxForm.Show(LocalizedStrings.InvalidEmailFormat, LocalizedStrings.Error); MsgBoxForm.Show(LocalizedStrings.InvalidEmailFormat, LocalizedStrings.Error);
break; break;
default: default:
MsgBoxForm.Show($"{LocalizedStrings.Error}: " + accounResponse.Message, LocalizedStrings.Error); MsgBoxForm.Show($"{LocalizedStrings.Error}: {response}", LocalizedStrings.Error);
break; break;
} }
@ -399,7 +375,7 @@ namespace RHLauncher
string password = PasswordTextBox.Text; string password = PasswordTextBox.Text;
// Check for minimum length and maximum length // Check for minimum length and maximum length
if (password.Length < 8 || password.Length > 16) if (password.Length < 6 || password.Length > 16)
{ {
PwdDescLabel.Text = LocalizedStrings.PwdDescLabelSize; PwdDescLabel.Text = LocalizedStrings.PwdDescLabelSize;
PwdDescLabel.ForeColor = Color.Red; PwdDescLabel.ForeColor = Color.Red;

View file

@ -10,20 +10,20 @@ public class Configuration
public Configuration() public Configuration()
{ {
string apiUrl = iniFile.ReadValue("Info", "ServerURL"); string apiUrl = iniFile.ReadValue("Info", "LoginURL");
//Client endpoints //Client endpoints
GateXMLUrl = $"{apiUrl}/launcher/GetGatewayAction"; GateXMLUrl = $"{apiUrl}/serverApi/gateway";
GateInfoUrl = $"{apiUrl}/launcher/GetGatewayAction/info"; GateInfoUrl = $"{apiUrl}/serverApi/gateway/info";
GateStatusUrl = $"{apiUrl}/launcher/GetGatewayAction/status"; GateStatusUrl = $"{apiUrl}/serverApi/gateway/status";
//Launcher endpoints //Launcher endpoints
LoginUrl = $"{apiUrl}/launcher/LoginAction"; LoginUrl = $"{apiUrl}/accountApi/login";
RegisterUrl = $"{apiUrl}/launcher/SignupAction"; RegisterUrl = $"{apiUrl}/accountApi/register";
SendCodeUrl = $"{apiUrl}/launcher/SendVerificationEmailAction"; SendCodeUrl = $"{apiUrl}/accountApi/sendVerificationEmail";
VerifyCodeUrl = $"{apiUrl}/launcher/VerifyCodeAction"; VerifyCodeUrl = $"{apiUrl}/accountApi/codeVerification";
SendPasswordCodeUrl = $"{apiUrl}/launcher/SendPasswordResetEmailAction"; SendPasswordCodeUrl = $"{apiUrl}/accountApi/sendPasswordResetEmail";
ChangePasswordUrl = $"{apiUrl}/launcher/ResetPasswordAction"; ChangePasswordUrl = $"{apiUrl}/accountApi/changePassword";
LauncherNewsUrl = $"{apiUrl}/launcher/news"; LauncherNewsUrl = $"{apiUrl}/launcher/news";
AgreementUrl = $"{apiUrl}/launcher/agreement"; AgreementUrl = $"{apiUrl}/launcher/agreement";
@ -36,12 +36,12 @@ public class Configuration
DownloadUpdateFileUrl = $"{apiUrl}/launcher/patch"; DownloadUpdateFileUrl = $"{apiUrl}/launcher/patch";
//Launcher update endpoints //Launcher update endpoints
GetLauncherVersion = $"{apiUrl}/launcherAction/getLauncherVersion"; GetLauncherVersion = $"{apiUrl}/launcherApi/launcherUpdater/getLauncherVersion";
UpdateLauncherVersion = $"{apiUrl}/launcherAction/updateLauncherVersion"; UpdateLauncherVersion = $"{apiUrl}/launcherApi/launcherUpdater/updateLauncherVersion";
//Launcher settings //Launcher settings
Lang = iniFile.ReadValue("Launcher", "Lang"); string lang = iniFile.ReadValue("Launcher", "Lang");
Service = iniFile.ReadValue("Info", "Service"); Lang = lang;
} }
public string GateXMLUrl { get; set; } public string GateXMLUrl { get; set; }
@ -62,6 +62,5 @@ public class Configuration
public string ClientPartsListUrl { get; set; } public string ClientPartsListUrl { get; set; }
public string DownloadClientPartUrl { get; set; } public string DownloadClientPartUrl { get; set; }
public string Lang { get; set; } public string Lang { get; set; }
public string Service { get; set; }
} }

View file

@ -1,36 +0,0 @@
using Newtonsoft.Json;
namespace RHLauncher.RHLauncher.Helper;
public class HttpResponse
{
[JsonProperty("success")]
public string? Success { get; set; }
[JsonProperty("result")]
public string? Result { get; set; }
[JsonProperty("message")]
public string? Message { get; set; }
}
public class LoginResponse
{
[JsonProperty("result")]
public string? Result { get; set; }
[JsonProperty("token")]
public string? Token { get; set; }
[JsonProperty("windyCode")]
public string? WindyCode { get; set; }
[JsonProperty("message")]
public string? Message { get; set; }
}
public class ServerStatusResponse
{
[JsonProperty("status")]
public string? Status { get; set; }
}

View file

@ -21,9 +21,9 @@ namespace RHLauncher.RHLauncher.Helper
if (!File.Exists(_iniFilePath)) if (!File.Exists(_iniFilePath))
{ {
//Default api url //Default api url
WritePrivateProfileString("Info", "ServerURL", "http://127.0.0.1", _iniFilePath); WritePrivateProfileString("Info", "LoginURL", "http://localhost:3000", _iniFilePath);
//Default client service //Default client service
WritePrivateProfileString("Info", "Service", "jpn", _iniFilePath); WritePrivateProfileString("Info", "Service", "usa", _iniFilePath);
//Default launcher language //Default launcher language
WritePrivateProfileString("Launcher", "Lang", "en", _iniFilePath); WritePrivateProfileString("Launcher", "Lang", "en", _iniFilePath);
} }

View file

@ -1,8 +1,8 @@
using RHLauncher.RHLauncher.Helper; using Ionic.Zip;
using RHLauncher.RHLauncher.Helper;
using RHLauncher.RHLauncher.i8n; using RHLauncher.RHLauncher.i8n;
using System.Diagnostics; using System.Diagnostics;
using System.Globalization; using System.Globalization;
using System.IO.Compression;
using System.Net; using System.Net;
namespace RHLauncher.RHLauncher.Http namespace RHLauncher.RHLauncher.Http
@ -51,10 +51,10 @@ namespace RHLauncher.RHLauncher.Http
Directory.CreateDirectory(downloadDir); Directory.CreateDirectory(downloadDir);
} }
List<string> filesToBeDownloaded = []; List<string> filesToBeDownloaded = new();
long totalBytesToDownload = 0L; long totalBytesToDownload = 0L;
List<string> lines = [.. filelistText.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries)]; List<string> lines = filelistText.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries).ToList();
int totalLines = lines.Count; int totalLines = lines.Count;
int checkedFiles = 0; int checkedFiles = 0;
@ -146,17 +146,14 @@ namespace RHLauncher.RHLauncher.Http
private static async Task<string> UnzipFilesAsync(string sourceDirectory, string destinationDirectory, IProgress<ProgressReport> progress, CancellationToken cancellationToken) private static async Task<string> UnzipFilesAsync(string sourceDirectory, string destinationDirectory, IProgress<ProgressReport> progress, CancellationToken cancellationToken)
{ {
string[] fileEntries = [.. Directory.GetFiles(sourceDirectory, "*.zip.*").OrderBy(f => f)]; string[] fileEntries = Directory.GetFiles(sourceDirectory, "*.zip.*").OrderBy(f => f).ToArray();
string rhExeDirectoryPath = ""; string rhExeDirectoryPath = "";
// Calculate total uncompressed size of all files in all zip archives // Calculate total uncompressed size of all files in all zip archives
long totalUncompressedSize = fileEntries.Sum(file => long totalUncompressedSize = fileEntries.Sum(file =>
{ {
using FileStream fs = new(file, FileMode.Open, FileAccess.Read); using ZipFile zip = ZipFile.Read(file);
using ZipArchive zip = new(fs, ZipArchiveMode.Read); return zip.Entries.Sum(entry => entry.UncompressedSize);
static long entryLength(ZipArchiveEntry entry) => entry.Length;
return zip.Entries.Sum(entryLength);
}); });
long totalExtracted = 0; long totalExtracted = 0;
@ -166,27 +163,26 @@ namespace RHLauncher.RHLauncher.Http
{ {
await Task.Run(() => await Task.Run(() =>
{ {
using FileStream fs = new(file, FileMode.Open, FileAccess.Read); using ZipFile zip = ZipFile.Read(file);
using ZipArchive zip = new(fs, ZipArchiveMode.Read); foreach (var entry in zip)
foreach (var entry in zip.Entries)
{ {
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
string destinationPath = Path.Combine(destinationDirectory, entry.FullName); string destinationPath = Path.Combine(destinationDirectory, entry.FileName);
string? directoryPath = Path.GetDirectoryName(destinationPath); string? directoryPath = Path.GetDirectoryName(destinationPath);
if (!string.IsNullOrEmpty(directoryPath) && !Directory.Exists(directoryPath)) if (!string.IsNullOrEmpty(directoryPath) && !Directory.Exists(directoryPath))
{ {
Directory.CreateDirectory(directoryPath); Directory.CreateDirectory(directoryPath);
} }
entry.ExtractToFile(destinationPath, overwrite: true); entry.Extract(destinationDirectory, ExtractExistingFileAction.OverwriteSilently);
totalExtracted += entry.Length; totalExtracted += entry.UncompressedSize;
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
ProgressReporter.ReportUnzipProgress(progress, totalExtracted, totalUncompressedSize, cancellationToken); ProgressReporter.ReportUnzipProgress(progress, totalExtracted, totalUncompressedSize, cancellationToken);
// Check if the current entry is "rustyhearts.exe" and store its directory path // Check if the current entry is "rustyhearts.exe" and store its directory path
if (entry.FullName.EndsWith("rustyhearts.exe", StringComparison.OrdinalIgnoreCase)) if (entry.FileName.EndsWith("rustyhearts.exe", StringComparison.OrdinalIgnoreCase))
{ {
rhExeDirectoryPath = Path.GetDirectoryName(destinationPath) ?? ""; rhExeDirectoryPath = Path.GetDirectoryName(destinationPath) ?? "";
} }
@ -221,5 +217,7 @@ namespace RHLauncher.RHLauncher.Http
throw new FileNotFoundException($"{LocalizedStrings.ClientFolderExeErrorMessage}"); throw new FileNotFoundException($"{LocalizedStrings.ClientFolderExeErrorMessage}");
} }
} }
} }
} }

View file

@ -1,4 +1,4 @@
using System.IO.Compression; using Ionic.Zlib;
using RHLauncher.RHLauncher.Helper; using RHLauncher.RHLauncher.Helper;
using System.Text; using System.Text;
@ -35,7 +35,7 @@ namespace RHLauncher.RHLauncher.PCK
try try
{ {
using MemoryStream compressedStream = new(compressedBytes); using MemoryStream compressedStream = new(compressedBytes);
using ZLibStream deflateStream = new(compressedStream, CompressionMode.Decompress); using ZlibStream deflateStream = new(compressedStream, CompressionMode.Decompress);
using MemoryStream decompressedStream = new(); using MemoryStream decompressedStream = new();
deflateStream.CopyTo(decompressedStream); deflateStream.CopyTo(decompressedStream);
decompressedStream.Seek(0, SeekOrigin.Begin); decompressedStream.Seek(0, SeekOrigin.Begin);

View file

@ -6,7 +6,7 @@
<PropertyGroup> <PropertyGroup>
<OutputType>WinExe</OutputType> <OutputType>WinExe</OutputType>
<TargetFramework>net9.0-windows</TargetFramework> <TargetFramework>net7.0-windows7.0</TargetFramework>
<SatelliteResourceLanguages>en</SatelliteResourceLanguages> <SatelliteResourceLanguages>en</SatelliteResourceLanguages>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<UseWindowsForms>true</UseWindowsForms> <UseWindowsForms>true</UseWindowsForms>
@ -19,8 +19,8 @@
<AssemblyName>Launcher</AssemblyName> <AssemblyName>Launcher</AssemblyName>
<Description>Rusty Hearts Launcher</Description> <Description>Rusty Hearts Launcher</Description>
<PlatformTarget>x64</PlatformTarget> <PlatformTarget>x64</PlatformTarget>
<AssemblyVersion>1.4.0</AssemblyVersion> <AssemblyVersion>1.2.0</AssemblyVersion>
<FileVersion>1.4.0</FileVersion> <FileVersion>1.2.0</FileVersion>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
@ -36,9 +36,10 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.3179.45" /> <PackageReference Include="DotNetZip" Version="1.16.0" />
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.2210.55" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="WindowsAPICodePack" Version="8.0.6" /> <PackageReference Include="WindowsAPICodePack" Version="7.0.4" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View file

@ -438,24 +438,6 @@ namespace RHLauncher.RHLauncher.i8n {
} }
} }
/// <summary>
/// Looks up a localized string similar to Failed to process server response..
/// </summary>
public static string HttpResponseNull {
get {
return ResourceManager.GetString("HttpResponseNull", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Failed to parse server response..
/// </summary>
public static string HttpResponseParseError {
get {
return ResourceManager.GetString("HttpResponseParseError", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Info. /// Looks up a localized string similar to Info.
/// </summary> /// </summary>
@ -754,7 +736,7 @@ namespace RHLauncher.RHLauncher.i8n {
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to 8-16 characters. /// Looks up a localized string similar to 6-16 characters.
/// </summary> /// </summary>
public static string NewPasswordDesc { public static string NewPasswordDesc {
get { get {
@ -844,7 +826,7 @@ namespace RHLauncher.RHLauncher.i8n {
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to Password must be between 8-16 characters!. /// Looks up a localized string similar to Password must be between 6-16 characters!.
/// </summary> /// </summary>
public static string PwdDescLabelSize { public static string PwdDescLabelSize {
get { get {
@ -996,15 +978,6 @@ namespace RHLauncher.RHLauncher.i8n {
} }
} }
/// <summary>
/// Looks up a localized string similar to Service.
/// </summary>
public static string Service {
get {
return ResourceManager.GetString("Service", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Could not find Service.dat. Please check if the Install Directory is correct.. /// Looks up a localized string similar to Could not find Service.dat. Please check if the Install Directory is correct..
/// </summary> /// </summary>

View file

@ -243,12 +243,6 @@
<data name="GameSettings" xml:space="preserve"> <data name="GameSettings" xml:space="preserve">
<value>게임 설정</value> <value>게임 설정</value>
</data> </data>
<data name="HttpResponseNull" xml:space="preserve">
<value>서버 응답을 처리하지 못했습니다.</value>
</data>
<data name="HttpResponseParseError" xml:space="preserve">
<value>서버 응답을 구문 분석하는 데 실패했습니다.</value>
</data>
<data name="Info" xml:space="preserve"> <data name="Info" xml:space="preserve">
<value>정보</value> <value>정보</value>
</data> </data>
@ -349,7 +343,7 @@
<value>새 비밀번호를 입력하세요</value> <value>새 비밀번호를 입력하세요</value>
</data> </data>
<data name="NewPasswordDesc" xml:space="preserve"> <data name="NewPasswordDesc" xml:space="preserve">
<value>8~16자</value> <value>6~16자</value>
</data> </data>
<data name="No" xml:space="preserve"> <data name="No" xml:space="preserve">
<value>아니요</value> <value>아니요</value>
@ -379,7 +373,7 @@
<value>비밀번호는 비워둘 수 없습니다!</value> <value>비밀번호는 비워둘 수 없습니다!</value>
</data> </data>
<data name="PwdDescLabelSize" xml:space="preserve"> <data name="PwdDescLabelSize" xml:space="preserve">
<value>비밀번호는 8~16자 사이여야 합니다!</value> <value>비밀번호는 6~16자 사이여야 합니다!</value>
</data> </data>
<data name="PwdStrengthLabelMedium" xml:space="preserve"> <data name="PwdStrengthLabelMedium" xml:space="preserve">
<value>매질</value> <value>매질</value>
@ -429,9 +423,6 @@
<data name="ServerOffline" xml:space="preserve"> <data name="ServerOffline" xml:space="preserve">
<value>게임 서버에 연결할 수 없습니다.</value> <value>게임 서버에 연결할 수 없습니다.</value>
</data> </data>
<data name="Service" xml:space="preserve">
<value>서비스</value>
</data>
<data name="ServiceDatFileMissing" xml:space="preserve"> <data name="ServiceDatFileMissing" xml:space="preserve">
<value>Service.dat를 찾을 수 없습니다. 설치 디렉터리가 올바른지 확인하세요.</value> <value>Service.dat를 찾을 수 없습니다. 설치 디렉터리가 올바른지 확인하세요.</value>
</data> </data>

View file

@ -243,12 +243,6 @@
<data name="GameSettings" xml:space="preserve"> <data name="GameSettings" xml:space="preserve">
<value>Game Settings</value> <value>Game Settings</value>
</data> </data>
<data name="HttpResponseNull" xml:space="preserve">
<value>Failed to process server response.</value>
</data>
<data name="HttpResponseParseError" xml:space="preserve">
<value>Failed to parse server response.</value>
</data>
<data name="Info" xml:space="preserve"> <data name="Info" xml:space="preserve">
<value>Info</value> <value>Info</value>
</data> </data>
@ -349,7 +343,7 @@
<value>Enter the new password</value> <value>Enter the new password</value>
</data> </data>
<data name="NewPasswordDesc" xml:space="preserve"> <data name="NewPasswordDesc" xml:space="preserve">
<value>8-16 characters</value> <value>6-16 characters</value>
</data> </data>
<data name="No" xml:space="preserve"> <data name="No" xml:space="preserve">
<value>No</value> <value>No</value>
@ -379,7 +373,7 @@
<value>Password cannot be empty!</value> <value>Password cannot be empty!</value>
</data> </data>
<data name="PwdDescLabelSize" xml:space="preserve"> <data name="PwdDescLabelSize" xml:space="preserve">
<value>Password must be between 8-16 characters!</value> <value>Password must be between 6-16 characters!</value>
</data> </data>
<data name="PwdStrengthLabelMedium" xml:space="preserve"> <data name="PwdStrengthLabelMedium" xml:space="preserve">
<value>Medium</value> <value>Medium</value>
@ -429,9 +423,6 @@
<data name="ServerOffline" xml:space="preserve"> <data name="ServerOffline" xml:space="preserve">
<value>Cannot connect to the game server.</value> <value>Cannot connect to the game server.</value>
</data> </data>
<data name="Service" xml:space="preserve">
<value>Service</value>
</data>
<data name="ServiceDatFileMissing" xml:space="preserve"> <data name="ServiceDatFileMissing" xml:space="preserve">
<value>Could not find Service.dat. Please check if the Install Directory is correct.</value> <value>Could not find Service.dat. Please check if the Install Directory is correct.</value>
</data> </data>