Compare commits

..

37 commits

Author SHA1 Message Date
Junior
d45726a46b Update README.md 2025-04-29 17:21:18 -03:00
Junior
1692923e18 Changes for RustyHearts-API 1.3.0 2025-04-29 17:14:19 -03:00
Hamilton
558761943e
Bump Microsoft.Web.WebView2 from 1.0.2903.40 to 1.0.3179.45
Bump Microsoft.Web.WebView2 from 1.0.2903.40 to 1.0.3179.45
2025-04-08 08:40:06 -03:00
dependabot[bot]
5be5ff2e10
Bump Microsoft.Web.WebView2 from 1.0.2903.40 to 1.0.3179.45
Bumps Microsoft.Web.WebView2 from 1.0.2903.40 to 1.0.3179.45.

---
updated-dependencies:
- dependency-name: Microsoft.Web.WebView2
  dependency-version: 1.0.3179.45
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-07 13:48:40 +00:00
Junior
8526698244 Refactor zip handling for System.IO.Compression 2024-11-28 07:51:57 -03:00
Junior
9fb4b4a6af Update release.yml 2024-11-27 00:42:24 -03:00
Junior
7849b2001a Updated dependencies
Replaced deprecated DotNetZip with System.IO.Compression.
Changed target framework to net 9.0.
Removed DotNetZip package reference.
Updated Microsoft.Web.WebView2 to 1.0.2903.40.
Updated WindowsAPICodePack to 8.0.6.
2024-11-27 00:28:46 -03:00
Hamilton
3648b49bb3
Bump WindowsAPICodePack from 7.0.4 to 8.0.4
Bump WindowsAPICodePack from 7.0.4 to 8.0.4
2024-06-11 13:41:59 -03:00
Hamilton
6d31e23124
Bump Microsoft.Web.WebView2 from 1.0.2365.46 to 1.0.2535.41
Bump Microsoft.Web.WebView2 from 1.0.2365.46 to 1.0.2535.41
2024-06-11 13:41:46 -03:00
dependabot[bot]
56973cf95f
Bump WindowsAPICodePack from 7.0.4 to 8.0.4
Bumps [WindowsAPICodePack](https://github.com/Wagnerp/Windows-API-CodePack-NET) from 7.0.4 to 8.0.4.
- [Changelog](https://github.com/Wagnerp/Windows-API-CodePack-NET/blob/main/Changelog.md)
- [Commits](https://github.com/Wagnerp/Windows-API-CodePack-NET/commits)

---
updated-dependencies:
- dependency-name: WindowsAPICodePack
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-10 12:25:20 +00:00
dependabot[bot]
5baa8daa62
Bump Microsoft.Web.WebView2 from 1.0.2365.46 to 1.0.2535.41
Bumps Microsoft.Web.WebView2 from 1.0.2365.46 to 1.0.2535.41.

---
updated-dependencies:
- dependency-name: Microsoft.Web.WebView2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-03 13:05:14 +00:00
Hamilton
a0c4fd7a5e
Bump Microsoft.Web.WebView2 from 1.0.2210.55 to 1.0.2365.46
Bump Microsoft.Web.WebView2 from 1.0.2210.55 to 1.0.2365.46
2024-03-12 16:47:22 -03:00
dependabot[bot]
30a30145bc
Bump Microsoft.Web.WebView2 from 1.0.2210.55 to 1.0.2365.46
Bumps Microsoft.Web.WebView2 from 1.0.2210.55 to 1.0.2365.46.

---
updated-dependencies:
- dependency-name: Microsoft.Web.WebView2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-04 12:09:16 +00:00
Junior
e74d93fab9 Version 1.2.0 2024-01-04 22:59:30 -03:00
Junior
9b3a0e00a2
Merge pull request #10 from JuniorDark/dependabot/github_actions/actions/setup-dotnet-4
Bump actions/setup-dotnet from 3 to 4
2023-12-17 22:27:06 -03:00
dependabot[bot]
6431d0f0cd
Bump actions/setup-dotnet from 3 to 4
Bumps [actions/setup-dotnet](https://github.com/actions/setup-dotnet) from 3 to 4.
- [Release notes](https://github.com/actions/setup-dotnet/releases)
- [Commits](https://github.com/actions/setup-dotnet/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/setup-dotnet
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-11 12:16:43 +00:00
Junior
9c2b46b0d6
Merge pull request #9 from JuniorDark/dependabot/nuget/Microsoft.Web.WebView2-1.0.2151.40
Bump Microsoft.Web.WebView2 from 1.0.2045.28 to 1.0.2151.40
2023-12-05 12:34:25 -03:00
dependabot[bot]
300530e657
Bump Microsoft.Web.WebView2 from 1.0.2045.28 to 1.0.2151.40
Bumps Microsoft.Web.WebView2 from 1.0.2045.28 to 1.0.2151.40.

---
updated-dependencies:
- dependency-name: Microsoft.Web.WebView2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-13 12:47:53 +00:00
Junior
ae34584021 Extended the localization system to easily include additional languages in the future 2023-10-07 00:08:43 -03:00
Junior
d5ec712d0f Fix bug related to collection modification during Application.Restart() on ChangePassword. 2023-10-05 23:36:56 -03:00
Junior
46b2b6f15d
Merge pull request #7 from JuniorDark/dependabot/nuget/Microsoft.Web.WebView2-1.0.2045.28
Bump Microsoft.Web.WebView2 from 1.0.1938.49 to 1.0.2045.28
2023-09-26 11:40:56 -03:00
dependabot[bot]
ecd29bdc5b
Bump Microsoft.Web.WebView2 from 1.0.1938.49 to 1.0.2045.28
Bumps Microsoft.Web.WebView2 from 1.0.1938.49 to 1.0.2045.28.

---
updated-dependencies:
- dependency-name: Microsoft.Web.WebView2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-25 12:25:58 +00:00
Junior
9c2bbd68c8
Merge pull request #6 from JuniorDark/dependabot/github_actions/actions/checkout-4
Bump actions/checkout from 3 to 4
2023-09-13 16:34:12 -03:00
Junior
e22421599f
Merge pull request #5 from JuniorDark/dependabot/nuget/Microsoft.Web.WebView2-1.0.1938.49
Bump Microsoft.Web.WebView2 from 1.0.1823.32 to 1.0.1938.49
2023-09-13 16:33:58 -03:00
dependabot[bot]
23446fef88
Bump actions/checkout from 3 to 4
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-04 12:29:44 +00:00
dependabot[bot]
d0e5102931
Bump Microsoft.Web.WebView2 from 1.0.1823.32 to 1.0.1938.49
Bumps Microsoft.Web.WebView2 from 1.0.1823.32 to 1.0.1938.49.

---
updated-dependencies:
- dependency-name: Microsoft.Web.WebView2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-04 12:24:00 +00:00
Junior
156835fa7b
Merge pull request #2 from JuniorDark/dependabot/github_actions/actions/checkout-3
Bump actions/checkout from 2 to 3
2023-06-19 18:00:23 -03:00
Junior
41d9b08d8c
Merge pull request #3 from JuniorDark/dependabot/github_actions/actions/setup-dotnet-3
Bump actions/setup-dotnet from 1 to 3
2023-06-19 18:00:13 -03:00
Junior
9a43aaa07f
Merge pull request #1 from JuniorDark/dependabot/nuget/Microsoft.Web.WebView2-1.0.1823.32
Bump Microsoft.Web.WebView2 from 1.0.1774.30 to 1.0.1823.32
2023-06-19 17:59:54 -03:00
dependabot[bot]
0c379e5e7d
Bump actions/setup-dotnet from 1 to 3
Bumps [actions/setup-dotnet](https://github.com/actions/setup-dotnet) from 1 to 3.
- [Release notes](https://github.com/actions/setup-dotnet/releases)
- [Commits](https://github.com/actions/setup-dotnet/compare/v1...v3)

---
updated-dependencies:
- dependency-name: actions/setup-dotnet
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-19 13:03:38 +00:00
dependabot[bot]
877cc7a4d6
Bump actions/checkout from 2 to 3
Bumps [actions/checkout](https://github.com/actions/checkout) from 2 to 3.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v2...v3)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-19 13:03:35 +00:00
dependabot[bot]
d98a18009e
Bump Microsoft.Web.WebView2 from 1.0.1774.30 to 1.0.1823.32
Bumps Microsoft.Web.WebView2 from 1.0.1774.30 to 1.0.1823.32.

---
updated-dependencies:
- dependency-name: Microsoft.Web.WebView2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-12 13:04:00 +00:00
Junior
086b25b83b Updated username regex to not allow uppercase characters 2023-06-09 19:47:07 -03:00
Junior
d319a7d4d7
Update RHLauncher.csproj 2023-06-05 23:16:16 -03:00
Junior
4aa059f309 Merge branch 'master' of https://github.com/JuniorDark/RustyHearts-Launcher 2023-06-05 23:08:58 -03:00
Junior
8cf88ab0e4 Add more error handling 2023-06-05 23:08:45 -03:00
Junior
71f7609dc5 Add more error handling 2023-06-05 23:03:15 -03:00
106 changed files with 113744 additions and 29814 deletions

View file

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

View file

@ -3,42 +3,50 @@ 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@v2 uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v1
with:
dotnet-version: '7.0.x'
- name: Get version from .csproj file
id: version
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '9.0.x'
# 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
run: | run: |
echo "::set-output name=version::$(grep -m1 -o '<FileVersion>[^<]*' RHLauncher.csproj | sed 's/<FileVersion>//')" $version = (Get-Command "./publish/RustyHearts-Launcher_self-contained/Launcher.dll").FileVersionInfo.FileVersion
- name: Build echo "::set-output name=version::$version"
run: dotnet publish --configuration Release --self-contained false --runtime win-x86 /p:PublishSingleFile=true
- name: Zip output file # Create Release and Upload Assets using softprops/action-gh-release
run: Compress-Archive -Path ./bin/Release/net7.0-windows7.0/win-x86/publish/Launcher.exe -DestinationPath Launcher.zip - name: Create GitHub Release and Upload Assets
- name: Create Release uses: softprops/action-gh-release@v2
id: create_release
uses: actions/create-release@v1
with: with:
tag_name: ${{ steps.version.outputs.version }} tag_name: v${{ steps.version.outputs.version }}
release_name: v${{ steps.version.outputs.version }} body: Automated pre-release created by GitHub Actions.
body: Automated release created by GitHub Actions. draft: true
draft: false prerelease: true
prerelease: false files: |
env: ./RustyHearts-Launcher-Framework-Dependent.zip
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ./RustyHearts-Launcher-SelfContained.zip
- 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 }}

3
App.config Normal file
View file

@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
</configuration>

View file

@ -1,18 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
public static class NativeMethod
{
[DllImport("kernel32.dll", EntryPoint = "LoadLibrary")]
public static extern int LoadLibrary(
[MarshalAs(UnmanagedType.LPStr)] string lpLibFileName);
[DllImport("kernel32.dll", EntryPoint = "GetProcAddress")]
public static extern IntPtr GetProcAddress(int hModule,
[MarshalAs(UnmanagedType.LPStr)] string lpProcName);
[DllImport("kernel32.dll", EntryPoint = "FreeLibrary")]
public static extern bool FreeLibrary(int hModule);
}

View file

@ -1,73 +0,0 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 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.
// </auto-generated>
//------------------------------------------------------------------------------
namespace RHLauncher.DynamicLib {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class ResourceDll {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal ResourceDll() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("RHLauncher.DynamicLib.ResourceDll", typeof(ResourceDll).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] ZlibDll {
get {
object obj = ResourceManager.GetObject("ZlibDll", resourceCulture);
return ((byte[])(obj));
}
}
}
}

View file

@ -1,124 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="ZlibDll" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>ZlibDll.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
</root>

View file

@ -1,41 +0,0 @@
using System;
using System.Text;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.IO;
using RHLauncher.DynamicLib;
public static class ZLibDll
{
//[DllImport("ZlibDll.dll", CallingConvention = CallingConvention.Cdecl)]
//public static extern int Decompress(byte[] compressed_buffer, int compressed_size, byte[] decompressed_buffer, ref int decompressed_size);
public delegate int DecompressDelegate(byte[] compressed_buffer, int compressed_size, byte[] decompressed_buffer, ref int decompressed_size);
public static DecompressDelegate? Decompress = null;
//[DllImport("ZlibDll.dll", CallingConvention = CallingConvention.Cdecl)]
//public static extern int Compress(byte[] decompressed_buffer, int decompressed_size, byte[] compressed_buffer, ref int compressed_size);
public delegate int CompressDelegate(byte[] decompressed_buffer, int decompressed_size, byte[] compressed_buffer, ref int compressed_size);
public static CompressDelegate? Compress = null;
static ZLibDll()
{
byte[] libBuffer = ResourceDll.ZlibDll;
string dllPath = Path.Combine(Path.GetTempPath(), "ZlibDll.dll");
try
{
File.WriteAllBytes(dllPath, libBuffer);
}
catch { }
int hModule = NativeMethod.LoadLibrary(dllPath);
if (hModule == 0) return;
IntPtr intPtr = NativeMethod.GetProcAddress(hModule, "Decompress");
Decompress = (DecompressDelegate)Marshal.GetDelegateForFunctionPointer(intPtr, typeof(DecompressDelegate));
intPtr = NativeMethod.GetProcAddress(hModule, "Compress");
Compress = (CompressDelegate)Marshal.GetDelegateForFunctionPointer(intPtr, typeof(CompressDelegate));
}
}

Binary file not shown.

Binary file not shown.

View file

@ -7,11 +7,13 @@ However, it requires further development to improve functionality and
ensure stability. Please check the GitHub repository for updates. ensure stability. Please check the GitHub repository for updates.
*/ */
using RHLauncher.RHLauncher.i8n;
namespace RHLauncher namespace RHLauncher
{ {
internal static class Program internal static class Program
{ {
private static readonly Mutex mutex = new(false, "Launcher"); private static readonly Mutex mutex = new(false, "RHLauncher");
/// <summary> /// <summary>
/// The main entry point for the application. /// The main entry point for the application.
/// </summary> /// </summary>
@ -29,7 +31,7 @@ namespace RHLauncher
} }
else else
{ {
MessageBox.Show("Only one instance of the launcher can run at a time."); MessageBox.Show(LocalizedStrings.LauncherAlreadyRunning, LocalizedStrings.Error);
} }
} }
} }

View file

@ -60,166 +60,6 @@ namespace RHLauncher.Properties {
} }
} }
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap bg {
get {
object obj = ResourceManager.GetObject("bg", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap button_close_active {
get {
object obj = ResourceManager.GetObject("button_close_active", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap button_close_down {
get {
object obj = ResourceManager.GetObject("button_close_down", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap button_close_normal {
get {
object obj = ResourceManager.GetObject("button_close_normal", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap button_login_active {
get {
object obj = ResourceManager.GetObject("button_login_active", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap button_login_down {
get {
object obj = ResourceManager.GetObject("button_login_down", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap button_login_normal {
get {
object obj = ResourceManager.GetObject("button_login_normal", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap button_minimize_active {
get {
object obj = ResourceManager.GetObject("button_minimize_active", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap button_minimize_down {
get {
object obj = ResourceManager.GetObject("button_minimize_down", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap button_minimize_normal {
get {
object obj = ResourceManager.GetObject("button_minimize_normal", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap button_register_active {
get {
object obj = ResourceManager.GetObject("button_register_active", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap button_register_down {
get {
object obj = ResourceManager.GetObject("button_register_down", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap button_register_normal {
get {
object obj = ResourceManager.GetObject("button_register_normal", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap ChangePwwnd_button_email_active {
get {
object obj = ResourceManager.GetObject("ChangePwwnd_button_email_active", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap ChangePwwnd_button_email_down {
get {
object obj = ResourceManager.GetObject("ChangePwwnd_button_email_down", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap ChangePwwnd_button_email_normal {
get {
object obj = ResourceManager.GetObject("ChangePwwnd_button_email_normal", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary> /// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap. /// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary> /// </summary>
@ -309,265 +149,5 @@ namespace RHLauncher.Properties {
return ((System.Drawing.Bitmap)(obj)); return ((System.Drawing.Bitmap)(obj));
} }
} }
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap help_panel_bkg {
get {
object obj = ResourceManager.GetObject("help_panel_bkg", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap launchbutton_bkg_active {
get {
object obj = ResourceManager.GetObject("launchbutton_bkg_active", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap launchbutton_bkg_down {
get {
object obj = ResourceManager.GetObject("launchbutton_bkg_down", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap launchbutton_bkg_normal {
get {
object obj = ResourceManager.GetObject("launchbutton_bkg_normal", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap launcher_bg {
get {
object obj = ResourceManager.GetObject("launcher_bg", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap launchoptionbutton_active {
get {
object obj = ResourceManager.GetObject("launchoptionbutton_active", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap launchoptionbutton_down {
get {
object obj = ResourceManager.GetObject("launchoptionbutton_down", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap launchoptionbutton_normal {
get {
object obj = ResourceManager.GetObject("launchoptionbutton_normal", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap list_button_hover {
get {
object obj = ResourceManager.GetObject("list_button_hover", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap list_button_normal {
get {
object obj = ResourceManager.GetObject("list_button_normal", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap login_bg {
get {
object obj = ResourceManager.GetObject("login_bg", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap menubutton_bkg_active {
get {
object obj = ResourceManager.GetObject("menubutton_bkg_active", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap menubutton_bkg_down {
get {
object obj = ResourceManager.GetObject("menubutton_bkg_down", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap menubutton_bkg_normal {
get {
object obj = ResourceManager.GetObject("menubutton_bkg_normal", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap message_bkg {
get {
object obj = ResourceManager.GetObject("message_bkg", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap messagewnd_button_ok_active {
get {
object obj = ResourceManager.GetObject("messagewnd_button_ok_active", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap messagewnd_button_ok_down {
get {
object obj = ResourceManager.GetObject("messagewnd_button_ok_down", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap messagewnd_button_ok_normal {
get {
object obj = ResourceManager.GetObject("messagewnd_button_ok_normal", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap Registerwnd_button_continue_active {
get {
object obj = ResourceManager.GetObject("Registerwnd_button_continue_active", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap Registerwnd_button_continue_down {
get {
object obj = ResourceManager.GetObject("Registerwnd_button_continue_down", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap Registerwnd_button_continue_normal {
get {
object obj = ResourceManager.GetObject("Registerwnd_button_continue_normal", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap Registerwndwnd_button_sendemail_active {
get {
object obj = ResourceManager.GetObject("Registerwndwnd_button_sendemail_active", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap Registerwndwnd_button_sendemail_down {
get {
object obj = ResourceManager.GetObject("Registerwndwnd_button_sendemail_down", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap Registerwndwnd_button_sendemail_normal {
get {
object obj = ResourceManager.GetObject("Registerwndwnd_button_sendemail_normal", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap tips_error {
get {
object obj = ResourceManager.GetObject("tips_error", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap tips_ok {
get {
object obj = ResourceManager.GetObject("tips_ok", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
} }
} }

View file

@ -118,54 +118,6 @@
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader> </resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> <assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="bg" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\bg\bg.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="button_close_active" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\buttons\button_close_active.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="button_close_down" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\buttons\button_close_down.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="button_close_normal" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\buttons\button_close_normal.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="button_login_active" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\buttons\button_login_active.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="button_login_down" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\buttons\button_login_down.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="button_login_normal" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\buttons\button_login_normal.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="button_minimize_active" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\buttons\button_minimize_active.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="button_minimize_down" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\buttons\button_minimize_down.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="button_minimize_normal" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\buttons\button_minimize_normal.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="button_register_active" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\buttons\button_register_active.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="button_register_down" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\buttons\button_register_down.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="button_register_normal" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\buttons\button_register_normal.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="ChangePwwnd_button_email_active" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\buttons\ChangePwwnd.button.email.active.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="ChangePwwnd_button_email_down" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\buttons\ChangePwwnd.button.email.down.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="ChangePwwnd_button_email_normal" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\buttons\ChangePwwnd.button.email.normal.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="character_select_cut_angela" type="System.Resources.ResXFileRef, System.Windows.Forms"> <data name="character_select_cut_angela" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\bg\character_select_cut_angela.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> <value>..\Resources\bg\character_select_cut_angela.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data> </data>
@ -193,82 +145,4 @@
<data name="character_select_cut_tude" type="System.Resources.ResXFileRef, System.Windows.Forms"> <data name="character_select_cut_tude" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\bg\character_select_cut_tude.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> <value>..\Resources\bg\character_select_cut_tude.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data> </data>
<data name="help_panel_bkg" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\bg\help_panel_bkg.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="launchbutton_bkg_active" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\buttons\launchbutton_bkg_active.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="launchbutton_bkg_down" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\buttons\launchbutton_bkg_down.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="launchbutton_bkg_normal" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\buttons\launchbutton_bkg_normal.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="launcher_bg" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\bg\launcher_bg.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="launchoptionbutton_active" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\buttons\launchoptionbutton_active.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="launchoptionbutton_down" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\buttons\launchoptionbutton_down.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="launchoptionbutton_normal" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\buttons\launchoptionbutton_normal.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="list_button_hover" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\buttons\list_button_hover.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="list_button_normal" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\buttons\list_button_normal.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="login_bg" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\bg\login_bg.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="menubutton_bkg_active" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\buttons\menubutton_bkg_active.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="menubutton_bkg_down" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\buttons\menubutton_bkg_down.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="menubutton_bkg_normal" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\buttons\menubutton_bkg_normal.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="messagewnd_button_ok_active" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\buttons\messagewnd.button.ok.active.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="messagewnd_button_ok_down" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\buttons\messagewnd.button.ok.down.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="messagewnd_button_ok_normal" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\buttons\messagewnd.button.ok.normal.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="message_bkg" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\bg\message_bkg.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="Registerwndwnd_button_sendemail_active" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\buttons\Registerwndwnd.button.sendemail.active.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="Registerwndwnd_button_sendemail_down" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\buttons\Registerwndwnd.button.sendemail.down.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="Registerwndwnd_button_sendemail_normal" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\buttons\Registerwndwnd.button.sendemail.normal.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="Registerwnd_button_continue_active" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\buttons\Registerwnd.button.continue.active.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="Registerwnd_button_continue_down" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\buttons\Registerwnd.button.continue.down.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="Registerwnd_button_continue_normal" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\buttons\Registerwnd.button.continue.normal.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="tips_error" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\icons\tips_error.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="tips_ok" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\icons\tips_ok.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
</root> </root>

View file

@ -1,26 +0,0 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 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.
// </auto-generated>
//------------------------------------------------------------------------------
namespace RHLauncher.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.5.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;
}
}
}
}

View file

@ -1,6 +0,0 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
</SettingsFile>

View file

@ -10,22 +10,26 @@
## Introduction ## Introduction
Rusty Hearts Launcher is a custom launcher for the Rusty Hearts game client. It provides several features, including self-updating, automatic game updates, account registration, and a news window. Rusty Hearts Launcher is a custom launcher for the Rusty Hearts game client. It provides several features, including self-updating, automatic game updates, account registration, and a news window.
## Preview
![image](screenshoots/preview-01.png)
![image](screenshoots/preview-02.png)
![image](screenshoots/preview-03.png)
![image](screenshoots/preview-04.png)
![image](screenshoots/preview-ko.png)
## Table of Contents ## Table of Contents
* [Features](#features) * [Features](#features)
* [Setup](#setup) * [Setup](#setup)
* [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)
* [Preview](#preview)
* [License](#license) * [License](#license)
* [Contributing](#contributing) * [Building](#building)
* [FAQ](#faq)
* [Credits](#credits) * [Credits](#credits)
* [Support](#support)
* [Roadmap](#roadmap)
## Features ## Features
* Game Download: The launcher can download and install the client.
* Game Update: The launcher can automatically download and install game updates.
* Self-updating: The launcher can automatically update itself to the latest version. * Self-updating: The launcher can automatically update itself to the latest version.
* Automatic game update: The launcher can automatically download and install updates.
* Register account: Users can register a new account/change the password directly from the launcher. * Register account: Users can register a new account/change the password directly from the launcher.
* News window: The launcher displays the latest news and updates about the game. * News window: The launcher displays the latest news and updates about the game.
@ -33,71 +37,72 @@ Rusty Hearts Launcher is a custom launcher for the Rusty Hearts game client. It
The launcher require the [Rusty Hearts API](https://github.com/JuniorDark/RustyHearts-API) to work. See the api documentation for instructions on setup. The launcher require the [Rusty Hearts API](https://github.com/JuniorDark/RustyHearts-API) to work. See the api documentation for instructions on setup.
### API URL ### API URL
In order for the launcher to work it need to be conected to the api. To change the URL address of the launcher API open the Config.ini (it will be created when opening the launcher for the first time).
In order for the launcher to work it need to be conected to the api. To change the URL address of the launcher API open the config.ini (it will be created when opening the launcher for the first time).
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 Service on config.ini The client region can be set on Config.ini or in the Config menu
* **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
### Launcher self-update ### Launcher self-update
In order for the launcher to automatically update itself, you need to use the launcher_info.ini in the `launcher_update` directory of the api. This file specifies the version of the launcher. After each update of the launcher, you need to change the version in the ini, as well in the launcher executable file. In order for the launcher to automatically update itself, you need to use the launcher_info.ini in the `launcher_update` directory of the api. This file specifies the version of the launcher. After each update of the launcher, you need to change the version in the ini, as well in the launcher executable file.
### Client patch ### Client download
In order to download the client, you need to use the `client\download` directory of the api.
The tool for creating the client files is available in the repository: https://github.com/JuniorDark/RustyHearts-MIPTool
### Client patch
In order to create client patches, you need to use the `patch` directory of the api. In order to create client patches, you need to use the `patch` directory of the api.
The tool for creating the patch files is available in the repository: https://github.com/JuniorDark/RustyHearts-MIPTool The tool for creating the patch files is available in the repository: https://github.com/JuniorDark/RustyHearts-MIPTool
### Launcher Language
The launcher language can be changed on `Lang` on Config.ini or in the Config menu
* **en** - English (en-US) default language
* **ko** - Korean ("ko-KR) (Machine Translated)
### Launcher customization ### Launcher customization
If you want to change the text on the launcher the strings can be found on LocalizedStrings.resx resource file. If you want to add a new language create a LocalizedStrings.<language>.resx with for the desired language. The english strings can be found on LocalizedStrings.resx resource file.
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 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 Building Locally/Development ## Prerequisites for Development
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. * Visual Studio 2022 (Any Edition - 17.12 or later)
* Visual Studio 2022 (Any Edition - 17.4 or later) * Windows 10 SDK or Windows 11 SDK via Visual Studio Installer
* Windows 10 SDK (10.0.19043.0) or Windows 11 SDK (10.0.22000.0) via Visual Studio Installer * .NET Core 9 SDK (9.0.100 or later)
* .NET: [.NET Core 7 SDK (7.0.100 or later)](https://dotnet.microsoft.com/en-us/download/dotnet/7.0)
## System Requirements for Ready-to-use build ## Building
* OS: Windows 10 1809 Update (build 17763) or later / Windows 11 (Any builds)
* Architecture: x64/AMD64
## Preview If you wish to build the project yourself, follow these steps:
![image](screenshoots/preview-01.png)
![image](screenshoots/preview-02.png) ### Step 1
![image](screenshoots/preview-03.png)
![image](screenshoots/preview-04.png) 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:
* [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)
## Support
If you need help with the launcher, please submit an issue on GitHub.
## Roadmap
* Add support for client download/repair
* Improve performance and stability
* Add support for additional languages

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
namespace RHLauncher namespace RHLauncher
{ {
partial class ChangePwd partial class ChangePwdForm
{ {
/// <summary> /// <summary>
/// Required designer variable. /// Required designer variable.
@ -29,7 +29,7 @@
private void InitializeComponent() private void InitializeComponent()
{ {
components = new System.ComponentModel.Container(); components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ChangePwd)); System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ChangePwdForm));
CloseButton = new Button(); CloseButton = new Button();
imageListCloseBtn = new ImageList(components); imageListCloseBtn = new ImageList(components);
MinimizeButton = new Button(); MinimizeButton = new Button();
@ -67,6 +67,9 @@
SubTitleLabelS2 = new Label(); SubTitleLabelS2 = new Label();
TitleLabelS2 = new Label(); TitleLabelS2 = new Label();
imageListTips = new ImageList(components); imageListTips = new ImageList(components);
imageListSendEmailBtn_ko = new ImageList(components);
imageListContinueBtn_ko = new ImageList(components);
imageListOKBtn_ko = new ImageList(components);
Stage1Panel.SuspendLayout(); Stage1Panel.SuspendLayout();
((System.ComponentModel.ISupportInitialize)EmailPictureBox).BeginInit(); ((System.ComponentModel.ISupportInitialize)EmailPictureBox).BeginInit();
((System.ComponentModel.ISupportInitialize)CodePictureBox).BeginInit(); ((System.ComponentModel.ISupportInitialize)CodePictureBox).BeginInit();
@ -92,9 +95,9 @@
CloseButton.TabIndex = 9; CloseButton.TabIndex = 9;
CloseButton.UseVisualStyleBackColor = false; CloseButton.UseVisualStyleBackColor = false;
CloseButton.Click += CloseButton_Click; CloseButton.Click += CloseButton_Click;
CloseButton.MouseDown += CloseButton_OnMouseDown; CloseButton.MouseDown += Button_MouseDown;
CloseButton.MouseLeave += CloseButton_MouseLeave; CloseButton.MouseLeave += Button_MouseLeave;
CloseButton.MouseHover += CloseButton_MouseHover; CloseButton.MouseHover += Button_MouseHover;
// //
// imageListCloseBtn // imageListCloseBtn
// //
@ -122,9 +125,9 @@
MinimizeButton.TabIndex = 8; MinimizeButton.TabIndex = 8;
MinimizeButton.UseVisualStyleBackColor = false; MinimizeButton.UseVisualStyleBackColor = false;
MinimizeButton.Click += MinimizeButton_Click; MinimizeButton.Click += MinimizeButton_Click;
MinimizeButton.MouseDown += MinimizeButton_OnMouseDown; MinimizeButton.MouseDown += Button_MouseDown;
MinimizeButton.MouseLeave += MinimizeButton_MouseLeave; MinimizeButton.MouseLeave += Button_MouseLeave;
MinimizeButton.MouseHover += MinimizeButton_MouseHover; MinimizeButton.MouseHover += Button_MouseHover;
// //
// imageListMinBtn // imageListMinBtn
// //
@ -177,9 +180,9 @@
ContinueButtonS1.TabIndex = 16; ContinueButtonS1.TabIndex = 16;
ContinueButtonS1.UseVisualStyleBackColor = false; ContinueButtonS1.UseVisualStyleBackColor = false;
ContinueButtonS1.Click += ContinueButtonS1_Click; ContinueButtonS1.Click += ContinueButtonS1_Click;
ContinueButtonS1.MouseDown += ContinueButtonS1_OnMouseDown; ContinueButtonS1.MouseDown += Button_MouseDown;
ContinueButtonS1.MouseLeave += ContinueButtonS1_MouseLeave; ContinueButtonS1.MouseLeave += Button_MouseLeave;
ContinueButtonS1.MouseHover += ContinueButtonS1_MouseHover; ContinueButtonS1.MouseHover += Button_MouseHover;
// //
// imageListContinueBtn // imageListContinueBtn
// //
@ -239,9 +242,9 @@
SendEmailButton.TabIndex = 21; SendEmailButton.TabIndex = 21;
SendEmailButton.UseVisualStyleBackColor = false; SendEmailButton.UseVisualStyleBackColor = false;
SendEmailButton.Click += SendEmailButton_Click; SendEmailButton.Click += SendEmailButton_Click;
SendEmailButton.MouseDown += SendEmailButton_OnMouseDown; SendEmailButton.MouseDown += Button_MouseDown;
SendEmailButton.MouseLeave += SendEmailButton_MouseLeave; SendEmailButton.MouseLeave += Button_MouseLeave;
SendEmailButton.MouseHover += SendEmailButton_MouseHover; SendEmailButton.MouseHover += Button_MouseHover;
// //
// imageListSendEmailBtn // imageListSendEmailBtn
// //
@ -503,6 +506,7 @@
ReturnLabelS2.AutoEllipsis = true; ReturnLabelS2.AutoEllipsis = true;
ReturnLabelS2.AutoSize = true; ReturnLabelS2.AutoSize = true;
ReturnLabelS2.BackColor = Color.Transparent; ReturnLabelS2.BackColor = Color.Transparent;
ReturnLabelS2.Cursor = Cursors.Hand;
ReturnLabelS2.Font = new Font("Segoe UI", 10F, FontStyle.Bold, GraphicsUnit.Point); ReturnLabelS2.Font = new Font("Segoe UI", 10F, FontStyle.Bold, GraphicsUnit.Point);
ReturnLabelS2.ForeColor = Color.Gainsboro; ReturnLabelS2.ForeColor = Color.Gainsboro;
ReturnLabelS2.ImeMode = ImeMode.NoControl; ReturnLabelS2.ImeMode = ImeMode.NoControl;
@ -513,8 +517,8 @@
ReturnLabelS2.Text = "< Return"; ReturnLabelS2.Text = "< Return";
ReturnLabelS2.TextAlign = ContentAlignment.TopCenter; ReturnLabelS2.TextAlign = ContentAlignment.TopCenter;
ReturnLabelS2.Click += ReturnLabel_Click; ReturnLabelS2.Click += ReturnLabel_Click;
ReturnLabelS2.MouseLeave += ReturnLabelS2_MouseLeave; ReturnLabelS2.MouseLeave += Label_MouseLeave;
ReturnLabelS2.MouseHover += ReturnLabelS2_MouseHover; ReturnLabelS2.MouseHover += Label_MouseHover;
// //
// OkButtonS2 // OkButtonS2
// //
@ -532,9 +536,9 @@
OkButtonS2.TabIndex = 26; OkButtonS2.TabIndex = 26;
OkButtonS2.UseVisualStyleBackColor = false; OkButtonS2.UseVisualStyleBackColor = false;
OkButtonS2.Click += OkButtonS2_Click; OkButtonS2.Click += OkButtonS2_Click;
OkButtonS2.MouseDown += OkButtonS2_OnMouseDown; OkButtonS2.MouseDown += Button_MouseDown;
OkButtonS2.MouseLeave += OkButtonS2_MouseLeave; OkButtonS2.MouseLeave += Button_MouseLeave;
OkButtonS2.MouseHover += OkButtonS2_MouseHover; OkButtonS2.MouseHover += Button_MouseHover;
// //
// PasswordTextBox // PasswordTextBox
// //
@ -594,12 +598,39 @@
imageListTips.Images.SetKeyName(0, "tips_error.png"); imageListTips.Images.SetKeyName(0, "tips_error.png");
imageListTips.Images.SetKeyName(1, "tips_ok.png"); imageListTips.Images.SetKeyName(1, "tips_ok.png");
// //
// ChangePwd // imageListSendEmailBtn_ko
//
imageListSendEmailBtn_ko.ColorDepth = ColorDepth.Depth32Bit;
imageListSendEmailBtn_ko.ImageStream = (ImageListStreamer)resources.GetObject("imageListSendEmailBtn_ko.ImageStream");
imageListSendEmailBtn_ko.TransparentColor = Color.Transparent;
imageListSendEmailBtn_ko.Images.SetKeyName(0, "ChangePwwnd_button_email_normal_ko.png");
imageListSendEmailBtn_ko.Images.SetKeyName(1, "ChangePwwnd_button_email_active_ko.png");
imageListSendEmailBtn_ko.Images.SetKeyName(2, "ChangePwwnd_button_email_down_ko.png");
//
// imageListContinueBtn_ko
//
imageListContinueBtn_ko.ColorDepth = ColorDepth.Depth32Bit;
imageListContinueBtn_ko.ImageStream = (ImageListStreamer)resources.GetObject("imageListContinueBtn_ko.ImageStream");
imageListContinueBtn_ko.TransparentColor = Color.Transparent;
imageListContinueBtn_ko.Images.SetKeyName(0, "Registerwnd_button_continue_normal_ko.png");
imageListContinueBtn_ko.Images.SetKeyName(1, "Registerwnd_button_continue_active_ko.png");
imageListContinueBtn_ko.Images.SetKeyName(2, "Registerwnd_button_continue_down_ko.png");
//
// imageListOKBtn_ko
//
imageListOKBtn_ko.ColorDepth = ColorDepth.Depth32Bit;
imageListOKBtn_ko.ImageStream = (ImageListStreamer)resources.GetObject("imageListOKBtn_ko.ImageStream");
imageListOKBtn_ko.TransparentColor = Color.Transparent;
imageListOKBtn_ko.Images.SetKeyName(0, "messagewnd.button.ok.normal.png");
imageListOKBtn_ko.Images.SetKeyName(1, "messagewnd.button.ok.active.png");
imageListOKBtn_ko.Images.SetKeyName(2, "messagewnd.button.ok.down.png");
//
// ChangePwdForm
// //
AutoScaleDimensions = new SizeF(7F, 15F); AutoScaleDimensions = new SizeF(7F, 15F);
AutoScaleMode = AutoScaleMode.Font; AutoScaleMode = AutoScaleMode.Font;
BackColor = Color.Black; BackColor = Color.Black;
BackgroundImage = Properties.Resources.bg; BackgroundImage = (Image)resources.GetObject("$this.BackgroundImage");
BackgroundImageLayout = ImageLayout.Center; BackgroundImageLayout = ImageLayout.Center;
ClientSize = new Size(800, 571); ClientSize = new Size(800, 571);
Controls.Add(CloseButton); Controls.Add(CloseButton);
@ -609,7 +640,7 @@
DoubleBuffered = true; DoubleBuffered = true;
FormBorderStyle = FormBorderStyle.None; FormBorderStyle = FormBorderStyle.None;
Icon = (Icon)resources.GetObject("$this.Icon"); Icon = (Icon)resources.GetObject("$this.Icon");
Name = "ChangePwd"; Name = "ChangePwdForm";
StartPosition = FormStartPosition.CenterScreen; StartPosition = FormStartPosition.CenterScreen;
Text = "Change Password"; Text = "Change Password";
FormClosing += ChangePwd_FormClosing; FormClosing += ChangePwd_FormClosing;
@ -664,5 +695,8 @@
private Label TimerLabel; private Label TimerLabel;
private ImageList imageListContinueBtn; private ImageList imageListContinueBtn;
private Label PwdStrengthLabel; private Label PwdStrengthLabel;
private ImageList imageListSendEmailBtn_ko;
private ImageList imageListContinueBtn_ko;
private ImageList imageListOKBtn_ko;
} }
} }

View file

@ -1,24 +1,27 @@
using RHLauncher.Helper; using Newtonsoft.Json;
using RHLauncher.RHLauncher;
using RHLauncher.RHLauncher.Helper; using RHLauncher.RHLauncher.Helper;
using RHLauncher.RHLauncher.i8n;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
namespace RHLauncher namespace RHLauncher
{ {
public partial class ChangePwd : Form public partial class ChangePwdForm : Form
{ {
private RegistryHandler registryHandler = new(); private RegistryHandler registryHandler = new();
public string SendPasswordCodeUrl = Configuration.Default.SendPasswordCodeUrl; private readonly string SendPasswordCodeUrl = Configuration.Default.SendPasswordCodeUrl;
public string VerifyCodeUrl = Configuration.Default.VerifyCodeUrl; private readonly string VerifyCodeUrl = Configuration.Default.VerifyCodeUrl;
public string ChangePasswordUrl = Configuration.Default.ChangePasswordUrl; private readonly string ChangePasswordUrl = Configuration.Default.ChangePasswordUrl;
private readonly string Lang = Configuration.Default.Lang;
private List<Button>? buttons;
private List<ImageList>? imageLists;
private Dictionary<string, List<ImageList>>? languageImageLists;
private readonly System.Windows.Forms.Timer resendTimer = new(); private readonly System.Windows.Forms.Timer resendTimer = new();
private int secondsLeft = 60; private int secondsLeft = 60;
private readonly bool _shouldRestart; private readonly bool _shouldRestart;
public ChangePwd(bool shouldRestart = false) public ChangePwdForm(bool shouldRestart = false)
{ {
InitializeComponent(); InitializeComponent();
@ -32,7 +35,9 @@ namespace RHLauncher
resendTimer.Tick += ResendTimer_Tick; resendTimer.Tick += ResendTimer_Tick;
_shouldRestart = shouldRestart; _shouldRestart = shouldRestart;
LoadLocalizedStrings();
Text = LocalizedStrings.ChangePwdFormTitle;
TitleLabelS1.Text = LocalizedStrings.ChangePassword; TitleLabelS1.Text = LocalizedStrings.ChangePassword;
TitleLabelS2.Text = LocalizedStrings.ChangePassword; TitleLabelS2.Text = LocalizedStrings.ChangePassword;
SubTitleLabelS1.Text = LocalizedStrings.RustyHearts; SubTitleLabelS1.Text = LocalizedStrings.RustyHearts;
@ -47,104 +52,158 @@ namespace RHLauncher
} }
private void LoadLocalizedStrings()
{
// Initialize buttons and image lists
buttons = [ContinueButtonS1, SendEmailButton, OkButtonS2];
imageLists = [imageListContinueBtn, imageListSendEmailBtn, imageListOKBtn];
// Initialize language-specific image lists
languageImageLists = new Dictionary<string, List<ImageList>>
{
{ "en", new List<ImageList> { imageListContinueBtn, imageListSendEmailBtn, imageListOKBtn } }, // English image lists
{ "ko", new List<ImageList> { imageListContinueBtn_ko, imageListSendEmailBtn_ko, imageListOKBtn_ko } }, // Korean image lists
// Add other languages and their respective image lists here
};
// Load the appropriate resource file based on the selected language
LocalizationHelper.LoadLocalizedStrings(Lang, buttons, imageLists, languageImageLists);
}
#region Form Events
private void ChangePwd_Load(object sender, EventArgs e)
{
ContinueButtonS1.Enabled = false;
}
private void ChangePwd_FormClosing(object sender, FormClosingEventArgs e)
{
resendTimer.Dispose();
if (sender is ChangePwdForm changePwd)
{
changePwd.Dispose();
}
}
#endregion
#region Methods #region Methods
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(new[] using HttpResponseMessage response = await client.PostAsync(SendPasswordCodeUrl, new FormUrlEncodedContent(
{ [
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)
{ {
switch (response) Invoke((MethodInvoker)(() =>
{ {
case "EmailSent": try
SendEmailButton.Enabled = false; {
resendTimer.Start(); HttpResponse? httpResponse = JsonConvert.DeserializeObject<HttpResponse>(response);
break;
case "ValidVerificationCode": if (httpResponse == null)
// Hide the firs panel and show the second panel {
Stage1Panel.Visible = false; MsgBoxForm.Show(LocalizedStrings.Error + $": {LocalizedStrings.HttpResponseNull}", LocalizedStrings.Error);
Stage2Panel.Visible = true; return;
EmailLabelS2.Text = EmailTextBox.Text; }
CodeDescLabel.Text = "";
CodePictureBox.Image = imageListTips.Images[1]; switch (httpResponse.Result)
break; {
case "PasswordChanged": case "EmailSent":
MsgBoxForm.Show(LocalizedStrings.PasswordChanged, LocalizedStrings.Success); SendEmailButton.Enabled = false;
OnPasswordChanged(); resendTimer.Start();
break; break;
case "SamePassword": case "ValidVerificationCode":
MsgBoxForm.Show(LocalizedStrings.SamePassword, LocalizedStrings.Failed); Stage1Panel.Visible = false;
break; Stage2Panel.Visible = true;
case "AccountNotFound": EmailLabelS2.Text = EmailTextBox.Text;
EmailDescLabel.Text = LocalizedStrings.AccountNotFound; CodeDescLabel.Text = "";
EmailDescLabel.ForeColor = Color.Red; CodePictureBox.Image = imageListTips.Images[1];
EmailPictureBox.Image = imageListTips.Images[0]; break;
return; case "PasswordChanged":
case "InvalidVerificationCode": MsgBoxForm.Show(LocalizedStrings.PasswordChanged, LocalizedStrings.Success);
CodeDescLabel.Text = LocalizedStrings.InvalidVerificationCode; OnPasswordChanged();
CodeDescLabel.ForeColor = Color.Red; break;
CodePictureBox.Image = imageListTips.Images[0]; case "SamePassword":
return; MsgBoxForm.Show(LocalizedStrings.SamePassword, LocalizedStrings.Failed);
case "ExpiredVerificationCode": break;
CodeDescLabel.Text = LocalizedStrings.ExpiredVerificationCode; case "AccountNotFound":
CodeDescLabel.ForeColor = Color.Red; EmailDescLabel.Text = LocalizedStrings.AccountNotFound;
CodePictureBox.Image = imageListTips.Images[0]; EmailDescLabel.ForeColor = Color.Red;
return; EmailPictureBox.Image = imageListTips.Images[0];
default: break;
MsgBoxForm.Show("Error:" + response, LocalizedStrings.Error); case "InvalidVerificationCode":
break; 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);
}
}));
} }
private void ResendTimer_Tick(object? sender, EventArgs e) private void ResendTimer_Tick(object? sender, EventArgs e)
{ {
// Decrement the secondsLeft variable and update the button text // Decrement the secondsLeft variable and update the button text
secondsLeft--; secondsLeft--;
TimerLabel.Text = $"({secondsLeft})"; Invoke((MethodInvoker)(() =>
// If the timer has finished counting down, stop the timer and enable the ResendEmailButton
if (secondsLeft == 0)
{ {
resendTimer.Stop(); TimerLabel.Text = $"({secondsLeft})";
SendEmailButton.Enabled = true;
TimerLabel.Text = ""; if (secondsLeft == 0)
} {
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(new[] using HttpResponseMessage response = await client.PostAsync(VerifyCodeUrl, new FormUrlEncodedContent(
{ [
new KeyValuePair<string, string>("email", EmailTextBox.Text), new KeyValuePair<string, string>("email", EmailTextBox.Text),
new KeyValuePair<string, string>("verification_code", CodeTextBox.Text), new KeyValuePair<string, string>("verificationCode", CodeTextBox.Text),
new KeyValuePair<string, string>("verification_code_type", "Password"), new KeyValuePair<string, string>("verificationCodeType", "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(new[] using HttpResponseMessage response = await client.PostAsync(ChangePasswordUrl, new FormUrlEncodedContent(
{ [
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>("verification_code", CodeTextBox.Text), new KeyValuePair<string, string>("verificationCode", CodeTextBox.Text),
}));
]));
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync(); return await response.Content.ReadAsStringAsync();
} }
@ -155,11 +214,15 @@ namespace RHLauncher
registryHandler = new RegistryHandler(); registryHandler = new RegistryHandler();
registryHandler.ClearPassword(); registryHandler.ClearPassword();
Application.Restart(); Invoke((MethodInvoker)(() => Close()));
Task.Delay(500).ContinueWith(_ =>
{
Application.Restart();
});
} }
else else
{ {
Close(); Invoke((MethodInvoker)(() => Close()));
} }
} }
@ -192,9 +255,9 @@ namespace RHLauncher
try try
{ {
string email = EmailTextBox.Text; Regex emailRegex = RegexPatterns.EmailRegex();
string pattern = @"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$";
if (Regex.IsMatch(email, pattern)) if (emailRegex.IsMatch(EmailTextBox.Text))
{ {
// email is valid // email is valid
EmailPictureBox.Image = imageListTips.Images[1]; EmailPictureBox.Image = imageListTips.Images[1];
@ -277,7 +340,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 < 6 || password.Length > 16) if (password.Length < 8 || password.Length > 16)
{ {
PwdDescLabel.Text = LocalizedStrings.PwdDescLabelSize; PwdDescLabel.Text = LocalizedStrings.PwdDescLabelSize;
PwdDescLabel.ForeColor = Color.Red; PwdDescLabel.ForeColor = Color.Red;
@ -289,8 +352,9 @@ namespace RHLauncher
} }
// Check for at least one uppercase, one lowercase letter, and one number // Check for at least one uppercase, one lowercase letter, and one number
Regex regex = new(@"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).+$"); Regex pwRegex = RegexPatterns.PWRegex();
if (!regex.IsMatch(password))
if (!pwRegex.IsMatch(password))
{ {
PwdDescLabel.Text = LocalizedStrings.PwdDescLabelCriteria; PwdDescLabel.Text = LocalizedStrings.PwdDescLabelCriteria;
PwdDescLabel.ForeColor = Color.Red; PwdDescLabel.ForeColor = Color.Red;
@ -304,8 +368,8 @@ namespace RHLauncher
} }
// Check for additional character types such as symbols // Check for additional character types such as symbols
regex = new Regex(@"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^\da-zA-Z]).+$"); Regex strongPWRegex = RegexPatterns.StrongPWRegex();
if (regex.IsMatch(password)) if (strongPWRegex.IsMatch(password))
{ {
PwdDescLabel.Text = ""; PwdDescLabel.Text = "";
PwdPictureBox.Image = imageListTips.Images[1]; PwdPictureBox.Image = imageListTips.Images[1];
@ -352,7 +416,6 @@ namespace RHLauncher
CheckFormS2Validity(); CheckFormS2Validity();
} }
private bool EmailTextBoxValid = false; private bool EmailTextBoxValid = false;
private void EmailTextBox_TextChanged(object sender, EventArgs e) private void EmailTextBox_TextChanged(object sender, EventArgs e)
{ {
@ -365,9 +428,9 @@ namespace RHLauncher
} }
try try
{ {
string email = EmailTextBox.Text; Regex emailRegex = RegexPatterns.EmailRegex();
string pattern = @"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$";
if (Regex.IsMatch(email, pattern)) if (emailRegex.IsMatch(EmailTextBox.Text))
{ {
// email is valid // email is valid
EmailPictureBox.Image = imageListTips.Images[1]; EmailPictureBox.Image = imageListTips.Images[1];
@ -465,101 +528,46 @@ namespace RHLauncher
#endregion #endregion
#region Button Events #region Button Events
private void Button_MouseHover(object sender, EventArgs e)
private void ContinueButtonS1_MouseHover(object sender, EventArgs e)
{ {
ContinueButtonS1.ImageIndex = 1; if (sender is Button button)
}
private void ContinueButtonS1_MouseLeave(object sender, EventArgs e)
{
ContinueButtonS1.ImageIndex = 0;
}
private void ContinueButtonS1_OnMouseDown(object sender, MouseEventArgs e)
{
ContinueButtonS1.ImageIndex = 2;
}
private void OkButtonS2_MouseHover(object sender, EventArgs e)
{
OkButtonS2.ImageIndex = 1;
}
private void OkButtonS2_MouseLeave(object sender, EventArgs e)
{
OkButtonS2.ImageIndex = 0;
}
private void OkButtonS2_OnMouseDown(object sender, MouseEventArgs e)
{
OkButtonS2.ImageIndex = 2;
}
private void SendEmailButton_MouseHover(object sender, EventArgs e)
{
SendEmailButton.ImageIndex = 1;
}
private void SendEmailButton_MouseLeave(object sender, EventArgs e)
{
SendEmailButton.ImageIndex = 0;
}
private void SendEmailButton_OnMouseDown(object sender, MouseEventArgs e)
{
SendEmailButton.ImageIndex = 2;
}
private void ChangePwd_FormClosing(object sender, FormClosingEventArgs e)
{
resendTimer.Dispose();
if (sender is ChangePwd changePwd)
{ {
changePwd.Dispose(); button.ImageIndex = 1;
} }
} }
private void MinimizeButton_MouseHover(object sender, EventArgs e) private void Button_MouseLeave(object sender, EventArgs e)
{ {
MinimizeButton.ImageIndex = 1; if (sender is Button button)
{
button.ImageIndex = 0;
}
} }
private void MinimizeButton_MouseLeave(object sender, EventArgs e) private void Button_MouseDown(object sender, MouseEventArgs e)
{ {
MinimizeButton.ImageIndex = 0; if (sender is Button button)
} {
private void MinimizeButton_OnMouseDown(object sender, MouseEventArgs e) button.ImageIndex = 2;
{ }
MinimizeButton.ImageIndex = 2;
} }
private void CloseButton_MouseHover(object sender, EventArgs e) private void Label_MouseHover(object sender, EventArgs e)
{ {
CloseButton.ImageIndex = 1; if (sender is Label label)
{
label.ForeColor = Color.White;
}
} }
private void CloseButton_MouseLeave(object sender, EventArgs e) private void Label_MouseLeave(object sender, EventArgs e)
{ {
CloseButton.ImageIndex = 0;
}
private void CloseButton_OnMouseDown(object sender, MouseEventArgs e)
{
CloseButton.ImageIndex = 2;
}
private void ReturnLabelS2_MouseHover(object sender, EventArgs e) if (sender is Label label)
{ {
ReturnLabelS2.ForeColor = Color.White; label.ForeColor = Color.Gainsboro;
}
} }
private void ReturnLabelS2_MouseLeave(object sender, EventArgs e)
{
ReturnLabelS2.ForeColor = Color.Gainsboro;
}
private void ChangePwd_Load(object sender, EventArgs e)
{
ContinueButtonS1.Enabled = false;
}
#endregion #endregion
} }
} }

File diff suppressed because it is too large Load diff

248
RHLauncher.Forms/ConfigForm.Designer.cs generated Normal file
View file

@ -0,0 +1,248 @@
namespace RHLauncher
{
partial class ConfigForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ConfigForm));
CloseButton = new Button();
imageListCloseBtn = new ImageList(components);
imageListOKBtn = new ImageList(components);
TitleLabel = new Label();
imageListBtn = new ImageList(components);
cbLauncherLanguage = new ComboBox();
LanguageLabel = new Label();
OkButton = new Button();
VersionLabel = new Label();
toolTip = new ToolTip(components);
ServiceLabel = new Label();
cbLauncherService = new ComboBox();
SuspendLayout();
//
// CloseButton
//
CloseButton.BackColor = Color.Transparent;
CloseButton.FlatAppearance.BorderColor = Color.Black;
CloseButton.FlatAppearance.BorderSize = 0;
CloseButton.FlatAppearance.MouseDownBackColor = Color.Transparent;
CloseButton.FlatAppearance.MouseOverBackColor = Color.Transparent;
CloseButton.FlatStyle = FlatStyle.Flat;
CloseButton.ForeColor = Color.Transparent;
CloseButton.ImageIndex = 0;
CloseButton.ImageList = imageListCloseBtn;
CloseButton.ImeMode = ImeMode.NoControl;
CloseButton.Location = new Point(607, 9);
CloseButton.Name = "CloseButton";
CloseButton.Size = new Size(32, 29);
CloseButton.TabIndex = 8;
CloseButton.UseVisualStyleBackColor = false;
CloseButton.Click += CloseButton_Click;
CloseButton.MouseDown += Button_MouseDown;
CloseButton.MouseLeave += Button_MouseLeave;
CloseButton.MouseHover += Button_MouseHover;
//
// imageListCloseBtn
//
imageListCloseBtn.ColorDepth = ColorDepth.Depth32Bit;
imageListCloseBtn.ImageStream = (ImageListStreamer)resources.GetObject("imageListCloseBtn.ImageStream");
imageListCloseBtn.TransparentColor = Color.Transparent;
imageListCloseBtn.Images.SetKeyName(0, "button_close_normal.png");
imageListCloseBtn.Images.SetKeyName(1, "button_close_active.png");
imageListCloseBtn.Images.SetKeyName(2, "button_close_down.png");
//
// imageListOKBtn
//
imageListOKBtn.ColorDepth = ColorDepth.Depth32Bit;
imageListOKBtn.ImageStream = (ImageListStreamer)resources.GetObject("imageListOKBtn.ImageStream");
imageListOKBtn.TransparentColor = Color.Transparent;
imageListOKBtn.Images.SetKeyName(0, "messagewnd.button.ok.normal.png");
imageListOKBtn.Images.SetKeyName(1, "messagewnd.button.ok.active.png");
imageListOKBtn.Images.SetKeyName(2, "messagewnd.button.ok.down.png");
//
// TitleLabel
//
TitleLabel.Anchor = AnchorStyles.None;
TitleLabel.AutoEllipsis = true;
TitleLabel.AutoSize = true;
TitleLabel.BackColor = Color.Transparent;
TitleLabel.Font = new Font("Segoe UI", 11F, FontStyle.Bold);
TitleLabel.ForeColor = Color.White;
TitleLabel.ImageAlign = ContentAlignment.TopRight;
TitleLabel.ImeMode = ImeMode.NoControl;
TitleLabel.Location = new Point(287, 18);
TitleLabel.Name = "TitleLabel";
TitleLabel.Size = new Size(66, 20);
TitleLabel.TabIndex = 10;
TitleLabel.Text = "Settings";
TitleLabel.TextAlign = ContentAlignment.MiddleCenter;
//
// imageListBtn
//
imageListBtn.ColorDepth = ColorDepth.Depth32Bit;
imageListBtn.ImageStream = (ImageListStreamer)resources.GetObject("imageListBtn.ImageStream");
imageListBtn.TransparentColor = Color.Transparent;
imageListBtn.Images.SetKeyName(0, "button_normal.png");
imageListBtn.Images.SetKeyName(1, "button_active.png");
imageListBtn.Images.SetKeyName(2, "button_down.png");
//
// cbLauncherLanguage
//
cbLauncherLanguage.DropDownStyle = ComboBoxStyle.DropDownList;
cbLauncherLanguage.FormattingEnabled = true;
cbLauncherLanguage.Items.AddRange(new object[] { "English", "한국어" });
cbLauncherLanguage.Location = new Point(254, 91);
cbLauncherLanguage.Name = "cbLauncherLanguage";
cbLauncherLanguage.Size = new Size(145, 23);
cbLauncherLanguage.TabIndex = 12;
cbLauncherLanguage.SelectedIndexChanged += CbLauncherLanguage_SelectedIndexChanged;
//
// LanguageLabel
//
LanguageLabel.Anchor = AnchorStyles.None;
LanguageLabel.AutoEllipsis = true;
LanguageLabel.AutoSize = true;
LanguageLabel.BackColor = Color.Transparent;
LanguageLabel.Font = new Font("Segoe UI", 11F, FontStyle.Bold);
LanguageLabel.ForeColor = Color.White;
LanguageLabel.ImageAlign = ContentAlignment.TopRight;
LanguageLabel.ImeMode = ImeMode.NoControl;
LanguageLabel.Location = new Point(254, 68);
LanguageLabel.Name = "LanguageLabel";
LanguageLabel.Size = new Size(145, 20);
LanguageLabel.TabIndex = 13;
LanguageLabel.Text = "Launcher Language";
LanguageLabel.TextAlign = ContentAlignment.MiddleCenter;
//
// OkButton
//
OkButton.BackColor = Color.Transparent;
OkButton.FlatAppearance.BorderSize = 0;
OkButton.FlatAppearance.MouseDownBackColor = Color.Transparent;
OkButton.FlatAppearance.MouseOverBackColor = Color.Transparent;
OkButton.FlatStyle = FlatStyle.Flat;
OkButton.ImageIndex = 0;
OkButton.ImageList = imageListOKBtn;
OkButton.ImeMode = ImeMode.NoControl;
OkButton.Location = new Point(268, 218);
OkButton.Name = "OkButton";
OkButton.Size = new Size(110, 44);
OkButton.TabIndex = 14;
OkButton.UseVisualStyleBackColor = false;
OkButton.Click += OkButton_Click;
OkButton.MouseDown += Button_MouseDown;
OkButton.MouseLeave += Button_MouseLeave;
OkButton.MouseHover += Button_MouseHover;
//
// VersionLabel
//
VersionLabel.AutoSize = true;
VersionLabel.BackColor = Color.Transparent;
VersionLabel.Cursor = Cursors.Hand;
VersionLabel.Font = new Font("Segoe UI", 10F, FontStyle.Bold);
VersionLabel.ForeColor = Color.White;
VersionLabel.Location = new Point(5, 248);
VersionLabel.Name = "VersionLabel";
VersionLabel.Size = new Size(62, 19);
VersionLabel.TabIndex = 16;
VersionLabel.Text = "Version:";
toolTip.SetToolTip(VersionLabel, "Click to open github repository");
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
//
AutoScaleDimensions = new SizeF(7F, 15F);
AutoScaleMode = AutoScaleMode.Font;
BackColor = Color.Magenta;
BackgroundImage = (Image)resources.GetObject("$this.BackgroundImage");
ClientSize = new Size(646, 272);
Controls.Add(ServiceLabel);
Controls.Add(cbLauncherService);
Controls.Add(VersionLabel);
Controls.Add(OkButton);
Controls.Add(LanguageLabel);
Controls.Add(cbLauncherLanguage);
Controls.Add(TitleLabel);
Controls.Add(CloseButton);
DoubleBuffered = true;
FormBorderStyle = FormBorderStyle.None;
Icon = (Icon)resources.GetObject("$this.Icon");
Name = "ConfigForm";
ShowInTaskbar = false;
StartPosition = FormStartPosition.CenterScreen;
Text = "Message";
TransparencyKey = Color.Magenta;
FormClosing += ConfigForm_FormClosing;
Load += ConfigForm_Load;
ResumeLayout(false);
PerformLayout();
}
#endregion
private Button CloseButton;
private ImageList imageListCloseBtn;
private ImageList imageListOKBtn;
private Label TitleLabel;
private ImageList imageListBtn;
private ComboBox cbLauncherLanguage;
private Label LanguageLabel;
private Button OkButton;
private Label VersionLabel;
private ToolTip toolTip;
private Label ServiceLabel;
private ComboBox cbLauncherService;
}
}

View file

@ -0,0 +1,257 @@
using RHLauncher.RHLauncher.i8n;
using RHLauncher.RHLauncher.Helper;
using System.Diagnostics;
using System.Text;
namespace RHLauncher
{
public partial class ConfigForm : Form
{
private readonly RegistryHandler registryHandler = new();
private readonly string? installDirectory;
private readonly string Url = "https://github.com/JuniorDark/RustyHearts-Launcher";
private bool languageChanged = false;
readonly string currentLanguageCode = Configuration.Default.Lang;
private bool serviceChanged = false;
readonly string currentService = Configuration.Default.Service;
public ConfigForm()
{
InitializeComponent();
installDirectory = registryHandler.GetInstallDirectory();
string currentVersion = GetLauncherVersion.GetVersion();
cbLauncherLanguage.SelectedItem = GetLanguageName(currentLanguageCode);
cbLauncherService.SelectedItem = GetServiceName(currentService);
VersionLabel.Text = $"{LocalizedStrings.Version}: {currentVersion}";
Text = LocalizedStrings.ConfigFormTitle;
TitleLabel.Text = LocalizedStrings.Settings;
LanguageLabel.Text = LocalizedStrings.LauncherLanguage;
ServiceLabel.Text = LocalizedStrings.Service;
}
#region Form Events
private void ConfigForm_Load(object sender, EventArgs e)
{
TitleLabel.Left = (ClientSize.Width - TitleLabel.Width) / 2;
}
private void ConfigForm_FormClosing(object sender, FormClosingEventArgs e)
{
Dispose();
}
#endregion
#region Language Methods
private void CbLauncherLanguage_SelectedIndexChanged(object sender, EventArgs e)
{
if (cbLauncherLanguage.SelectedItem is string selectedItem)
{
string selectedLanguageCode = GetLanguageCode(selectedItem);
if (selectedLanguageCode != currentLanguageCode)
{
languageChanged = true;
}
else
{
languageChanged = false;
}
}
}
private static string GetLanguageCode(string? language)
{
return language switch
{
"English" => "en",
"한국어" => "ko",
_ => "en",
};
}
private static string GetLanguageName(string code)
{
return code switch
{
"en" => "English",
"ko" => "한국어",
_ => "English",
};
}
#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
private void OkButton_Click(object sender, EventArgs e)
{
try
{
if (languageChanged || serviceChanged)
{
string? selectedService = cbLauncherService.SelectedItem?.ToString();
string serviceCode = GetServiceCode(selectedService);
if (serviceCode != null)
{
// Update the service in the INI file
Configuration.Default.Service = serviceCode;
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()));
Task.Delay(1000).ContinueWith(_ =>
{
Application.Restart();
});
}
}
}
else
{
Close();
}
}
catch (Exception ex)
{
MessageBox.Show($"{LocalizedStrings.Error}: {ex.Message}", LocalizedStrings.Error, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void VersionLabel_Click(object sender, EventArgs e)
{
Process.Start(new ProcessStartInfo { FileName = Url, UseShellExecute = true });
}
private void CloseButton_Click(object sender, EventArgs e)
{
Close();
}
#endregion
#region Button Events
private void Button_MouseHover(object sender, EventArgs e)
{
if (sender is Button button)
{
button.ImageIndex = 1;
}
}
private void Button_MouseLeave(object sender, EventArgs e)
{
if (sender is Button button)
{
button.ImageIndex = 0;
}
}
private void Button_MouseDown(object sender, MouseEventArgs e)
{
if (sender is Button button)
{
button.ImageIndex = 2;
}
}
#endregion
}
}

File diff suppressed because it is too large Load diff

View file

@ -48,8 +48,8 @@
PercentLabel = new Label(); PercentLabel = new Label();
DownloadingLabel = new Label(); DownloadingLabel = new Label();
FileNameLabel = new Label(); FileNameLabel = new Label();
progressBar1 = new ProgressBar(); progressBar = new ProgressBar();
webView21 = new Microsoft.Web.WebView2.WinForms.WebView2(); webView2 = new Microsoft.Web.WebView2.WinForms.WebView2();
LabelNews = new Label(); LabelNews = new Label();
imageListButton = new ImageList(components); imageListButton = new ImageList(components);
AccOptionsButton = new Button(); AccOptionsButton = new Button();
@ -64,12 +64,18 @@
OpenInstallDirButton = new Button(); OpenInstallDirButton = new Button();
ManageButton = new Button(); ManageButton = new Button();
CheckUpdateButton = new Button(); CheckUpdateButton = new Button();
InstallButton = new Button(); ChangeInstallLocationButton = new Button();
InstallPanel = new Panel(); InstallPanel = new Panel();
UninstallButton = new Button(); UninstallButton = new Button();
notifyIcon = new NotifyIcon(components);
LabelInstalled = new Label();
LabelLocate = new Label();
SettingsButton = new Button();
imageListGear = new ImageList(components);
toolTip = new ToolTip(components);
((System.ComponentModel.ISupportInitialize)CharPictureBox).BeginInit(); ((System.ComponentModel.ISupportInitialize)CharPictureBox).BeginInit();
getUpdatePanel.SuspendLayout(); getUpdatePanel.SuspendLayout();
((System.ComponentModel.ISupportInitialize)webView21).BeginInit(); ((System.ComponentModel.ISupportInitialize)webView2).BeginInit();
AccPanel.SuspendLayout(); AccPanel.SuspendLayout();
LaunchPanel.SuspendLayout(); LaunchPanel.SuspendLayout();
InstallPanel.SuspendLayout(); InstallPanel.SuspendLayout();
@ -93,9 +99,9 @@
CloseButton.TabIndex = 9; CloseButton.TabIndex = 9;
CloseButton.UseVisualStyleBackColor = false; CloseButton.UseVisualStyleBackColor = false;
CloseButton.Click += CloseButton_Click; CloseButton.Click += CloseButton_Click;
CloseButton.MouseDown += CloseButton_OnMouseDown; CloseButton.MouseDown += Button_MouseDown;
CloseButton.MouseLeave += CloseButton_MouseLeave; CloseButton.MouseLeave += Button_MouseLeave;
CloseButton.MouseHover += CloseButton_MouseHover; CloseButton.MouseHover += Button_MouseHover;
// //
// imageListCloseBtn // imageListCloseBtn
// //
@ -124,9 +130,9 @@
MinimizeButton.TabIndex = 8; MinimizeButton.TabIndex = 8;
MinimizeButton.UseVisualStyleBackColor = false; MinimizeButton.UseVisualStyleBackColor = false;
MinimizeButton.Click += MinimizeButton_Click; MinimizeButton.Click += MinimizeButton_Click;
MinimizeButton.MouseDown += MinimizeButton_OnMouseDown; MinimizeButton.MouseDown += Button_MouseDown;
MinimizeButton.MouseLeave += MinimizeButton_MouseLeave; MinimizeButton.MouseLeave += Button_MouseLeave;
MinimizeButton.MouseHover += MinimizeButton_MouseHover; MinimizeButton.MouseHover += Button_MouseHover;
// //
// imageListMinBtn // imageListMinBtn
// //
@ -155,9 +161,9 @@
LaunchButton.TabIndex = 10; LaunchButton.TabIndex = 10;
LaunchButton.Text = "Launch"; LaunchButton.Text = "Launch";
LaunchButton.UseVisualStyleBackColor = false; LaunchButton.UseVisualStyleBackColor = false;
LaunchButton.MouseDown += LaunchButton_OnMouseDown; LaunchButton.MouseDown += Button_MouseDown;
LaunchButton.MouseLeave += LaunchButton_MouseLeave; LaunchButton.MouseLeave += Button_MouseLeave;
LaunchButton.MouseHover += LaunchButton_MouseHover; LaunchButton.MouseHover += Button_MouseHover;
// //
// imageListLaunch // imageListLaunch
// //
@ -184,7 +190,7 @@
// CharPictureBox // CharPictureBox
// //
CharPictureBox.BackColor = Color.Transparent; CharPictureBox.BackColor = Color.Transparent;
CharPictureBox.Image = Properties.Resources.character_select_cut_roselle; CharPictureBox.Image = (Image)resources.GetObject("CharPictureBox.Image");
CharPictureBox.Location = new Point(23, 165); CharPictureBox.Location = new Point(23, 165);
CharPictureBox.Name = "CharPictureBox"; CharPictureBox.Name = "CharPictureBox";
CharPictureBox.Size = new Size(367, 497); CharPictureBox.Size = new Size(367, 497);
@ -206,7 +212,7 @@
getUpdatePanel.Controls.Add(PercentLabel); getUpdatePanel.Controls.Add(PercentLabel);
getUpdatePanel.Controls.Add(DownloadingLabel); getUpdatePanel.Controls.Add(DownloadingLabel);
getUpdatePanel.Controls.Add(FileNameLabel); getUpdatePanel.Controls.Add(FileNameLabel);
getUpdatePanel.Controls.Add(progressBar1); getUpdatePanel.Controls.Add(progressBar);
getUpdatePanel.Location = new Point(397, 570); getUpdatePanel.Location = new Point(397, 570);
getUpdatePanel.Name = "getUpdatePanel"; getUpdatePanel.Name = "getUpdatePanel";
getUpdatePanel.Size = new Size(594, 93); getUpdatePanel.Size = new Size(594, 93);
@ -230,9 +236,9 @@
StopButton.TabIndex = 28; StopButton.TabIndex = 28;
StopButton.UseVisualStyleBackColor = false; StopButton.UseVisualStyleBackColor = false;
StopButton.Click += StopButton_Click; StopButton.Click += StopButton_Click;
StopButton.MouseDown += StopButton_OnMouseDown; StopButton.MouseDown += Button_MouseDown;
StopButton.MouseLeave += StopButton_MouseLeave; StopButton.MouseLeave += Button_MouseLeave;
StopButton.MouseHover += StopButton_MouseHover; StopButton.MouseHover += Button_MouseHover;
// //
// imageListStopBtn // imageListStopBtn
// //
@ -344,24 +350,24 @@
FileNameLabel.TabIndex = 1; FileNameLabel.TabIndex = 1;
FileNameLabel.Text = "filename"; FileNameLabel.Text = "filename";
// //
// progressBar1 // progressBar
// //
progressBar1.Location = new Point(11, 38); progressBar.Location = new Point(11, 38);
progressBar1.Name = "progressBar1"; progressBar.Name = "progressBar";
progressBar1.Size = new Size(502, 23); progressBar.Size = new Size(502, 23);
progressBar1.TabIndex = 0; progressBar.TabIndex = 0;
// //
// webView21 // webView2
// //
webView21.AllowExternalDrop = true; webView2.AllowExternalDrop = true;
webView21.BackColor = Color.RoyalBlue; webView2.BackColor = Color.RoyalBlue;
webView21.CreationProperties = null; webView2.CreationProperties = null;
webView21.DefaultBackgroundColor = Color.White; webView2.DefaultBackgroundColor = Color.White;
webView21.Location = new Point(412, 101); webView2.Location = new Point(412, 101);
webView21.Name = "webView21"; webView2.Name = "webView2";
webView21.Size = new Size(475, 405); webView2.Size = new Size(475, 405);
webView21.TabIndex = 21; webView2.TabIndex = 21;
webView21.ZoomFactor = 1D; webView2.ZoomFactor = 1D;
// //
// LabelNews // LabelNews
// //
@ -402,13 +408,13 @@
AccOptionsButton.TabIndex = 23; AccOptionsButton.TabIndex = 23;
AccOptionsButton.UseVisualStyleBackColor = false; AccOptionsButton.UseVisualStyleBackColor = false;
AccOptionsButton.Click += AccOptionsButton_Click; AccOptionsButton.Click += AccOptionsButton_Click;
AccOptionsButton.MouseLeave += AccOptionsButton_MouseLeave; AccOptionsButton.MouseLeave += Button_MouseLeave;
AccOptionsButton.MouseHover += AccOptionsButton_MouseHover; AccOptionsButton.MouseHover += Button_MouseHover;
// //
// AccPanel // AccPanel
// //
AccPanel.BackColor = Color.RoyalBlue; AccPanel.BackColor = Color.RoyalBlue;
AccPanel.BackgroundImage = Properties.Resources.help_panel_bkg; AccPanel.BackgroundImage = (Image)resources.GetObject("AccPanel.BackgroundImage");
AccPanel.Controls.Add(LogoutButton); AccPanel.Controls.Add(LogoutButton);
AccPanel.Controls.Add(ChangePwdButton); AccPanel.Controls.Add(ChangePwdButton);
AccPanel.Location = new Point(969, 52); AccPanel.Location = new Point(969, 52);
@ -436,9 +442,9 @@
LogoutButton.Text = "Logout"; LogoutButton.Text = "Logout";
LogoutButton.UseVisualStyleBackColor = false; LogoutButton.UseVisualStyleBackColor = false;
LogoutButton.Click += LogoutButton_Click; LogoutButton.Click += LogoutButton_Click;
LogoutButton.MouseDown += MenuButton_MouseDown; LogoutButton.MouseDown += Button_MouseDown;
LogoutButton.MouseLeave += MenuButton_MouseLeave; LogoutButton.MouseLeave += Button_MouseLeave;
LogoutButton.MouseHover += MenuButton_MouseHover; LogoutButton.MouseHover += Button_MouseHover;
// //
// imageListMenuButton // imageListMenuButton
// //
@ -468,9 +474,9 @@
ChangePwdButton.Text = "Change Password"; ChangePwdButton.Text = "Change Password";
ChangePwdButton.UseVisualStyleBackColor = false; ChangePwdButton.UseVisualStyleBackColor = false;
ChangePwdButton.Click += ChangePwdButton_Click; ChangePwdButton.Click += ChangePwdButton_Click;
ChangePwdButton.MouseDown += MenuButton_MouseDown; ChangePwdButton.MouseDown += Button_MouseDown;
ChangePwdButton.MouseLeave += MenuButton_MouseLeave; ChangePwdButton.MouseLeave += Button_MouseLeave;
ChangePwdButton.MouseHover += MenuButton_MouseHover; ChangePwdButton.MouseHover += Button_MouseHover;
// //
// LaunchOptionsButton // LaunchOptionsButton
// //
@ -490,9 +496,9 @@
LaunchOptionsButton.TabIndex = 25; LaunchOptionsButton.TabIndex = 25;
LaunchOptionsButton.UseVisualStyleBackColor = false; LaunchOptionsButton.UseVisualStyleBackColor = false;
LaunchOptionsButton.Click += LaunchOptionsButton_Click; LaunchOptionsButton.Click += LaunchOptionsButton_Click;
LaunchOptionsButton.MouseDown += LaunchOptionsButton_OnMouseDown; LaunchOptionsButton.MouseDown += Button_MouseDown;
LaunchOptionsButton.MouseLeave += LaunchOptionsButton_MouseLeave; LaunchOptionsButton.MouseLeave += Button_MouseLeave;
LaunchOptionsButton.MouseHover += LaunchOptionsButton_MouseHover; LaunchOptionsButton.MouseHover += Button_MouseHover;
// //
// imageListLaunchOpt // imageListLaunchOpt
// //
@ -506,7 +512,7 @@
// LaunchPanel // LaunchPanel
// //
LaunchPanel.BackColor = Color.RoyalBlue; LaunchPanel.BackColor = Color.RoyalBlue;
LaunchPanel.BackgroundImage = Properties.Resources.help_panel_bkg; LaunchPanel.BackgroundImage = (Image)resources.GetObject("LaunchPanel.BackgroundImage");
LaunchPanel.Controls.Add(OpenSettingsButton); LaunchPanel.Controls.Add(OpenSettingsButton);
LaunchPanel.Controls.Add(OpenInstallDirButton); LaunchPanel.Controls.Add(OpenInstallDirButton);
LaunchPanel.Controls.Add(ManageButton); LaunchPanel.Controls.Add(ManageButton);
@ -524,7 +530,7 @@
OpenSettingsButton.FlatAppearance.MouseDownBackColor = Color.Transparent; OpenSettingsButton.FlatAppearance.MouseDownBackColor = Color.Transparent;
OpenSettingsButton.FlatAppearance.MouseOverBackColor = Color.Transparent; OpenSettingsButton.FlatAppearance.MouseOverBackColor = Color.Transparent;
OpenSettingsButton.FlatStyle = FlatStyle.Flat; OpenSettingsButton.FlatStyle = FlatStyle.Flat;
OpenSettingsButton.Font = new Font("Segoe UI", 8F, FontStyle.Bold, GraphicsUnit.Point); OpenSettingsButton.Font = new Font("Segoe UI", 7F, FontStyle.Bold, GraphicsUnit.Point);
OpenSettingsButton.ForeColor = Color.White; OpenSettingsButton.ForeColor = Color.White;
OpenSettingsButton.ImageIndex = 0; OpenSettingsButton.ImageIndex = 0;
OpenSettingsButton.ImageList = imageListMenuButton; OpenSettingsButton.ImageList = imageListMenuButton;
@ -536,9 +542,9 @@
OpenSettingsButton.Text = "Game Settings"; OpenSettingsButton.Text = "Game Settings";
OpenSettingsButton.UseVisualStyleBackColor = false; OpenSettingsButton.UseVisualStyleBackColor = false;
OpenSettingsButton.Click += OpenSettingsButton_Click; OpenSettingsButton.Click += OpenSettingsButton_Click;
OpenSettingsButton.MouseDown += MenuButton_MouseDown; OpenSettingsButton.MouseDown += Button_MouseDown;
OpenSettingsButton.MouseLeave += MenuButton_MouseLeave; OpenSettingsButton.MouseLeave += Button_MouseLeave;
OpenSettingsButton.MouseHover += MenuButton_MouseHover; OpenSettingsButton.MouseHover += Button_MouseHover;
// //
// OpenInstallDirButton // OpenInstallDirButton
// //
@ -547,7 +553,7 @@
OpenInstallDirButton.FlatAppearance.MouseDownBackColor = Color.Transparent; OpenInstallDirButton.FlatAppearance.MouseDownBackColor = Color.Transparent;
OpenInstallDirButton.FlatAppearance.MouseOverBackColor = Color.Transparent; OpenInstallDirButton.FlatAppearance.MouseOverBackColor = Color.Transparent;
OpenInstallDirButton.FlatStyle = FlatStyle.Flat; OpenInstallDirButton.FlatStyle = FlatStyle.Flat;
OpenInstallDirButton.Font = new Font("Segoe UI", 8F, FontStyle.Bold, GraphicsUnit.Point); OpenInstallDirButton.Font = new Font("Segoe UI", 7F, FontStyle.Bold, GraphicsUnit.Point);
OpenInstallDirButton.ForeColor = Color.White; OpenInstallDirButton.ForeColor = Color.White;
OpenInstallDirButton.ImageIndex = 0; OpenInstallDirButton.ImageIndex = 0;
OpenInstallDirButton.ImageList = imageListMenuButton; OpenInstallDirButton.ImageList = imageListMenuButton;
@ -556,12 +562,12 @@
OpenInstallDirButton.Name = "OpenInstallDirButton"; OpenInstallDirButton.Name = "OpenInstallDirButton";
OpenInstallDirButton.Size = new Size(118, 28); OpenInstallDirButton.Size = new Size(118, 28);
OpenInstallDirButton.TabIndex = 28; OpenInstallDirButton.TabIndex = 28;
OpenInstallDirButton.Text = "Open Install Dir"; OpenInstallDirButton.Text = "Open Install Directory";
OpenInstallDirButton.UseVisualStyleBackColor = false; OpenInstallDirButton.UseVisualStyleBackColor = false;
OpenInstallDirButton.Click += OpenInstallDirButton_Click; OpenInstallDirButton.Click += OpenInstallDirButton_Click;
OpenInstallDirButton.MouseDown += MenuButton_MouseDown; OpenInstallDirButton.MouseDown += Button_MouseDown;
OpenInstallDirButton.MouseLeave += MenuButton_MouseLeave; OpenInstallDirButton.MouseLeave += Button_MouseLeave;
OpenInstallDirButton.MouseHover += MenuButton_MouseHover; OpenInstallDirButton.MouseHover += Button_MouseHover;
// //
// ManageButton // ManageButton
// //
@ -570,7 +576,7 @@
ManageButton.FlatAppearance.MouseDownBackColor = Color.Transparent; ManageButton.FlatAppearance.MouseDownBackColor = Color.Transparent;
ManageButton.FlatAppearance.MouseOverBackColor = Color.Transparent; ManageButton.FlatAppearance.MouseOverBackColor = Color.Transparent;
ManageButton.FlatStyle = FlatStyle.Flat; ManageButton.FlatStyle = FlatStyle.Flat;
ManageButton.Font = new Font("Segoe UI", 8F, FontStyle.Bold, GraphicsUnit.Point); ManageButton.Font = new Font("Segoe UI", 7F, FontStyle.Bold, GraphicsUnit.Point);
ManageButton.ForeColor = Color.White; ManageButton.ForeColor = Color.White;
ManageButton.ImageIndex = 0; ManageButton.ImageIndex = 0;
ManageButton.ImageList = imageListMenuButton; ManageButton.ImageList = imageListMenuButton;
@ -582,9 +588,9 @@
ManageButton.Text = "< Manage"; ManageButton.Text = "< Manage";
ManageButton.UseVisualStyleBackColor = false; ManageButton.UseVisualStyleBackColor = false;
ManageButton.Click += ManageButton_Click; ManageButton.Click += ManageButton_Click;
ManageButton.MouseDown += MenuButton_MouseDown; ManageButton.MouseDown += Button_MouseDown;
ManageButton.MouseLeave += MenuButton_MouseLeave; ManageButton.MouseLeave += Button_MouseLeave;
ManageButton.MouseHover += MenuButton_MouseHover; ManageButton.MouseHover += Button_MouseHover;
// //
// CheckUpdateButton // CheckUpdateButton
// //
@ -593,7 +599,7 @@
CheckUpdateButton.FlatAppearance.MouseDownBackColor = Color.Transparent; CheckUpdateButton.FlatAppearance.MouseDownBackColor = Color.Transparent;
CheckUpdateButton.FlatAppearance.MouseOverBackColor = Color.Transparent; CheckUpdateButton.FlatAppearance.MouseOverBackColor = Color.Transparent;
CheckUpdateButton.FlatStyle = FlatStyle.Flat; CheckUpdateButton.FlatStyle = FlatStyle.Flat;
CheckUpdateButton.Font = new Font("Segoe UI", 8F, FontStyle.Bold, GraphicsUnit.Point); CheckUpdateButton.Font = new Font("Segoe UI", 7F, FontStyle.Bold, GraphicsUnit.Point);
CheckUpdateButton.ForeColor = Color.White; CheckUpdateButton.ForeColor = Color.White;
CheckUpdateButton.ImageIndex = 0; CheckUpdateButton.ImageIndex = 0;
CheckUpdateButton.ImageList = imageListMenuButton; CheckUpdateButton.ImageList = imageListMenuButton;
@ -602,42 +608,42 @@
CheckUpdateButton.Name = "CheckUpdateButton"; CheckUpdateButton.Name = "CheckUpdateButton";
CheckUpdateButton.Size = new Size(118, 28); CheckUpdateButton.Size = new Size(118, 28);
CheckUpdateButton.TabIndex = 27; CheckUpdateButton.TabIndex = 27;
CheckUpdateButton.Text = "Check Update"; CheckUpdateButton.Text = "Check for Updates";
CheckUpdateButton.UseVisualStyleBackColor = false; CheckUpdateButton.UseVisualStyleBackColor = false;
CheckUpdateButton.Click += UpdateCheckButton_Click; CheckUpdateButton.Click += UpdateCheckButton_Click;
CheckUpdateButton.MouseDown += MenuButton_MouseDown; CheckUpdateButton.MouseDown += Button_MouseDown;
CheckUpdateButton.MouseLeave += MenuButton_MouseLeave; CheckUpdateButton.MouseLeave += Button_MouseLeave;
CheckUpdateButton.MouseHover += MenuButton_MouseHover; CheckUpdateButton.MouseHover += Button_MouseHover;
// //
// InstallButton // ChangeInstallLocationButton
// //
InstallButton.BackColor = Color.Transparent; ChangeInstallLocationButton.BackColor = Color.Transparent;
InstallButton.FlatAppearance.BorderSize = 0; ChangeInstallLocationButton.FlatAppearance.BorderSize = 0;
InstallButton.FlatAppearance.MouseDownBackColor = Color.Transparent; ChangeInstallLocationButton.FlatAppearance.MouseDownBackColor = Color.Transparent;
InstallButton.FlatAppearance.MouseOverBackColor = Color.Transparent; ChangeInstallLocationButton.FlatAppearance.MouseOverBackColor = Color.Transparent;
InstallButton.FlatStyle = FlatStyle.Flat; ChangeInstallLocationButton.FlatStyle = FlatStyle.Flat;
InstallButton.Font = new Font("Microsoft Sans Serif", 8F, FontStyle.Bold, GraphicsUnit.Point); ChangeInstallLocationButton.Font = new Font("Microsoft Sans Serif", 7F, FontStyle.Bold, GraphicsUnit.Point);
InstallButton.ForeColor = Color.White; ChangeInstallLocationButton.ForeColor = Color.White;
InstallButton.ImageIndex = 0; ChangeInstallLocationButton.ImageIndex = 0;
InstallButton.ImageList = imageListMenuButton; ChangeInstallLocationButton.ImageList = imageListMenuButton;
InstallButton.ImeMode = ImeMode.NoControl; ChangeInstallLocationButton.ImeMode = ImeMode.NoControl;
InstallButton.Location = new Point(3, 2); ChangeInstallLocationButton.Location = new Point(3, 2);
InstallButton.Name = "InstallButton"; ChangeInstallLocationButton.Name = "ChangeInstallLocationButton";
InstallButton.Size = new Size(118, 28); ChangeInstallLocationButton.Size = new Size(118, 28);
InstallButton.TabIndex = 28; ChangeInstallLocationButton.TabIndex = 28;
InstallButton.Text = "Install Location"; ChangeInstallLocationButton.Text = "Install Location";
InstallButton.UseVisualStyleBackColor = false; ChangeInstallLocationButton.UseVisualStyleBackColor = false;
InstallButton.Click += InstallButton_Click; ChangeInstallLocationButton.Click += ChangeInstallLocationButton_Click;
InstallButton.MouseDown += MenuButton_MouseDown; ChangeInstallLocationButton.MouseDown += Button_MouseDown;
InstallButton.MouseLeave += MenuButton_MouseLeave; ChangeInstallLocationButton.MouseLeave += Button_MouseLeave;
InstallButton.MouseHover += MenuButton_MouseHover; ChangeInstallLocationButton.MouseHover += Button_MouseHover;
// //
// InstallPanel // InstallPanel
// //
InstallPanel.BackColor = Color.RoyalBlue; InstallPanel.BackColor = Color.RoyalBlue;
InstallPanel.BackgroundImage = Properties.Resources.help_panel_bkg; InstallPanel.BackgroundImage = (Image)resources.GetObject("InstallPanel.BackgroundImage");
InstallPanel.Controls.Add(UninstallButton); InstallPanel.Controls.Add(UninstallButton);
InstallPanel.Controls.Add(InstallButton); InstallPanel.Controls.Add(ChangeInstallLocationButton);
InstallPanel.Location = new Point(941, 469); InstallPanel.Location = new Point(941, 469);
InstallPanel.Name = "InstallPanel"; InstallPanel.Name = "InstallPanel";
InstallPanel.Size = new Size(124, 62); InstallPanel.Size = new Size(124, 62);
@ -651,7 +657,7 @@
UninstallButton.FlatAppearance.MouseDownBackColor = Color.Transparent; UninstallButton.FlatAppearance.MouseDownBackColor = Color.Transparent;
UninstallButton.FlatAppearance.MouseOverBackColor = Color.Transparent; UninstallButton.FlatAppearance.MouseOverBackColor = Color.Transparent;
UninstallButton.FlatStyle = FlatStyle.Flat; UninstallButton.FlatStyle = FlatStyle.Flat;
UninstallButton.Font = new Font("Microsoft Sans Serif", 8F, FontStyle.Bold, GraphicsUnit.Point); UninstallButton.Font = new Font("Microsoft Sans Serif", 7F, FontStyle.Bold, GraphicsUnit.Point);
UninstallButton.ForeColor = Color.Red; UninstallButton.ForeColor = Color.Red;
UninstallButton.ImageIndex = 0; UninstallButton.ImageIndex = 0;
UninstallButton.ImageList = imageListMenuButton; UninstallButton.ImageList = imageListMenuButton;
@ -663,25 +669,99 @@
UninstallButton.Text = "Uninstall"; UninstallButton.Text = "Uninstall";
UninstallButton.UseVisualStyleBackColor = false; UninstallButton.UseVisualStyleBackColor = false;
UninstallButton.Click += UninstallButton_Click; UninstallButton.Click += UninstallButton_Click;
UninstallButton.MouseDown += MenuButton_MouseDown; UninstallButton.MouseDown += Button_MouseDown;
UninstallButton.MouseLeave += MenuButton_MouseLeave; UninstallButton.MouseLeave += Button_MouseLeave;
UninstallButton.MouseHover += MenuButton_MouseHover; UninstallButton.MouseHover += Button_MouseHover;
//
// notifyIcon
//
notifyIcon.Icon = (Icon)resources.GetObject("notifyIcon.Icon");
notifyIcon.Text = "Rusty Hearts";
notifyIcon.Visible = true;
notifyIcon.MouseClick += NotifyIcon_MouseClick;
//
// LabelInstalled
//
LabelInstalled.AutoSize = true;
LabelInstalled.BackColor = Color.Transparent;
LabelInstalled.FlatStyle = FlatStyle.Flat;
LabelInstalled.Font = new Font("Segoe UI", 9F, FontStyle.Bold | FontStyle.Underline, GraphicsUnit.Point);
LabelInstalled.ForeColor = Color.FromArgb(246, 239, 247);
LabelInstalled.Location = new Point(998, 647);
LabelInstalled.MaximumSize = new Size(85, 0);
LabelInstalled.Name = "LabelInstalled";
LabelInstalled.Size = new Size(59, 15);
LabelInstalled.TabIndex = 28;
LabelInstalled.Text = "Installed?";
LabelInstalled.Visible = false;
//
// LabelLocate
//
LabelLocate.AutoSize = true;
LabelLocate.BackColor = Color.Transparent;
LabelLocate.Cursor = Cursors.Hand;
LabelLocate.FlatStyle = FlatStyle.Flat;
LabelLocate.Font = new Font("Segoe UI", 9F, FontStyle.Bold | FontStyle.Underline, GraphicsUnit.Point);
LabelLocate.ForeColor = Color.Gold;
LabelLocate.Location = new Point(1078, 647);
LabelLocate.MaximumSize = new Size(90, 0);
LabelLocate.Name = "LabelLocate";
LabelLocate.Size = new Size(80, 15);
LabelLocate.TabIndex = 29;
LabelLocate.Text = "Locate Game";
LabelLocate.Visible = false;
LabelLocate.Click += LbLocate_Click;
LabelLocate.MouseLeave += LabelLocate_MouseLeave;
LabelLocate.MouseHover += LabelLocate_MouseHover;
//
// SettingsButton
//
SettingsButton.BackColor = Color.Transparent;
SettingsButton.FlatAppearance.BorderColor = Color.Black;
SettingsButton.FlatAppearance.BorderSize = 0;
SettingsButton.FlatAppearance.MouseDownBackColor = Color.Transparent;
SettingsButton.FlatAppearance.MouseOverBackColor = Color.Transparent;
SettingsButton.FlatStyle = FlatStyle.Flat;
SettingsButton.Font = new Font("Segoe UI", 9F, FontStyle.Regular, GraphicsUnit.Point);
SettingsButton.ForeColor = Color.Transparent;
SettingsButton.ImageIndex = 0;
SettingsButton.ImageList = imageListGear;
SettingsButton.ImeMode = ImeMode.NoControl;
SettingsButton.Location = new Point(1130, 32);
SettingsButton.Name = "SettingsButton";
SettingsButton.Size = new Size(25, 26);
SettingsButton.TabIndex = 30;
SettingsButton.UseVisualStyleBackColor = false;
SettingsButton.Click += SettingsButton_Click;
SettingsButton.MouseLeave += Button_MouseLeave;
SettingsButton.MouseHover += Button_MouseHover;
//
// imageListGear
//
imageListGear.ColorDepth = ColorDepth.Depth32Bit;
imageListGear.ImageStream = (ImageListStreamer)resources.GetObject("imageListGear.ImageStream");
imageListGear.TransparentColor = Color.Transparent;
imageListGear.Images.SetKeyName(0, "gear.png");
imageListGear.Images.SetKeyName(1, "gear_hover.png");
// //
// LauncherForm // LauncherForm
// //
AutoScaleDimensions = new SizeF(7F, 15F); AutoScaleDimensions = new SizeF(7F, 15F);
AutoScaleMode = AutoScaleMode.Font; AutoScaleMode = AutoScaleMode.Font;
BackColor = Color.Magenta; BackColor = Color.Magenta;
BackgroundImage = Properties.Resources.launcher_bg; BackgroundImage = (Image)resources.GetObject("$this.BackgroundImage");
BackgroundImageLayout = ImageLayout.None; BackgroundImageLayout = ImageLayout.None;
ClientSize = new Size(1239, 700); ClientSize = new Size(1239, 700);
Controls.Add(SettingsButton);
Controls.Add(LabelLocate);
Controls.Add(LabelInstalled);
Controls.Add(InstallPanel); Controls.Add(InstallPanel);
Controls.Add(LaunchPanel); Controls.Add(LaunchPanel);
Controls.Add(LaunchOptionsButton); Controls.Add(LaunchOptionsButton);
Controls.Add(AccPanel); Controls.Add(AccPanel);
Controls.Add(AccOptionsButton); Controls.Add(AccOptionsButton);
Controls.Add(LabelNews); Controls.Add(LabelNews);
Controls.Add(webView21); Controls.Add(webView2);
Controls.Add(getUpdatePanel); Controls.Add(getUpdatePanel);
Controls.Add(CharPictureBox); Controls.Add(CharPictureBox);
Controls.Add(NameLabel); Controls.Add(NameLabel);
@ -696,12 +776,14 @@
Text = "Rusty Hearts Launcher"; Text = "Rusty Hearts Launcher";
TransparencyKey = Color.Magenta; TransparencyKey = Color.Magenta;
FormClosing += LauncherForm_FormClosing; FormClosing += LauncherForm_FormClosing;
FormClosed += LauncherForm_FormClosed;
Load += LauncherForm_Load; Load += LauncherForm_Load;
MouseDown += OnMouseDown; MouseDown += OnMouseDown;
Resize += LauncherForm_Resize;
((System.ComponentModel.ISupportInitialize)CharPictureBox).EndInit(); ((System.ComponentModel.ISupportInitialize)CharPictureBox).EndInit();
getUpdatePanel.ResumeLayout(false); getUpdatePanel.ResumeLayout(false);
getUpdatePanel.PerformLayout(); getUpdatePanel.PerformLayout();
((System.ComponentModel.ISupportInitialize)webView21).EndInit(); ((System.ComponentModel.ISupportInitialize)webView2).EndInit();
AccPanel.ResumeLayout(false); AccPanel.ResumeLayout(false);
LaunchPanel.ResumeLayout(false); LaunchPanel.ResumeLayout(false);
InstallPanel.ResumeLayout(false); InstallPanel.ResumeLayout(false);
@ -719,7 +801,7 @@
private Label NameLabel; private Label NameLabel;
private PictureBox CharPictureBox; private PictureBox CharPictureBox;
private Panel getUpdatePanel; private Panel getUpdatePanel;
private ProgressBar progressBar1; private ProgressBar progressBar;
private Label FileSizeLabel; private Label FileSizeLabel;
private Label SpeedLabel; private Label SpeedLabel;
private Label TimeLabel; private Label TimeLabel;
@ -728,7 +810,7 @@
private Label FileNameLabel; private Label FileNameLabel;
private Button LaunchButton; private Button LaunchButton;
private Label FileCountLabel; private Label FileCountLabel;
private Microsoft.Web.WebView2.WinForms.WebView2 webView21; private Microsoft.Web.WebView2.WinForms.WebView2 webView2;
private Label LabelNews; private Label LabelNews;
private ImageList imageListButton; private ImageList imageListButton;
private Button AccOptionsButton; private Button AccOptionsButton;
@ -736,12 +818,11 @@
private Button LaunchOptionsButton; private Button LaunchOptionsButton;
private ImageList imageListLaunchOpt; private ImageList imageListLaunchOpt;
private Panel LaunchPanel; private Panel LaunchPanel;
private Label CheckUpdateLabel;
private Button CheckUpdateButton; private Button CheckUpdateButton;
private ImageList imageListMenuButton; private ImageList imageListMenuButton;
private Button LogoutButton; private Button LogoutButton;
private Button ChangePwdButton; private Button ChangePwdButton;
private Button InstallButton; private Button ChangeInstallLocationButton;
private Button ManageButton; private Button ManageButton;
private Panel InstallPanel; private Panel InstallPanel;
private Button UninstallButton; private Button UninstallButton;
@ -749,5 +830,11 @@
private Button OpenSettingsButton; private Button OpenSettingsButton;
private ImageList imageListStopBtn; private ImageList imageListStopBtn;
private Button StopButton; private Button StopButton;
private NotifyIcon notifyIcon;
private Label LabelInstalled;
private Label LabelLocate;
private Button SettingsButton;
private ImageList imageListGear;
private ToolTip toolTip;
} }
} }

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -44,10 +44,14 @@
imageListRegister = new ImageList(components); imageListRegister = new ImageList(components);
CheckBoxAutoLogin = new CheckBox(); CheckBoxAutoLogin = new CheckBox();
CheckBoxSaveUser = new CheckBox(); CheckBoxSaveUser = new CheckBox();
timer1 = new System.Windows.Forms.Timer(components); timer = new System.Windows.Forms.Timer(components);
progressBarLogin = new ProgressBar(); progressBarLogin = new ProgressBar();
ForgotPwdLabel = new Label(); ForgotPwdLabel = new Label();
VersionLabel = new Label(); VersionLabel = new Label();
imageListLogin_ko = new ImageList(components);
imageList2 = new ImageList(components);
imageListRegister_ko = new ImageList(components);
notifyIcon = new NotifyIcon(components);
SuspendLayout(); SuspendLayout();
// //
// UsernameLabel // UsernameLabel
@ -78,18 +82,18 @@
// UsernameTextBox // UsernameTextBox
// //
UsernameTextBox.Font = new Font("Microsoft Sans Serif", 9F, FontStyle.Regular, GraphicsUnit.Point); UsernameTextBox.Font = new Font("Microsoft Sans Serif", 9F, FontStyle.Regular, GraphicsUnit.Point);
UsernameTextBox.Location = new Point(612, 222); UsernameTextBox.Location = new Point(614, 222);
UsernameTextBox.Name = "UsernameTextBox"; UsernameTextBox.Name = "UsernameTextBox";
UsernameTextBox.Size = new Size(210, 21); UsernameTextBox.Size = new Size(206, 21);
UsernameTextBox.TabIndex = 2; UsernameTextBox.TabIndex = 2;
// //
// PasswordTextBox // PasswordTextBox
// //
PasswordTextBox.Font = new Font("Microsoft Sans Serif", 9F, FontStyle.Regular, GraphicsUnit.Point); PasswordTextBox.Font = new Font("Microsoft Sans Serif", 9F, FontStyle.Regular, GraphicsUnit.Point);
PasswordTextBox.Location = new Point(613, 271); PasswordTextBox.Location = new Point(614, 271);
PasswordTextBox.Name = "PasswordTextBox"; PasswordTextBox.Name = "PasswordTextBox";
PasswordTextBox.PasswordChar = '*'; PasswordTextBox.PasswordChar = '*';
PasswordTextBox.Size = new Size(210, 21); PasswordTextBox.Size = new Size(206, 21);
PasswordTextBox.TabIndex = 3; PasswordTextBox.TabIndex = 3;
// //
// MinimizeButton // MinimizeButton
@ -109,9 +113,9 @@
MinimizeButton.TabIndex = 5; MinimizeButton.TabIndex = 5;
MinimizeButton.UseVisualStyleBackColor = false; MinimizeButton.UseVisualStyleBackColor = false;
MinimizeButton.Click += MinimizeButton_Click; MinimizeButton.Click += MinimizeButton_Click;
MinimizeButton.MouseDown += MinimizeButton_OnMouseDown; MinimizeButton.MouseDown += Button_MouseDown;
MinimizeButton.MouseLeave += MinimizeButton_MouseLeave; MinimizeButton.MouseLeave += Button_MouseLeave;
MinimizeButton.MouseHover += MinimizeButton_MouseHover; MinimizeButton.MouseHover += Button_MouseHover;
// //
// imageListMinBtn // imageListMinBtn
// //
@ -148,9 +152,9 @@
CloseButton.TabIndex = 7; CloseButton.TabIndex = 7;
CloseButton.UseVisualStyleBackColor = false; CloseButton.UseVisualStyleBackColor = false;
CloseButton.Click += CloseButton_Click; CloseButton.Click += CloseButton_Click;
CloseButton.MouseDown += CloseButton_OnMouseDown; CloseButton.MouseDown += Button_MouseDown;
CloseButton.MouseLeave += CloseButton_MouseLeave; CloseButton.MouseLeave += Button_MouseLeave;
CloseButton.MouseHover += CloseButton_MouseHover; CloseButton.MouseHover += Button_MouseHover;
// //
// imageListLogin // imageListLogin
// //
@ -176,9 +180,9 @@
LoginButton.TabIndex = 8; LoginButton.TabIndex = 8;
LoginButton.UseVisualStyleBackColor = false; LoginButton.UseVisualStyleBackColor = false;
LoginButton.Click += LoginButton_Click; LoginButton.Click += LoginButton_Click;
LoginButton.MouseDown += LoginButton_OnMouseDown; LoginButton.MouseDown += Button_MouseDown;
LoginButton.MouseLeave += LoginButton_MouseLeave; LoginButton.MouseLeave += Button_MouseLeave;
LoginButton.MouseHover += LoginButton_MouseHover; LoginButton.MouseHover += Button_MouseHover;
// //
// RegisterButton // RegisterButton
// //
@ -195,9 +199,9 @@
RegisterButton.TabIndex = 9; RegisterButton.TabIndex = 9;
RegisterButton.UseVisualStyleBackColor = false; RegisterButton.UseVisualStyleBackColor = false;
RegisterButton.Click += RegisterButton_Click; RegisterButton.Click += RegisterButton_Click;
RegisterButton.MouseDown += RegisterButton_OnMouseDown; RegisterButton.MouseDown += Button_MouseDown;
RegisterButton.MouseLeave += RegisterButton_MouseLeave; RegisterButton.MouseLeave += Button_MouseLeave;
RegisterButton.MouseHover += RegisterButton_MouseHover; RegisterButton.MouseHover += Button_MouseHover;
// //
// imageListRegister // imageListRegister
// //
@ -237,15 +241,15 @@
CheckBoxSaveUser.UseVisualStyleBackColor = false; CheckBoxSaveUser.UseVisualStyleBackColor = false;
CheckBoxSaveUser.CheckedChanged += CheckBoxSaveUser_CheckedChanged; CheckBoxSaveUser.CheckedChanged += CheckBoxSaveUser_CheckedChanged;
// //
// timer1 // timer
// //
timer1.Enabled = true; timer.Enabled = true;
// //
// progressBarLogin // progressBarLogin
// //
progressBarLogin.BackColor = SystemColors.ControlDark; progressBarLogin.BackColor = SystemColors.ControlDark;
progressBarLogin.ForeColor = Color.Transparent; progressBarLogin.ForeColor = Color.Transparent;
progressBarLogin.Location = new Point(788, 369); progressBarLogin.Location = new Point(787, 369);
progressBarLogin.Name = "progressBarLogin"; progressBarLogin.Name = "progressBarLogin";
progressBarLogin.Size = new Size(24, 23); progressBarLogin.Size = new Size(24, 23);
progressBarLogin.Style = ProgressBarStyle.Continuous; progressBarLogin.Style = ProgressBarStyle.Continuous;
@ -256,6 +260,7 @@
// //
ForgotPwdLabel.AutoSize = true; ForgotPwdLabel.AutoSize = true;
ForgotPwdLabel.BackColor = Color.Transparent; ForgotPwdLabel.BackColor = Color.Transparent;
ForgotPwdLabel.Cursor = Cursors.Hand;
ForgotPwdLabel.Font = new Font("Segoe UI", 11F, FontStyle.Bold, GraphicsUnit.Point); ForgotPwdLabel.Font = new Font("Segoe UI", 11F, FontStyle.Bold, GraphicsUnit.Point);
ForgotPwdLabel.ForeColor = Color.White; ForgotPwdLabel.ForeColor = Color.White;
ForgotPwdLabel.Location = new Point(652, 410); ForgotPwdLabel.Location = new Point(652, 410);
@ -279,13 +284,47 @@
VersionLabel.TabIndex = 15; VersionLabel.TabIndex = 15;
VersionLabel.Text = "Version:"; VersionLabel.Text = "Version:";
// //
// imageListLogin_ko
//
imageListLogin_ko.ColorDepth = ColorDepth.Depth32Bit;
imageListLogin_ko.ImageStream = (ImageListStreamer)resources.GetObject("imageListLogin_ko.ImageStream");
imageListLogin_ko.TransparentColor = Color.Transparent;
imageListLogin_ko.Images.SetKeyName(0, "button_login_normal_ko.png");
imageListLogin_ko.Images.SetKeyName(1, "button_login_active_ko.png");
imageListLogin_ko.Images.SetKeyName(2, "button_login_down_ko.png");
//
// imageList2
//
imageList2.ColorDepth = ColorDepth.Depth32Bit;
imageList2.ImageStream = (ImageListStreamer)resources.GetObject("imageList2.ImageStream");
imageList2.TransparentColor = Color.Transparent;
imageList2.Images.SetKeyName(0, "button_login_normal.png");
imageList2.Images.SetKeyName(1, "button_login_active.png");
imageList2.Images.SetKeyName(2, "button_login_down.png");
//
// imageListRegister_ko
//
imageListRegister_ko.ColorDepth = ColorDepth.Depth32Bit;
imageListRegister_ko.ImageStream = (ImageListStreamer)resources.GetObject("imageListRegister_ko.ImageStream");
imageListRegister_ko.TransparentColor = Color.Transparent;
imageListRegister_ko.Images.SetKeyName(0, "button_register_normal_ko.png");
imageListRegister_ko.Images.SetKeyName(1, "button_register_active_ko.png");
imageListRegister_ko.Images.SetKeyName(2, "button_register_down_ko.png");
//
// notifyIcon
//
notifyIcon.Icon = (Icon)resources.GetObject("notifyIcon.Icon");
notifyIcon.Text = "Rusty Hearts";
notifyIcon.Visible = true;
notifyIcon.MouseClick += NotifyIcon_MouseClick;
//
// LoginForm // LoginForm
// //
AutoScaleDimensions = new SizeF(7F, 15F); AutoScaleDimensions = new SizeF(7F, 15F);
AutoScaleMode = AutoScaleMode.Font; AutoScaleMode = AutoScaleMode.Font;
AutoSize = true; AutoSize = true;
BackColor = Color.Magenta; BackColor = Color.Magenta;
BackgroundImage = Properties.Resources.login_bg; BackgroundImage = (Image)resources.GetObject("$this.BackgroundImage");
BackgroundImageLayout = ImageLayout.Stretch; BackgroundImageLayout = ImageLayout.Stretch;
ClientSize = new Size(874, 497); ClientSize = new Size(874, 497);
Controls.Add(VersionLabel); Controls.Add(VersionLabel);
@ -311,6 +350,7 @@
FormClosing += LoginForm_FormClosing; FormClosing += LoginForm_FormClosing;
Load += LoginForm_Load; Load += LoginForm_Load;
MouseDown += OnMouseDown; MouseDown += OnMouseDown;
Resize += LoginForm_Resize;
ResumeLayout(false); ResumeLayout(false);
PerformLayout(); PerformLayout();
} }
@ -331,9 +371,13 @@
private ImageList imageListRegister; private ImageList imageListRegister;
private CheckBox CheckBoxAutoLogin; private CheckBox CheckBoxAutoLogin;
private CheckBox CheckBoxSaveUser; private CheckBox CheckBoxSaveUser;
private System.Windows.Forms.Timer timer1; private System.Windows.Forms.Timer timer;
private ProgressBar progressBarLogin; private ProgressBar progressBarLogin;
private Label ForgotPwdLabel; private Label ForgotPwdLabel;
private Label VersionLabel; private Label VersionLabel;
private ImageList imageListLogin_ko;
private ImageList imageList2;
private ImageList imageListRegister_ko;
private NotifyIcon notifyIcon;
} }
} }

View file

@ -1,8 +1,7 @@
using Newtonsoft.Json; using Newtonsoft.Json;
using RHLauncher.Helper;
using RHLauncher.RHLauncher;
using RHLauncher.RHLauncher.Helper; using RHLauncher.RHLauncher.Helper;
using System.Diagnostics; using RHLauncher.RHLauncher.Http;
using RHLauncher.RHLauncher.i8n;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
namespace RHLauncher namespace RHLauncher
@ -11,26 +10,58 @@ namespace RHLauncher
{ {
private RegistryHandler registryHandler = new(); private RegistryHandler registryHandler = new();
public string windyCode = string.Empty; private string windyCode = string.Empty;
public string password = string.Empty; private string password = string.Empty;
public string LoginUrl = Configuration.Default.LoginUrl; private readonly string LoginUrl = Configuration.Default.LoginUrl;
private readonly string Lang = Configuration.Default.Lang;
private List<Button>? buttons;
private List<ImageList>? imageLists;
private Dictionary<string, List<ImageList>>? languageImageLists;
public LoginForm() public LoginForm()
{ {
InitializeComponent(); InitializeComponent();
LoadLocalizedStrings();
notifyIcon.Text = LocalizedStrings.RustyHearts;
Text = LocalizedStrings.LauncherFormTitle;
UsernameLabel.Text = LocalizedStrings.UsernameLabel; UsernameLabel.Text = LocalizedStrings.UsernameLabel;
PasswordLabel.Text = LocalizedStrings.PasswordLabel; PasswordLabel.Text = LocalizedStrings.PasswordLabel;
CheckBoxSaveUser.Text = LocalizedStrings.CheckBoxSaveUser; CheckBoxSaveUser.Text = LocalizedStrings.CheckBoxSaveUser;
CheckBoxAutoLogin.Text = LocalizedStrings.CheckBoxAutoLogin; CheckBoxAutoLogin.Text = LocalizedStrings.CheckBoxAutoLogin;
ForgotPwdLabel.Text = LocalizedStrings.ForgotPwdLabel; ForgotPwdLabel.Text = LocalizedStrings.ForgotPwdLabel;
// Adjust ForgotPwdLabel location for Korean
if (Lang == "ko")
{
ForgotPwdLabel.Location = new Point(630, 410);
}
} }
#region Methods private void LoadLocalizedStrings()
{
// Initialize buttons and image lists
buttons = [LoginButton, RegisterButton];
imageLists = [imageListLogin, imageListRegister];
// Initialize language-specific image lists
languageImageLists = new Dictionary<string, List<ImageList>>
{
{ "en", new List<ImageList> { imageListLogin, imageListRegister } }, // English image lists
{ "ko", new List<ImageList> { imageListLogin_ko, imageListRegister_ko } }, // Korean image lists
// Add other languages and their respective image lists here
};
// Load the appropriate resource file based on the selected language
LocalizationHelper.LoadLocalizedStrings(Lang, buttons, imageLists, languageImageLists);
}
#region Form Events
private async void LoginForm_Load(object sender, EventArgs e) private async void LoginForm_Load(object sender, EventArgs e)
{ {
string currentVersion = GetLauncherVersion(); string currentVersion = GetLauncherVersion.GetVersion();
VersionLabel.Text = $"{LocalizedStrings.Version}: {currentVersion}"; VersionLabel.Text = $"{LocalizedStrings.Version}: {currentVersion}";
registryHandler = new RegistryHandler(); registryHandler = new RegistryHandler();
@ -53,38 +84,40 @@ namespace RHLauncher
} }
private static async Task CheckForLauncherUpdate() private void LoginForm_FormClosing(object sender, FormClosingEventArgs e)
{ {
try notifyIcon.Visible = false;
notifyIcon?.Dispose();
if (e.CloseReason == CloseReason.UserClosing)
{ {
LauncherUpdater launcherUpdater = new(); Application.Exit();
await launcherUpdater.CheckForLauncherUpdateAsync();
}
catch (Exception ex)
{
HandleException(ex);
} }
} }
public static string GetLauncherVersion() private void LoginForm_Resize(object sender, EventArgs e)
{ {
// Get the version information of the application if (WindowState == FormWindowState.Minimized)
FileVersionInfo versionInfo = FileVersionInfo.GetVersionInfo(Application.ExecutablePath); {
notifyIcon.Visible = true;
// Extract the version number }
string version = $"{versionInfo.FileMajorPart}.{versionInfo.FileMinorPart}.{versionInfo.FileBuildPart}"; else
{
return version; notifyIcon.Visible = false;
}
} }
#endregion
#region Login Methods
private async Task Login() private async Task Login()
{ {
Regex usernameRegex = RegexPatterns.UsernameRegex();
if (string.IsNullOrEmpty(UsernameTextBox.Text)) if (string.IsNullOrEmpty(UsernameTextBox.Text))
{ {
MsgBoxForm.Show(LocalizedStrings.LoginInsertUsername, LocalizedStrings.LoginWindowTitle); MsgBoxForm.Show(LocalizedStrings.LoginInsertUsername, LocalizedStrings.LoginWindowTitle);
return; return;
} }
if (!Regex.IsMatch(UsernameTextBox.Text, @"^[A-Za-z0-9]{6,50}$|^[\w\d._%+-]+@[\w\d.-]+\.[\w]{2,}$")) if (!usernameRegex.IsMatch(UsernameTextBox.Text))
{ {
MsgBoxForm.Show(LocalizedStrings.LoginInvalidUsernameFormat, LocalizedStrings.LoginWindowTitle); MsgBoxForm.Show(LocalizedStrings.LoginInvalidUsernameFormat, LocalizedStrings.LoginWindowTitle);
return; return;
@ -138,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(new[] using HttpResponseMessage response = await client.PostAsync(LoginUrl, new FormUrlEncodedContent(
{ [
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();
} }
@ -151,36 +184,63 @@ namespace RHLauncher
{ {
try try
{ {
Dictionary<string, string>? loginResponse = JsonConvert.DeserializeObject<Dictionary<string, string>>(response); var loginResponse = JsonConvert.DeserializeObject<LoginResponse>(response);
switch (loginResponse["Result"]) if (loginResponse == null)
{
MsgBoxForm.Show(LocalizedStrings.Error + $": {LocalizedStrings.HttpResponseNull}", LocalizedStrings.Error);
return;
}
switch (loginResponse.Result)
{ {
case "LoginSuccess": case "LoginSuccess":
windyCode = loginResponse["WindyCode"]; if (!string.IsNullOrEmpty(loginResponse.WindyCode) && !string.IsNullOrEmpty(loginResponse.Token))
password = loginResponse["Token"]; {
Hide(); windyCode = loginResponse.WindyCode;
LauncherForm launcherForm = new(windyCode, password); password = loginResponse.Token;
launcherForm.ShowDialog(); 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; break;
case "InvalidCredentials": case "InvalidCredentials":
MsgBoxForm.Show(LocalizedStrings.LoginInvalidCredentials, LocalizedStrings.LoginInfoTitle);
break;
case "InvalidUsernameFormat":
MsgBoxForm.Show(LocalizedStrings.LoginInvalidUsernameFormat, LocalizedStrings.LoginInfoTitle);
break;
case "AccountNotFound": case "AccountNotFound":
MsgBoxForm.Show(LocalizedStrings.LoginInvalidCredentials, LocalizedStrings.LoginInfoTitle); MsgBoxForm.Show(LocalizedStrings.LoginInvalidCredentials, LocalizedStrings.LoginInfoTitle);
break; break;
case "Locked": case "Locked":
MsgBoxForm.Show(LocalizedStrings.LoginLocked, LocalizedStrings.LoginInfoTitle); MsgBoxForm.Show(LocalizedStrings.LoginLocked, LocalizedStrings.LoginInfoTitle);
break; break;
case "TooManyAttempts": case "TooManyAttempts":
MsgBoxForm.Show(LocalizedStrings.LoginTooManyAttempts, LocalizedStrings.LoginInfoTitle); MsgBoxForm.Show(LocalizedStrings.LoginTooManyAttempts, LocalizedStrings.LoginInfoTitle);
break; 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: default:
MsgBoxForm.Show(LocalizedStrings.Error + loginResponse["Result"], LocalizedStrings.Error); MsgBoxForm.Show(LocalizedStrings.Error + ": " + loginResponse.Result, LocalizedStrings.Error);
break; break;
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -188,15 +248,6 @@ namespace RHLauncher
} }
} }
private static void HandleException(Exception ex)
{
string errorMessage = ex.Message;
string errorLog = ex.Message + ex.StackTrace;
Exception newEx = new(errorMessage, ex);
Exception newLogEx = new(errorLog, ex);
ExceptionHandler.HandleException(newEx, newLogEx);
}
private void CheckBoxAutoLogin_CheckedChanged(object sender, EventArgs e) private void CheckBoxAutoLogin_CheckedChanged(object sender, EventArgs e)
{ {
if (CheckBoxAutoLogin.Checked) if (CheckBoxAutoLogin.Checked)
@ -226,45 +277,72 @@ namespace RHLauncher
registryHandler.SaveUser("", false); registryHandler.SaveUser("", false);
} }
} }
#endregion
private void LoginForm_FormClosing(object sender, FormClosingEventArgs e) #region Methods
private static async Task CheckForLauncherUpdate()
{ {
if (e.CloseReason == CloseReason.UserClosing) try
{ {
Application.Exit(); LauncherUpdater launcherUpdater = new();
await launcherUpdater.CheckForLauncherUpdateAsync();
}
catch (Exception ex)
{
HandleException(ex);
} }
} }
private static void HandleException(Exception ex)
{
string errorMessage = ex.Message;
string errorLog = ex.Message + ex.StackTrace;
Exception newEx = new(errorMessage, ex);
Exception newLogEx = new(errorLog, ex);
ExceptionHandler.HandleException(newEx, newLogEx);
}
#endregion #endregion
#region Button Click Events #region Button Click Events
private async void LoginButton_Click(object sender, EventArgs e) private async void LoginButton_Click(object sender, EventArgs e)
{ {
await Login(); try
}
private void OnMouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{ {
FormUtils.MoveForm(Handle); await Login();
} }
catch (Exception ex)
{
HandleException(ex);
}
} }
private void RegisterButton_Click(object sender, EventArgs e) private void RegisterButton_Click(object sender, EventArgs e)
{ {
using RegForm RegisterForm = new(); try
RegisterForm.ShowDialog(); {
using RegisterForm RegisterForm = new();
RegisterForm.ShowDialog();
}
catch (Exception ex)
{
HandleException(ex);
}
} }
private void ForgotPwdLabel_Click(object sender, EventArgs e) private void ForgotPwdLabel_Click(object sender, EventArgs e)
{ {
using ChangePwd ChangePwd = new(); try
ChangePwd.ShowDialog(); {
using ChangePwdForm ChangePwd = new();
ChangePwd.ShowDialog();
}
catch (Exception ex)
{
HandleException(ex);
}
} }
private void CloseButton_Click(object sender, EventArgs e) private void CloseButton_Click(object sender, EventArgs e)
{ {
Close(); Close();
@ -275,65 +353,48 @@ namespace RHLauncher
WindowState = FormWindowState.Minimized; WindowState = FormWindowState.Minimized;
} }
private void OnMouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
FormUtils.MoveForm(Handle);
}
}
#endregion #endregion
#region Button Events #region Button Events
private void NotifyIcon_MouseClick(object sender, MouseEventArgs e)
private void MinimizeButton_MouseHover(object sender, EventArgs e)
{ {
MinimizeButton.ImageIndex = 1; if (e.Button == MouseButtons.Left)
{
Show();
WindowState = FormWindowState.Normal;
notifyIcon.Visible = false;
}
} }
private void MinimizeButton_MouseLeave(object sender, EventArgs e) private void Button_MouseHover(object sender, EventArgs e)
{ {
MinimizeButton.ImageIndex = 0; if (sender is Button button)
} {
private void MinimizeButton_OnMouseDown(object sender, MouseEventArgs e) button.ImageIndex = 1;
{ }
MinimizeButton.ImageIndex = 2;
} }
private void CloseButton_MouseHover(object sender, EventArgs e) private void Button_MouseLeave(object sender, EventArgs e)
{ {
CloseButton.ImageIndex = 1; if (sender is Button button)
{
button.ImageIndex = 0;
}
} }
private void CloseButton_MouseLeave(object sender, EventArgs e) private void Button_MouseDown(object sender, MouseEventArgs e)
{ {
CloseButton.ImageIndex = 0; if (sender is Button button)
} {
private void CloseButton_OnMouseDown(object sender, MouseEventArgs e) button.ImageIndex = 2;
{ }
CloseButton.ImageIndex = 2;
}
private void LoginButton_MouseHover(object sender, EventArgs e)
{
LoginButton.ImageIndex = 1;
}
private void LoginButton_MouseLeave(object sender, EventArgs e)
{
LoginButton.ImageIndex = 0;
}
private void LoginButton_OnMouseDown(object sender, MouseEventArgs e)
{
LoginButton.ImageIndex = 2;
}
private void RegisterButton_MouseHover(object sender, EventArgs e)
{
RegisterButton.ImageIndex = 1;
}
private void RegisterButton_MouseLeave(object sender, EventArgs e)
{
RegisterButton.ImageIndex = 0;
}
private void RegisterButton_OnMouseDown(object sender, MouseEventArgs e)
{
RegisterButton.ImageIndex = 2;
} }
private void ForgotPwdLabel_MouseHover(object sender, EventArgs e) private void ForgotPwdLabel_MouseHover(object sender, EventArgs e)

File diff suppressed because it is too large Load diff

View file

@ -36,7 +36,7 @@
imageListOKBtn = new ImageList(components); imageListOKBtn = new ImageList(components);
TitleLabel = new Label(); TitleLabel = new Label();
TextLabel = new Label(); TextLabel = new Label();
textBox1 = new TextBox(); tbMessage = new TextBox();
YesButton = new Button(); YesButton = new Button();
imageListBtn = new ImageList(components); imageListBtn = new ImageList(components);
NoButton = new Button(); NoButton = new Button();
@ -54,15 +54,15 @@
CloseButton.ImageIndex = 0; CloseButton.ImageIndex = 0;
CloseButton.ImageList = imageListCloseBtn; CloseButton.ImageList = imageListCloseBtn;
CloseButton.ImeMode = ImeMode.NoControl; CloseButton.ImeMode = ImeMode.NoControl;
CloseButton.Location = new Point(613, 16); CloseButton.Location = new Point(607, 9);
CloseButton.Name = "CloseButton"; CloseButton.Name = "CloseButton";
CloseButton.Size = new Size(32, 29); CloseButton.Size = new Size(32, 29);
CloseButton.TabIndex = 8; CloseButton.TabIndex = 8;
CloseButton.UseVisualStyleBackColor = false; CloseButton.UseVisualStyleBackColor = false;
CloseButton.Click += CloseButton_Click; CloseButton.Click += CloseButton_Click;
CloseButton.MouseDown += CloseButton_OnMouseDown; CloseButton.MouseDown += Button_MouseDown;
CloseButton.MouseLeave += CloseButton_MouseLeave; CloseButton.MouseLeave += Button_MouseLeave;
CloseButton.MouseHover += CloseButton_MouseHover; CloseButton.MouseHover += Button_MouseHover;
// //
// imageListCloseBtn // imageListCloseBtn
// //
@ -83,15 +83,15 @@
OkButton.ImageIndex = 0; OkButton.ImageIndex = 0;
OkButton.ImageList = imageListOKBtn; OkButton.ImageList = imageListOKBtn;
OkButton.ImeMode = ImeMode.NoControl; OkButton.ImeMode = ImeMode.NoControl;
OkButton.Location = new Point(268, 234); OkButton.Location = new Point(268, 224);
OkButton.Name = "OkButton"; OkButton.Name = "OkButton";
OkButton.Size = new Size(110, 44); OkButton.Size = new Size(110, 44);
OkButton.TabIndex = 9; OkButton.TabIndex = 9;
OkButton.UseVisualStyleBackColor = false; OkButton.UseVisualStyleBackColor = false;
OkButton.Click += OkButton_Click; OkButton.Click += OkButton_Click;
OkButton.MouseDown += OkButton_OnMouseDown; OkButton.MouseDown += Button_MouseDown;
OkButton.MouseLeave += OkButton_MouseLeave; OkButton.MouseLeave += Button_MouseLeave;
OkButton.MouseHover += OkButton_MouseHover; OkButton.MouseHover += Button_MouseHover;
// //
// imageListOKBtn // imageListOKBtn
// //
@ -112,7 +112,7 @@
TitleLabel.ForeColor = Color.White; TitleLabel.ForeColor = Color.White;
TitleLabel.ImageAlign = ContentAlignment.TopRight; TitleLabel.ImageAlign = ContentAlignment.TopRight;
TitleLabel.ImeMode = ImeMode.NoControl; TitleLabel.ImeMode = ImeMode.NoControl;
TitleLabel.Location = new Point(295, 30); TitleLabel.Location = new Point(285, 20);
TitleLabel.Name = "TitleLabel"; TitleLabel.Name = "TitleLabel";
TitleLabel.Size = new Size(40, 20); TitleLabel.Size = new Size(40, 20);
TitleLabel.TabIndex = 10; TitleLabel.TabIndex = 10;
@ -128,7 +128,7 @@
TextLabel.Font = new Font("Segoe UI", 9F, FontStyle.Bold, GraphicsUnit.Point); TextLabel.Font = new Font("Segoe UI", 9F, FontStyle.Bold, GraphicsUnit.Point);
TextLabel.ForeColor = Color.White; TextLabel.ForeColor = Color.White;
TextLabel.ImeMode = ImeMode.NoControl; TextLabel.ImeMode = ImeMode.NoControl;
TextLabel.Location = new Point(39, 72); TextLabel.Location = new Point(39, 62);
TextLabel.MaximumSize = new Size(550, 0); TextLabel.MaximumSize = new Size(550, 0);
TextLabel.MinimumSize = new Size(50, 0); TextLabel.MinimumSize = new Size(50, 0);
TextLabel.Name = "TextLabel"; TextLabel.Name = "TextLabel";
@ -136,16 +136,16 @@
TextLabel.TabIndex = 11; TextLabel.TabIndex = 11;
TextLabel.Text = "Text"; TextLabel.Text = "Text";
// //
// textBox1 // tbMessage
// //
textBox1.Location = new Point(106, 99); tbMessage.Location = new Point(106, 88);
textBox1.Multiline = true; tbMessage.Multiline = true;
textBox1.Name = "textBox1"; tbMessage.Name = "tbMessage";
textBox1.ReadOnly = true; tbMessage.ReadOnly = true;
textBox1.ScrollBars = ScrollBars.Vertical; tbMessage.ScrollBars = ScrollBars.Vertical;
textBox1.Size = new Size(441, 129); tbMessage.Size = new Size(441, 129);
textBox1.TabIndex = 12; tbMessage.TabIndex = 12;
textBox1.WordWrap = false; tbMessage.WordWrap = false;
// //
// YesButton // YesButton
// //
@ -159,15 +159,16 @@
YesButton.ImageIndex = 0; YesButton.ImageIndex = 0;
YesButton.ImageList = imageListBtn; YesButton.ImageList = imageListBtn;
YesButton.ImeMode = ImeMode.NoControl; YesButton.ImeMode = ImeMode.NoControl;
YesButton.Location = new Point(164, 234); YesButton.Location = new Point(164, 224);
YesButton.Name = "YesButton"; YesButton.Name = "YesButton";
YesButton.Size = new Size(110, 44); YesButton.Size = new Size(110, 44);
YesButton.TabIndex = 13; YesButton.TabIndex = 13;
YesButton.Text = "Yes"; YesButton.Text = "Yes";
YesButton.UseVisualStyleBackColor = false; YesButton.UseVisualStyleBackColor = false;
YesButton.MouseDown += YesButton_OnMouseDown; YesButton.Click += YesButton_Click;
YesButton.MouseLeave += YesButton_MouseLeave; YesButton.MouseDown += Button_MouseDown;
YesButton.MouseHover += YesButton_MouseHover; YesButton.MouseLeave += Button_MouseLeave;
YesButton.MouseHover += Button_MouseHover;
// //
// imageListBtn // imageListBtn
// //
@ -190,27 +191,28 @@
NoButton.ImageIndex = 0; NoButton.ImageIndex = 0;
NoButton.ImageList = imageListBtn; NoButton.ImageList = imageListBtn;
NoButton.ImeMode = ImeMode.NoControl; NoButton.ImeMode = ImeMode.NoControl;
NoButton.Location = new Point(373, 234); NoButton.Location = new Point(373, 224);
NoButton.Name = "NoButton"; NoButton.Name = "NoButton";
NoButton.Size = new Size(110, 44); NoButton.Size = new Size(110, 44);
NoButton.TabIndex = 14; NoButton.TabIndex = 14;
NoButton.Text = "No"; NoButton.Text = "No";
NoButton.UseVisualStyleBackColor = false; NoButton.UseVisualStyleBackColor = false;
NoButton.MouseDown += NoButton_OnMouseDown; NoButton.Click += NoButton_Click;
NoButton.MouseLeave += NoButton_MouseLeave; NoButton.MouseDown += Button_MouseDown;
NoButton.MouseHover += NoButton_MouseHover; NoButton.MouseLeave += Button_MouseLeave;
NoButton.MouseHover += Button_MouseHover;
// //
// MsgBoxForm // MsgBoxForm
// //
AutoScaleDimensions = new SizeF(7F, 15F); AutoScaleDimensions = new SizeF(7F, 15F);
AutoScaleMode = AutoScaleMode.Font; AutoScaleMode = AutoScaleMode.Font;
BackColor = Color.Black; BackColor = Color.Magenta;
BackgroundImage = Properties.Resources.message_bkg; BackgroundImage = (Image)resources.GetObject("$this.BackgroundImage");
BackgroundImageLayout = ImageLayout.Center; BackgroundImageLayout = ImageLayout.Center;
ClientSize = new Size(666, 292); ClientSize = new Size(646, 272);
Controls.Add(NoButton); Controls.Add(NoButton);
Controls.Add(YesButton); Controls.Add(YesButton);
Controls.Add(textBox1); Controls.Add(tbMessage);
Controls.Add(TextLabel); Controls.Add(TextLabel);
Controls.Add(TitleLabel); Controls.Add(TitleLabel);
Controls.Add(OkButton); Controls.Add(OkButton);
@ -221,7 +223,7 @@
Name = "MsgBoxForm"; Name = "MsgBoxForm";
StartPosition = FormStartPosition.CenterScreen; StartPosition = FormStartPosition.CenterScreen;
Text = "Message"; Text = "Message";
TransparencyKey = Color.Black; TransparencyKey = Color.Magenta;
FormClosing += MsgBoxForm_FormClosing; FormClosing += MsgBoxForm_FormClosing;
Load += MsgBoxForm_Load; Load += MsgBoxForm_Load;
ResumeLayout(false); ResumeLayout(false);
@ -236,7 +238,7 @@
private ImageList imageListOKBtn; private ImageList imageListOKBtn;
private Label TitleLabel; private Label TitleLabel;
private Label TextLabel; private Label TextLabel;
private TextBox textBox1; private TextBox tbMessage;
private Button YesButton; private Button YesButton;
private ImageList imageListBtn; private ImageList imageListBtn;
private Button NoButton; private Button NoButton;

View file

@ -1,20 +1,36 @@
using RHLauncher.RHLauncher.Helper; 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()
{ {
InitializeComponent(); InitializeComponent();
Text = LocalizedStrings.MsgBoxFormTitle;
YesButton.Click += YesButton_Click; YesButton.Text = LocalizedStrings.Yes;
NoButton.Click += NoButton_Click; NoButton.Text = LocalizedStrings.No;
} }
#region Form Events
private void MsgBoxForm_Load(object sender, EventArgs e)
{
TitleLabel.Left = (ClientSize.Width - TitleLabel.Width) / 2;
OkButton.Left = (ClientSize.Width - OkButton.Width) / 2;
}
private void MsgBoxForm_FormClosing(object sender, FormClosingEventArgs e)
{
Dispose();
}
#endregion
#region Button Click Events
private void YesButton_Click(object sender, EventArgs e) private void YesButton_Click(object sender, EventArgs e)
{ {
DialogResult = DialogResult.Yes; DialogResult = DialogResult.Yes;
@ -27,10 +43,22 @@ namespace RHLauncher
Close(); Close();
} }
private void CloseButton_Click(object sender, EventArgs e)
{
Close();
}
private void OkButton_Click(object sender, EventArgs e)
{
Close();
}
#endregion
#region Methods
public static void Show(string message, string title) public static void Show(string message, string title)
{ {
MsgBoxForm msgBox = new(); MsgBoxForm msgBox = new();
msgBox.textBox1.Visible = false; msgBox.tbMessage.Visible = false;
msgBox.YesButton.Visible = false; msgBox.YesButton.Visible = false;
msgBox.NoButton.Visible = false; msgBox.NoButton.Visible = false;
msgBox.TextLabel.Text = message; msgBox.TextLabel.Text = message;
@ -41,11 +69,11 @@ namespace RHLauncher
public static void ShowST(string message, string title, string stacktrace) public static void ShowST(string message, string title, string stacktrace)
{ {
MsgBoxForm msgBox = new(); MsgBoxForm msgBox = new();
msgBox.textBox1.Visible = true; msgBox.tbMessage.Visible = true;
msgBox.YesButton.Visible = false; msgBox.YesButton.Visible = false;
msgBox.NoButton.Visible = false; msgBox.NoButton.Visible = false;
msgBox.TextLabel.Text = message; msgBox.TextLabel.Text = message;
msgBox.textBox1.Text = stacktrace; msgBox.tbMessage.Text = stacktrace;
msgBox.TitleLabel.Text = title; msgBox.TitleLabel.Text = title;
msgBox.ShowDialog(); msgBox.ShowDialog();
} }
@ -53,7 +81,7 @@ namespace RHLauncher
public static DialogResult ShowYN(string message, string title) public static DialogResult ShowYN(string message, string title)
{ {
MsgBoxForm msgBox = new(); MsgBoxForm msgBox = new();
msgBox.textBox1.Visible = false; msgBox.tbMessage.Visible = false;
msgBox.OkButton.Visible = false; msgBox.OkButton.Visible = false;
msgBox.YesButton.Visible = true; msgBox.YesButton.Visible = true;
msgBox.NoButton.Visible = true; msgBox.NoButton.Visible = true;
@ -63,83 +91,32 @@ namespace RHLauncher
return msgBox.DialogResult; return msgBox.DialogResult;
} }
#endregion
private void CloseButton_Click(object sender, EventArgs e) #region Button Events
private void Button_MouseHover(object sender, EventArgs e)
{ {
Close(); if (sender is Button button)
{
button.ImageIndex = 1;
}
} }
private void OkButton_Click(object sender, EventArgs e) private void Button_MouseLeave(object sender, EventArgs e)
{ {
Close(); if (sender is Button button)
{
button.ImageIndex = 0;
}
} }
private void CloseButton_MouseHover(object sender, EventArgs e) private void Button_MouseDown(object sender, MouseEventArgs e)
{ {
CloseButton.ImageIndex = 1; if (sender is Button button)
} {
button.ImageIndex = 2;
private void CloseButton_MouseLeave(object sender, EventArgs e) }
{
CloseButton.ImageIndex = 0;
}
private void CloseButton_OnMouseDown(object sender, MouseEventArgs e)
{
CloseButton.ImageIndex = 2;
}
private void OkButton_MouseHover(object sender, EventArgs e)
{
OkButton.ImageIndex = 1;
}
private void OkButton_MouseLeave(object sender, EventArgs e)
{
OkButton.ImageIndex = 0;
}
private void OkButton_OnMouseDown(object sender, MouseEventArgs e)
{
OkButton.ImageIndex = 2;
}
private void YesButton_MouseHover(object sender, EventArgs e)
{
YesButton.ImageIndex = 1;
}
private void YesButton_MouseLeave(object sender, EventArgs e)
{
YesButton.ImageIndex = 0;
}
private void YesButton_OnMouseDown(object sender, MouseEventArgs e)
{
YesButton.ImageIndex = 2;
}
private void NoButton_MouseHover(object sender, EventArgs e)
{
NoButton.ImageIndex = 1;
}
private void NoButton_MouseLeave(object sender, EventArgs e)
{
NoButton.ImageIndex = 0;
}
private void NoButton_OnMouseDown(object sender, MouseEventArgs e)
{
NoButton.ImageIndex = 2;
}
private void MsgBoxForm_Load(object sender, EventArgs e)
{
TitleLabel.Left = (ClientSize.Width - TitleLabel.Width) / 2;
OkButton.Left = (ClientSize.Width - OkButton.Width) / 2;
}
private void MsgBoxForm_FormClosing(object sender, FormClosingEventArgs e)
{
this.Dispose();
} }
#endregion
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
namespace RHLauncher namespace RHLauncher
{ {
partial class RegForm partial class RegisterForm
{ {
/// <summary> /// <summary>
/// Required designer variable. /// Required designer variable.
@ -29,7 +29,7 @@
private void InitializeComponent() private void InitializeComponent()
{ {
components = new System.ComponentModel.Container(); components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(RegForm)); System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(RegisterForm));
CloseButton = new Button(); CloseButton = new Button();
imageListCloseBtn = new ImageList(components); imageListCloseBtn = new ImageList(components);
MinimizeButton = new Button(); MinimizeButton = new Button();
@ -57,7 +57,7 @@
AgreementLabel = new Label(); AgreementLabel = new Label();
AgreeCheckBox = new CheckBox(); AgreeCheckBox = new CheckBox();
NamePictureBox = new PictureBox(); NamePictureBox = new PictureBox();
NameTextBox = new TextBox(); UsernameTextBox = new TextBox();
NameDescLabel = new Label(); NameDescLabel = new Label();
NameLabel = new Label(); NameLabel = new Label();
PwdConfirmPictureBox = new PictureBox(); PwdConfirmPictureBox = new PictureBox();
@ -73,6 +73,9 @@
TitleLabelS2 = new Label(); TitleLabelS2 = new Label();
imageListTips = new ImageList(components); imageListTips = new ImageList(components);
imageListOkBtn = new ImageList(components); imageListOkBtn = new ImageList(components);
imageListSendEmailBtn_ko = new ImageList(components);
imageListOKBtn_ko = new ImageList(components);
imageListContinueBtn_ko = new ImageList(components);
Stage1Panel.SuspendLayout(); Stage1Panel.SuspendLayout();
((System.ComponentModel.ISupportInitialize)EmailPictureBox).BeginInit(); ((System.ComponentModel.ISupportInitialize)EmailPictureBox).BeginInit();
((System.ComponentModel.ISupportInitialize)CodePictureBox).BeginInit(); ((System.ComponentModel.ISupportInitialize)CodePictureBox).BeginInit();
@ -99,9 +102,9 @@
CloseButton.TabIndex = 9; CloseButton.TabIndex = 9;
CloseButton.UseVisualStyleBackColor = false; CloseButton.UseVisualStyleBackColor = false;
CloseButton.Click += CloseButton_Click; CloseButton.Click += CloseButton_Click;
CloseButton.MouseDown += CloseButton_OnMouseDown; CloseButton.MouseDown += Button_MouseDown;
CloseButton.MouseLeave += CloseButton_MouseLeave; CloseButton.MouseLeave += Button_MouseLeave;
CloseButton.MouseHover += CloseButton_MouseHover; CloseButton.MouseHover += Button_MouseHover;
// //
// imageListCloseBtn // imageListCloseBtn
// //
@ -129,9 +132,9 @@
MinimizeButton.TabIndex = 8; MinimizeButton.TabIndex = 8;
MinimizeButton.UseVisualStyleBackColor = false; MinimizeButton.UseVisualStyleBackColor = false;
MinimizeButton.Click += MinimizeButton_Click; MinimizeButton.Click += MinimizeButton_Click;
MinimizeButton.MouseDown += MinimizeButton_OnMouseDown; MinimizeButton.MouseDown += Button_MouseDown;
MinimizeButton.MouseLeave += MinimizeButton_MouseLeave; MinimizeButton.MouseLeave += Button_MouseLeave;
MinimizeButton.MouseHover += MinimizeButton_MouseHover; MinimizeButton.MouseHover += Button_MouseHover;
// //
// imageListMinBtn // imageListMinBtn
// //
@ -183,9 +186,9 @@
ContinueButtonS1.TabIndex = 16; ContinueButtonS1.TabIndex = 16;
ContinueButtonS1.UseVisualStyleBackColor = false; ContinueButtonS1.UseVisualStyleBackColor = false;
ContinueButtonS1.Click += ContinueButtonS1_Click; ContinueButtonS1.Click += ContinueButtonS1_Click;
ContinueButtonS1.MouseDown += ContinueButtonS1_OnMouseDown; ContinueButtonS1.MouseDown += Button_MouseDown;
ContinueButtonS1.MouseLeave += ContinueButtonS1_MouseLeave; ContinueButtonS1.MouseLeave += Button_MouseLeave;
ContinueButtonS1.MouseHover += ContinueButtonS1_MouseHover; ContinueButtonS1.MouseHover += Button_MouseHover;
// //
// PasswordLabel // PasswordLabel
// //
@ -235,9 +238,9 @@
SendEmailButton.TabIndex = 21; SendEmailButton.TabIndex = 21;
SendEmailButton.UseVisualStyleBackColor = false; SendEmailButton.UseVisualStyleBackColor = false;
SendEmailButton.Click += SendEmailButton_Click; SendEmailButton.Click += SendEmailButton_Click;
SendEmailButton.MouseDown += SendEmailButton_OnMouseDown; SendEmailButton.MouseDown += Button_MouseDown;
SendEmailButton.MouseLeave += SendEmailButton_MouseLeave; SendEmailButton.MouseLeave += Button_MouseLeave;
SendEmailButton.MouseHover += SendEmailButton_MouseHover; SendEmailButton.MouseHover += Button_MouseHover;
// //
// imageListSendEmailBtn // imageListSendEmailBtn
// //
@ -400,7 +403,7 @@
Stage2Panel.Controls.Add(AgreementLabel); Stage2Panel.Controls.Add(AgreementLabel);
Stage2Panel.Controls.Add(AgreeCheckBox); Stage2Panel.Controls.Add(AgreeCheckBox);
Stage2Panel.Controls.Add(NamePictureBox); Stage2Panel.Controls.Add(NamePictureBox);
Stage2Panel.Controls.Add(NameTextBox); Stage2Panel.Controls.Add(UsernameTextBox);
Stage2Panel.Controls.Add(NameDescLabel); Stage2Panel.Controls.Add(NameDescLabel);
Stage2Panel.Controls.Add(NameLabel); Stage2Panel.Controls.Add(NameLabel);
Stage2Panel.Controls.Add(PwdConfirmPictureBox); Stage2Panel.Controls.Add(PwdConfirmPictureBox);
@ -441,6 +444,7 @@
AgreementLabel.AutoEllipsis = true; AgreementLabel.AutoEllipsis = true;
AgreementLabel.AutoSize = true; AgreementLabel.AutoSize = true;
AgreementLabel.BackColor = Color.Transparent; AgreementLabel.BackColor = Color.Transparent;
AgreementLabel.Cursor = Cursors.Hand;
AgreementLabel.Font = new Font("Segoe UI", 10F, FontStyle.Bold, GraphicsUnit.Point); AgreementLabel.Font = new Font("Segoe UI", 10F, FontStyle.Bold, GraphicsUnit.Point);
AgreementLabel.ForeColor = Color.Gainsboro; AgreementLabel.ForeColor = Color.Gainsboro;
AgreementLabel.ImeMode = ImeMode.NoControl; AgreementLabel.ImeMode = ImeMode.NoControl;
@ -451,8 +455,8 @@
AgreementLabel.Text = "\"User Agreement\""; AgreementLabel.Text = "\"User Agreement\"";
AgreementLabel.TextAlign = ContentAlignment.TopCenter; AgreementLabel.TextAlign = ContentAlignment.TopCenter;
AgreementLabel.Click += AgreementLabel_Click; AgreementLabel.Click += AgreementLabel_Click;
AgreementLabel.MouseLeave += AgreementLabel_MouseLeave; AgreementLabel.MouseLeave += Label_MouseLeave;
AgreementLabel.MouseHover += AgreementLabel_MouseHover; AgreementLabel.MouseHover += Label_MouseHover;
// //
// AgreeCheckBox // AgreeCheckBox
// //
@ -471,19 +475,19 @@
// NamePictureBox // NamePictureBox
// //
NamePictureBox.BackColor = Color.Transparent; NamePictureBox.BackColor = Color.Transparent;
NamePictureBox.Location = new Point(383, 151); NamePictureBox.Location = new Point(379, 151);
NamePictureBox.Name = "NamePictureBox"; NamePictureBox.Name = "NamePictureBox";
NamePictureBox.Size = new Size(14, 14); NamePictureBox.Size = new Size(14, 14);
NamePictureBox.TabIndex = 39; NamePictureBox.TabIndex = 39;
NamePictureBox.TabStop = false; NamePictureBox.TabStop = false;
// //
// NameTextBox // UsernameTextBox
// //
NameTextBox.Location = new Point(93, 147); UsernameTextBox.Location = new Point(93, 147);
NameTextBox.Name = "NameTextBox"; UsernameTextBox.Name = "UsernameTextBox";
NameTextBox.Size = new Size(279, 23); UsernameTextBox.Size = new Size(279, 23);
NameTextBox.TabIndex = 38; UsernameTextBox.TabIndex = 38;
NameTextBox.TextChanged += NameTextBox_TextChanged; UsernameTextBox.TextChanged += NameTextBox_TextChanged;
// //
// NameDescLabel // NameDescLabel
// //
@ -494,7 +498,7 @@
NameDescLabel.Font = new Font("Segoe UI", 8F, FontStyle.Bold, GraphicsUnit.Point); NameDescLabel.Font = new Font("Segoe UI", 8F, FontStyle.Bold, GraphicsUnit.Point);
NameDescLabel.ForeColor = Color.White; NameDescLabel.ForeColor = Color.White;
NameDescLabel.ImeMode = ImeMode.NoControl; NameDescLabel.ImeMode = ImeMode.NoControl;
NameDescLabel.Location = new Point(399, 152); NameDescLabel.Location = new Point(395, 152);
NameDescLabel.MaximumSize = new Size(250, 0); NameDescLabel.MaximumSize = new Size(250, 0);
NameDescLabel.Name = "NameDescLabel"; NameDescLabel.Name = "NameDescLabel";
NameDescLabel.Size = new Size(158, 13); NameDescLabel.Size = new Size(158, 13);
@ -584,6 +588,7 @@
ReturnLabelS2.AutoEllipsis = true; ReturnLabelS2.AutoEllipsis = true;
ReturnLabelS2.AutoSize = true; ReturnLabelS2.AutoSize = true;
ReturnLabelS2.BackColor = Color.Transparent; ReturnLabelS2.BackColor = Color.Transparent;
ReturnLabelS2.Cursor = Cursors.Hand;
ReturnLabelS2.Font = new Font("Segoe UI", 10F, FontStyle.Bold, GraphicsUnit.Point); ReturnLabelS2.Font = new Font("Segoe UI", 10F, FontStyle.Bold, GraphicsUnit.Point);
ReturnLabelS2.ForeColor = Color.Gainsboro; ReturnLabelS2.ForeColor = Color.Gainsboro;
ReturnLabelS2.ImeMode = ImeMode.NoControl; ReturnLabelS2.ImeMode = ImeMode.NoControl;
@ -594,8 +599,8 @@
ReturnLabelS2.Text = "< Return"; ReturnLabelS2.Text = "< Return";
ReturnLabelS2.TextAlign = ContentAlignment.TopCenter; ReturnLabelS2.TextAlign = ContentAlignment.TopCenter;
ReturnLabelS2.Click += ReturnLabel_Click; ReturnLabelS2.Click += ReturnLabel_Click;
ReturnLabelS2.MouseLeave += ReturnLabelS2_MouseLeave; ReturnLabelS2.MouseLeave += Label_MouseLeave;
ReturnLabelS2.MouseHover += ReturnLabelS2_MouseHover; ReturnLabelS2.MouseHover += Label_MouseHover;
// //
// ContinueButtonS2 // ContinueButtonS2
// //
@ -607,14 +612,15 @@
ContinueButtonS2.ImageIndex = 0; ContinueButtonS2.ImageIndex = 0;
ContinueButtonS2.ImageList = imageListContinueBtn; ContinueButtonS2.ImageList = imageListContinueBtn;
ContinueButtonS2.ImeMode = ImeMode.NoControl; ContinueButtonS2.ImeMode = ImeMode.NoControl;
ContinueButtonS2.Location = new Point(95, 351); ContinueButtonS2.Location = new Point(94, 351);
ContinueButtonS2.Name = "ContinueButtonS2"; ContinueButtonS2.Name = "ContinueButtonS2";
ContinueButtonS2.Size = new Size(110, 44); ContinueButtonS2.Size = new Size(110, 44);
ContinueButtonS2.TabIndex = 26; ContinueButtonS2.TabIndex = 26;
ContinueButtonS2.UseVisualStyleBackColor = false; ContinueButtonS2.UseVisualStyleBackColor = false;
ContinueButtonS2.Click += ContinueButtonS2_Click; ContinueButtonS2.Click += ContinueButtonS2_Click;
ContinueButtonS2.MouseLeave += ContinueButtonS2_MouseLeave; ContinueButtonS2.MouseDown += Button_MouseDown;
ContinueButtonS2.MouseHover += ContinueButtonS2_MouseHover; ContinueButtonS2.MouseLeave += Button_MouseLeave;
ContinueButtonS2.MouseHover += Button_MouseHover;
// //
// PasswordTextBox // PasswordTextBox
// //
@ -683,24 +689,51 @@
imageListOkBtn.Images.SetKeyName(1, "messagewnd.button.ok.active.png"); imageListOkBtn.Images.SetKeyName(1, "messagewnd.button.ok.active.png");
imageListOkBtn.Images.SetKeyName(2, "messagewnd.button.ok.down.png"); imageListOkBtn.Images.SetKeyName(2, "messagewnd.button.ok.down.png");
// //
// RegForm // imageListSendEmailBtn_ko
//
imageListSendEmailBtn_ko.ColorDepth = ColorDepth.Depth32Bit;
imageListSendEmailBtn_ko.ImageStream = (ImageListStreamer)resources.GetObject("imageListSendEmailBtn_ko.ImageStream");
imageListSendEmailBtn_ko.TransparentColor = Color.Transparent;
imageListSendEmailBtn_ko.Images.SetKeyName(0, "ChangePwwnd_button_email_normal_ko.png");
imageListSendEmailBtn_ko.Images.SetKeyName(1, "ChangePwwnd_button_email_active_ko.png");
imageListSendEmailBtn_ko.Images.SetKeyName(2, "ChangePwwnd_button_email_down_ko.png");
//
// imageListOKBtn_ko
//
imageListOKBtn_ko.ColorDepth = ColorDepth.Depth32Bit;
imageListOKBtn_ko.ImageStream = (ImageListStreamer)resources.GetObject("imageListOKBtn_ko.ImageStream");
imageListOKBtn_ko.TransparentColor = Color.Transparent;
imageListOKBtn_ko.Images.SetKeyName(0, "messagewnd.button.ok.normal.png");
imageListOKBtn_ko.Images.SetKeyName(1, "messagewnd.button.ok.active.png");
imageListOKBtn_ko.Images.SetKeyName(2, "messagewnd.button.ok.down.png");
//
// imageListContinueBtn_ko
//
imageListContinueBtn_ko.ColorDepth = ColorDepth.Depth32Bit;
imageListContinueBtn_ko.ImageStream = (ImageListStreamer)resources.GetObject("imageListContinueBtn_ko.ImageStream");
imageListContinueBtn_ko.TransparentColor = Color.Transparent;
imageListContinueBtn_ko.Images.SetKeyName(0, "Registerwnd_button_continue_normal_ko.png");
imageListContinueBtn_ko.Images.SetKeyName(1, "Registerwnd_button_continue_active_ko.png");
imageListContinueBtn_ko.Images.SetKeyName(2, "Registerwnd_button_continue_down_ko.png");
//
// RegisterForm
// //
AutoScaleDimensions = new SizeF(7F, 15F); AutoScaleDimensions = new SizeF(7F, 15F);
AutoScaleMode = AutoScaleMode.Font; AutoScaleMode = AutoScaleMode.Font;
BackColor = Color.Black; BackColor = Color.Black;
BackgroundImage = Properties.Resources.bg; BackgroundImage = (Image)resources.GetObject("$this.BackgroundImage");
BackgroundImageLayout = ImageLayout.Center; BackgroundImageLayout = ImageLayout.Center;
ClientSize = new Size(800, 571); ClientSize = new Size(800, 571);
Controls.Add(CloseButton); Controls.Add(CloseButton);
Controls.Add(MinimizeButton); Controls.Add(MinimizeButton);
Controls.Add(Stage2Panel);
Controls.Add(Stage1Panel); Controls.Add(Stage1Panel);
Controls.Add(Stage2Panel);
DoubleBuffered = true; DoubleBuffered = true;
FormBorderStyle = FormBorderStyle.None; FormBorderStyle = FormBorderStyle.None;
Icon = (Icon)resources.GetObject("$this.Icon"); Icon = (Icon)resources.GetObject("$this.Icon");
Name = "RegForm"; Name = "RegisterForm";
StartPosition = FormStartPosition.CenterScreen; StartPosition = FormStartPosition.CenterScreen;
Text = "Change Password"; Text = "Register Account";
FormClosing += RegForm_FormClosing; FormClosing += RegForm_FormClosing;
Load += RegForm_Load; Load += RegForm_Load;
Stage1Panel.ResumeLayout(false); Stage1Panel.ResumeLayout(false);
@ -754,11 +787,14 @@
private Label EmailLabel; private Label EmailLabel;
private ImageList imageListOkBtn; private ImageList imageListOkBtn;
private PictureBox NamePictureBox; private PictureBox NamePictureBox;
private TextBox NameTextBox; private TextBox UsernameTextBox;
private Label NameDescLabel; private Label NameDescLabel;
private Label NameLabel; private Label NameLabel;
private CheckBox AgreeCheckBox; private CheckBox AgreeCheckBox;
private Label AgreementLabel; private Label AgreementLabel;
private Label PwdStrengthLabel; private Label PwdStrengthLabel;
private ImageList imageListSendEmailBtn_ko;
private ImageList imageListOKBtn_ko;
private ImageList imageListContinueBtn_ko;
} }
} }

View file

@ -1,30 +1,51 @@
using RHLauncher.RHLauncher; using Newtonsoft.Json;
using RHLauncher.RHLauncher.Helper; using RHLauncher.RHLauncher.Helper;
using RHLauncher.RHLauncher.i8n;
using System.Diagnostics; using System.Diagnostics;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
namespace RHLauncher namespace RHLauncher
{ {
public partial class RegForm : Form public partial class RegisterForm : Form
{ {
public string SendCodeUrl = Configuration.Default.SendCodeUrl; private readonly string SendCodeUrl = Configuration.Default.SendCodeUrl;
public string AgreementUrl = Configuration.Default.AgreementUrl; private readonly string AgreementUrl = Configuration.Default.AgreementUrl;
public string VerifyCodeUrl = Configuration.Default.VerifyCodeUrl; private readonly string VerifyCodeUrl = Configuration.Default.VerifyCodeUrl;
public string RegisterUrl = Configuration.Default.RegisterUrl; private readonly string RegisterUrl = Configuration.Default.RegisterUrl;
private readonly string Lang = Configuration.Default.Lang;
private List<Button>? buttons;
private List<ImageList>? imageLists;
private Dictionary<string, List<ImageList>>? languageImageLists;
private readonly System.Windows.Forms.Timer resendTimer = new(); private readonly System.Windows.Forms.Timer resendTimer = new();
private int secondsLeft = 60; private int secondsLeft = 60;
[GeneratedRegex("^(?=.*[a-zA-Z])[a-zA-Z0-9]+$")] public RegisterForm()
private static partial Regex MyRegex();
public RegForm()
{ {
InitializeComponent(); InitializeComponent();
Stage1Panel.Visible = true; Stage1Panel.Visible = true;
Stage2Panel.Visible = false; Stage2Panel.Visible = false;
LoadLocalizedStrings();
Text = LocalizedStrings.ChangePwdFormTitle;
EmailLabel.Text = LocalizedStrings.AccountEmail;
TitleLabelS1.Text = LocalizedStrings.RegisterAccount;
SubTitleLabelS1.Text = LocalizedStrings.RustyHearts;
CodeLabel.Text = LocalizedStrings.VerificationCode;
TitleLabelS2.Text = LocalizedStrings.AccountDetails;
SubTitleLabelS2.Text = LocalizedStrings.Account;
NameLabel.Text = LocalizedStrings.AccountName;
PasswordLabel.Text = LocalizedStrings.EnterPassword;
RepeatPasswordLabel.Text = LocalizedStrings.RepeatPassword;
AgreeCheckBox.Text = LocalizedStrings.AgreeTerms;
AgreementLabel.Text = LocalizedStrings.UserAgreement;
NameDescLabel.Text = LocalizedStrings.UsernameDesc;
PwdDescLabel.Text = LocalizedStrings.NewPasswordDesc;
PwdConfirmDescLabel.Text = LocalizedStrings.RepeatPasswordDesc;
ReturnLabelS2.Text = LocalizedStrings.Return;
resendTimer = new System.Windows.Forms.Timer resendTimer = new System.Windows.Forms.Timer
{ {
Interval = 1000 Interval = 1000
@ -32,30 +53,70 @@ namespace RHLauncher
resendTimer.Tick += ResendTimer_Tick; resendTimer.Tick += ResendTimer_Tick;
} }
private void LoadLocalizedStrings()
{
// Initialize buttons and image lists
buttons = [ContinueButtonS1, SendEmailButton, ContinueButtonS2];
imageLists = [imageListContinueBtn, imageListSendEmailBtn, imageListContinueBtn];
// Initialize language-specific image lists
languageImageLists = new Dictionary<string, List<ImageList>>
{
{ "en", new List<ImageList> { imageListContinueBtn, imageListSendEmailBtn, imageListContinueBtn } }, // English image lists
{ "ko", new List<ImageList> { imageListContinueBtn_ko, imageListSendEmailBtn_ko, imageListContinueBtn_ko } }, // Korean image lists
// Add other languages and their respective image lists here
};
// Load the appropriate resource file based on the selected language
LocalizationHelper.LoadLocalizedStrings(Lang, buttons, imageLists, languageImageLists);
}
#region Form Events
private void RegForm_Load(object sender, EventArgs e)
{
ContinueButtonS1.Enabled = false;
}
private void RegForm_FormClosing(object sender, FormClosingEventArgs e)
{
resendTimer.Dispose();
Dispose();
}
#endregion
#region Methods #region Methods
private async Task<string> SendEmailRequestAsync() private async Task<string> SendEmailRequestAsync()
{ {
using HttpClient client = new(); using HttpClient client = new();
HttpResponseMessage response = await client.PostAsync(SendCodeUrl, new FormUrlEncodedContent(new[] using HttpResponseMessage response = await client.PostAsync(SendCodeUrl, new FormUrlEncodedContent(
{ [
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)
{ {
switch (response) HttpResponse? httpResponse = JsonConvert.DeserializeObject<HttpResponse>(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;
resendTimer.Start(); resendTimer.Start();
break; break;
case "AccountExists": case "AccountExists":
MsgBoxForm.Show("A account with this email already exists.", "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
@ -66,17 +127,17 @@ namespace RHLauncher
CodePictureBox.Image = imageListTips.Images[1]; CodePictureBox.Image = imageListTips.Images[1];
break; break;
case "InvalidVerificationCode": case "InvalidVerificationCode":
CodeDescLabel.Text = "Invalid Verification Code"; CodeDescLabel.Text = LocalizedStrings.InvalidVerificationCode;
CodeDescLabel.ForeColor = Color.Red; CodeDescLabel.ForeColor = Color.Red;
CodePictureBox.Image = imageListTips.Images[0]; CodePictureBox.Image = imageListTips.Images[0];
return; return;
case "ExpiredVerificationCode": case "ExpiredVerificationCode":
CodeDescLabel.Text = "This verification code has expired, please request a new one."; CodeDescLabel.Text = LocalizedStrings.ExpiredVerificationCode;
CodeDescLabel.ForeColor = Color.Red; CodeDescLabel.ForeColor = Color.Red;
CodePictureBox.Image = imageListTips.Images[0]; CodePictureBox.Image = imageListTips.Images[0];
return; return;
default: default:
MsgBoxForm.Show("An error occurred:" + response, "Error"); MsgBoxForm.Show($"{LocalizedStrings.Error}: {response}", LocalizedStrings.Error);
break; break;
} }
} }
@ -90,61 +151,75 @@ 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)
{ {
resendTimer.Stop(); ResetSendEmailButton();
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();
HttpResponseMessage response = await client.PostAsync(VerifyCodeUrl, new FormUrlEncodedContent(new[] using HttpResponseMessage response = await client.PostAsync(VerifyCodeUrl, new FormUrlEncodedContent(
{ [
new KeyValuePair<string, string>("email", EmailTextBox.Text), new KeyValuePair<string, string>("email", EmailTextBox.Text),
new KeyValuePair<string, string>("verification_code", CodeTextBox.Text), new KeyValuePair<string, string>("verificationCode", CodeTextBox.Text),
new KeyValuePair<string, string>("verification_code_type", "Account"), new KeyValuePair<string, string>("verificationCodeType", "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();
HttpResponseMessage response = await client.PostAsync(RegisterUrl, new FormUrlEncodedContent(new[] using HttpResponseMessage response = await client.PostAsync(RegisterUrl, new FormUrlEncodedContent(
{ [
new KeyValuePair<string, string>("windyCode", NameTextBox.Text), new KeyValuePair<string, string>("username", 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)
{ {
switch (response) HttpResponse? accounResponse = JsonConvert.DeserializeObject<HttpResponse>(response);
if (accounResponse == null)
{ {
case "Success": MsgBoxForm.Show(LocalizedStrings.Error + $": {LocalizedStrings.HttpResponseNull}", LocalizedStrings.Error);
MsgBoxForm.Show("Account created successfully.", "Register Window"); return;
}
switch (accounResponse.Result)
{
case "AccountCreated":
MsgBoxForm.Show(LocalizedStrings.AccountCreateSuccess, LocalizedStrings.RegisterWindow);
Close(); Close();
break; break;
case "AccountExists": case "EmailExists":
MsgBoxForm.Show("A account with this username already exists.", "Info"); MsgBoxForm.Show(LocalizedStrings.AccountEmailExists, LocalizedStrings.Info);
break; break;
case "WindyCodeExists": case "UsernameExists":
MsgBoxForm.Show("A game account with this username already exists.", "Error"); MsgBoxForm.Show(LocalizedStrings.WindyCodeExists, LocalizedStrings.Error);
break; break;
case "InvalidUserNameFormat": case "InvalidUserNameFormat":
MsgBoxForm.Show("Invalid username format", "Error"); MsgBoxForm.Show(LocalizedStrings.InvalidUserNameFormat, LocalizedStrings.Error);
break; break;
case "InvalidEmailFormat": case "InvalidEmailFormat":
MsgBoxForm.Show("Invalid email format", "Error"); MsgBoxForm.Show(LocalizedStrings.InvalidEmailFormat, LocalizedStrings.Error);
break; break;
default: default:
MsgBoxForm.Show("An error occurred:" + response, "Error"); MsgBoxForm.Show($"{LocalizedStrings.Error}: " + accounResponse.Message, LocalizedStrings.Error);
break; break;
} }
@ -184,9 +259,9 @@ namespace RHLauncher
try try
{ {
string email = EmailTextBox.Text; Regex emailRegex = RegexPatterns.EmailRegex();
string pattern = @"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$";
if (Regex.IsMatch(email, pattern)) if (emailRegex.IsMatch(EmailTextBox.Text))
{ {
// email is valid // email is valid
EmailPictureBox.Image = imageListTips.Images[1]; EmailPictureBox.Image = imageListTips.Images[1];
@ -271,23 +346,32 @@ namespace RHLauncher
private bool NameTextBoxValid = false; private bool NameTextBoxValid = false;
private void NameTextBox_TextChanged(object sender, EventArgs e) private void NameTextBox_TextChanged(object sender, EventArgs e)
{ {
if (string.IsNullOrEmpty(NameTextBox.Text) || NameTextBox.Text.Length < 6 || NameTextBox.Text.Length > 16 || !MyRegex().IsMatch(NameTextBox.Text)) Regex usernameRegex = RegexPatterns.UsernameRegex();
if (string.IsNullOrEmpty(UsernameTextBox.Text) || UsernameTextBox.Text.Length < 6 || UsernameTextBox.Text.Length > 16 || !usernameRegex.IsMatch(UsernameTextBox.Text) || HasUppercase(UsernameTextBox.Text))
{ {
if (string.IsNullOrEmpty(NameTextBox.Text)) if (string.IsNullOrEmpty(UsernameTextBox.Text))
{ {
NameDescLabel.Text = LocalizedStrings.UsernameDescLabelEmpty; NameDescLabel.Text = LocalizedStrings.UsernameDescLabelEmpty;
NameDescLabel.ForeColor = Color.Red; NameDescLabel.ForeColor = Color.Red;
NamePictureBox.Image = imageListTips.Images[0]; NamePictureBox.Image = imageListTips.Images[0];
NameTextBoxValid = false; NameTextBoxValid = false;
} }
else if (NameTextBox.Text.Length < 6 || NameTextBox.Text.Length > 16) else if (UsernameTextBox.Text.Length < 6 || UsernameTextBox.Text.Length > 16)
{ {
NameDescLabel.Text = LocalizedStrings.UsernameDescLabelSize; NameDescLabel.Text = LocalizedStrings.UsernameDescLabelSize;
NameDescLabel.ForeColor = Color.Red; NameDescLabel.ForeColor = Color.Red;
NamePictureBox.Image = imageListTips.Images[0]; NamePictureBox.Image = imageListTips.Images[0];
NameTextBoxValid = false; NameTextBoxValid = false;
} }
else if (!MyRegex().IsMatch(NameTextBox.Text)) else if (HasUppercase(UsernameTextBox.Text))
{
NameDescLabel.Text = LocalizedStrings.UsernameDescLabelUppercase;
NameDescLabel.ForeColor = Color.Red;
NamePictureBox.Image = imageListTips.Images[0];
NameTextBoxValid = false;
}
else if (!usernameRegex.IsMatch(UsernameTextBox.Text))
{ {
NameDescLabel.Text = LocalizedStrings.UsernameDescLabelInvalid; NameDescLabel.Text = LocalizedStrings.UsernameDescLabelInvalid;
NameDescLabel.ForeColor = Color.Red; NameDescLabel.ForeColor = Color.Red;
@ -304,13 +388,18 @@ namespace RHLauncher
CheckFormS2Validity(); CheckFormS2Validity();
} }
private static bool HasUppercase(string text)
{
return text.Any(char.IsUpper);
}
private bool PasswordTextBoxValid = false; private bool PasswordTextBoxValid = false;
private void PasswordTextBox_TextChanged(object sender, EventArgs e) private void PasswordTextBox_TextChanged(object sender, EventArgs e)
{ {
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 < 6 || password.Length > 16) if (password.Length < 8 || password.Length > 16)
{ {
PwdDescLabel.Text = LocalizedStrings.PwdDescLabelSize; PwdDescLabel.Text = LocalizedStrings.PwdDescLabelSize;
PwdDescLabel.ForeColor = Color.Red; PwdDescLabel.ForeColor = Color.Red;
@ -322,8 +411,8 @@ namespace RHLauncher
} }
// Check for at least one uppercase, one lowercase letter, and one number // Check for at least one uppercase, one lowercase letter, and one number
Regex regex = new(@"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).+$"); Regex pwRegex = RegexPatterns.PWRegex();
if (!regex.IsMatch(password)) if (!pwRegex.IsMatch(password))
{ {
PwdDescLabel.Text = LocalizedStrings.PwdDescLabelCriteria; PwdDescLabel.Text = LocalizedStrings.PwdDescLabelCriteria;
PwdDescLabel.ForeColor = Color.Red; PwdDescLabel.ForeColor = Color.Red;
@ -337,8 +426,8 @@ namespace RHLauncher
} }
// Check for additional character types such as symbols // Check for additional character types such as symbols
regex = new Regex(@"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^\da-zA-Z]).+$"); Regex strongPWRegex = RegexPatterns.StrongPWRegex();
if (regex.IsMatch(password)) if (strongPWRegex.IsMatch(password))
{ {
PwdDescLabel.Text = ""; PwdDescLabel.Text = "";
PwdPictureBox.Image = imageListTips.Images[1]; PwdPictureBox.Image = imageListTips.Images[1];
@ -397,9 +486,9 @@ namespace RHLauncher
} }
try try
{ {
string email = EmailTextBox.Text; Regex emailRegex = RegexPatterns.EmailRegex();
string pattern = @"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$";
if (Regex.IsMatch(email, pattern)) if (emailRegex.IsMatch(EmailTextBox.Text))
{ {
// email is valid // email is valid
EmailPictureBox.Image = imageListTips.Images[1]; EmailPictureBox.Image = imageListTips.Images[1];
@ -491,10 +580,6 @@ namespace RHLauncher
} }
} }
#endregion
#region Button Events
private void CloseButton_Click(object sender, EventArgs e) private void CloseButton_Click(object sender, EventArgs e)
{ {
Close(); Close();
@ -504,108 +589,51 @@ namespace RHLauncher
{ {
WindowState = FormWindowState.Minimized; WindowState = FormWindowState.Minimized;
} }
private void RegForm_FormClosing(object sender, FormClosingEventArgs e)
{
resendTimer.Dispose();
Dispose();
}
private void ContinueButtonS1_MouseHover(object sender, EventArgs e)
{
ContinueButtonS1.ImageIndex = 1;
}
private void ContinueButtonS1_MouseLeave(object sender, EventArgs e)
{
ContinueButtonS1.ImageIndex = 0;
}
private void ContinueButtonS1_OnMouseDown(object sender, MouseEventArgs e)
{
ContinueButtonS1.ImageIndex = 2;
}
private void ContinueButtonS2_MouseHover(object sender, EventArgs e)
{
ContinueButtonS2.ImageIndex = 1;
}
private void ContinueButtonS2_MouseLeave(object sender, EventArgs e)
{
ContinueButtonS2.ImageIndex = 0;
}
private void ContinueButtonS2_OnMouseDown(object sender, MouseEventArgs e)
{
ContinueButtonS2.ImageIndex = 2;
}
private void SendEmailButton_MouseHover(object sender, EventArgs e)
{
SendEmailButton.ImageIndex = 1;
}
private void SendEmailButton_MouseLeave(object sender, EventArgs e)
{
SendEmailButton.ImageIndex = 0;
}
private void SendEmailButton_OnMouseDown(object sender, MouseEventArgs e)
{
SendEmailButton.ImageIndex = 2;
}
private void RegForm_Load(object sender, EventArgs e)
{
ContinueButtonS1.Enabled = false;
}
private void MinimizeButton_MouseHover(object sender, EventArgs e)
{
MinimizeButton.ImageIndex = 1;
}
private void MinimizeButton_MouseLeave(object sender, EventArgs e)
{
MinimizeButton.ImageIndex = 0;
}
private void MinimizeButton_OnMouseDown(object sender, MouseEventArgs e)
{
MinimizeButton.ImageIndex = 2;
}
private void CloseButton_MouseHover(object sender, EventArgs e)
{
CloseButton.ImageIndex = 1;
}
private void CloseButton_MouseLeave(object sender, EventArgs e)
{
CloseButton.ImageIndex = 0;
}
private void CloseButton_OnMouseDown(object sender, MouseEventArgs e)
{
CloseButton.ImageIndex = 2;
}
private void ReturnLabelS2_MouseHover(object sender, EventArgs e)
{
ReturnLabelS2.ForeColor = Color.White;
}
private void ReturnLabelS2_MouseLeave(object sender, EventArgs e)
{
ReturnLabelS2.ForeColor = Color.Gainsboro;
}
private void AgreementLabel_MouseHover(object sender, EventArgs e)
{
AgreementLabel.ForeColor = Color.White;
}
private void AgreementLabel_MouseLeave(object sender, EventArgs e)
{
AgreementLabel.ForeColor = Color.Gainsboro;
}
#endregion #endregion
#region Button Events
private void Button_MouseHover(object sender, EventArgs e)
{
if (sender is Button button)
{
button.ImageIndex = 1;
}
}
private void Button_MouseLeave(object sender, EventArgs e)
{
if (sender is Button button)
{
button.ImageIndex = 0;
}
}
private void Button_MouseDown(object sender, MouseEventArgs e)
{
if (sender is Button button)
{
button.ImageIndex = 2;
}
}
private void Label_MouseHover(object sender, EventArgs e)
{
if (sender is Label label)
{
label.ForeColor = Color.White;
}
}
private void Label_MouseLeave(object sender, EventArgs e)
{
if (sender is Label label)
{
label.ForeColor = Color.Gainsboro;
}
}
#endregion
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -2,38 +2,46 @@ namespace RHLauncher.RHLauncher.Helper;
public class Configuration public class Configuration
{ {
private static readonly string DefaultIniFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "config.ini"); private static readonly string DefaultIniFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.ini");
public static readonly Configuration Default = new(); public static readonly Configuration Default = new();
private readonly IniFile iniFile = new(DefaultIniFilePath); public readonly IniFile iniFile = new(DefaultIniFilePath);
public Configuration() public Configuration()
{ {
string apiUrl = iniFile.ReadValue("Info", "LoginURL"); string apiUrl = iniFile.ReadValue("Info", "ServerURL");
//Client endpoints //Client endpoints
GateXMLUrl = $"{apiUrl}/serverApi/gateway"; GateXMLUrl = $"{apiUrl}/launcher/GetGatewayAction";
GateInfoUrl = $"{apiUrl}/serverApi/gateway/info"; GateInfoUrl = $"{apiUrl}/launcher/GetGatewayAction/info";
GateStatusUrl = $"{apiUrl}/serverApi/gateway/status"; GateStatusUrl = $"{apiUrl}/launcher/GetGatewayAction/status";
//Launcher endpoints //Launcher endpoints
LoginUrl = $"{apiUrl}/accountApi/login"; LoginUrl = $"{apiUrl}/launcher/LoginAction";
RegisterUrl = $"{apiUrl}/accountApi/register"; RegisterUrl = $"{apiUrl}/launcher/SignupAction";
SendCodeUrl = $"{apiUrl}/accountApi/sendVerificationEmail"; SendCodeUrl = $"{apiUrl}/launcher/SendVerificationEmailAction";
VerifyCodeUrl = $"{apiUrl}/accountApi/codeVerification"; VerifyCodeUrl = $"{apiUrl}/launcher/VerifyCodeAction";
SendPasswordCodeUrl = $"{apiUrl}/accountApi/sendPasswordResetEmail"; SendPasswordCodeUrl = $"{apiUrl}/launcher/SendPasswordResetEmailAction";
ChangePasswordUrl = $"{apiUrl}/accountApi/changePassword"; ChangePasswordUrl = $"{apiUrl}/launcher/ResetPasswordAction";
LauncherNewsUrl = $"{apiUrl}/launcher/news"; LauncherNewsUrl = $"{apiUrl}/launcher/news";
AgreementUrl = $"{apiUrl}/launcher/agreement"; AgreementUrl = $"{apiUrl}/launcher/agreement";
//Client download endpoints
ClientPartsListUrl = $"{apiUrl}/launcher/client/download/filelist.txt";
DownloadClientPartUrl = $"{apiUrl}/launcher/client/download";
//Client update endpoints //Client update endpoints
FileListUrl = $"{apiUrl}/launcher/patch/filelist.txt"; FileListUrl = $"{apiUrl}/launcher/patch/filelist.txt";
DownloadUpdateFileUrl = $"{apiUrl}/launcher/patch"; DownloadUpdateFileUrl = $"{apiUrl}/launcher/patch";
//Launcher update endpoints //Launcher update endpoints
GetLauncherVersion = $"{apiUrl}/launcherApi/launcherUpdater/getLauncherVersion"; GetLauncherVersion = $"{apiUrl}/launcherAction/getLauncherVersion";
UpdateLauncherVersion = $"{apiUrl}/launcherApi/launcherUpdater/updateLauncherVersion"; UpdateLauncherVersion = $"{apiUrl}/launcherAction/updateLauncherVersion";
//Launcher settings
Lang = iniFile.ReadValue("Launcher", "Lang");
Service = iniFile.ReadValue("Info", "Service");
} }
public string GateXMLUrl { get; set; } public string GateXMLUrl { get; set; }
@ -51,5 +59,9 @@ public class Configuration
public string GetLauncherVersion { get; set; } public string GetLauncherVersion { get; set; }
public string UpdateLauncherVersion { get; set; } public string UpdateLauncherVersion { get; set; }
public string DownloadUpdateFileUrl { get; set; } public string DownloadUpdateFileUrl { get; set; }
public string ClientPartsListUrl { get; set; }
public string DownloadClientPartUrl { get; set; }
public string Lang { get; set; }
public string Service { get; set; }
} }

View file

@ -0,0 +1,49 @@
namespace RHLauncher.RHLauncher.Helper;
public static class Crc32
{
private static readonly uint[] Crc32Table = new uint[]
{
0, 0x77073096, 0xee0e612c, 0x990951ba, 0x76dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0xedb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x9b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
0x76dc4190, 0x1db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x6b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0xf00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x86d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
0xedb88320, 0x9abfb3b6, 0x3b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x4db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0xd6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0xa00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x26d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x5005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0xcb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0xbdbdf21,
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
public static string GetFileHash(string filePath)
{
uint crc = 0xFFFFFFFF;
using (FileStream stream = File.OpenRead(filePath))
{
int bytesRead;
byte[] buffer = new byte[4096];
while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
{
for (int i = 0; i < bytesRead; i++)
{
byte b = buffer[i];
crc = (crc >> 8) ^ Crc32Table[(crc ^ b) & 0xFF];
}
}
}
crc ^= 0x00000000;
return crc.ToString("X8");
}
}

View file

@ -1,4 +1,4 @@
using RHLauncher.Helper; using RHLauncher.RHLauncher.i8n;
namespace RHLauncher.RHLauncher.Helper namespace RHLauncher.RHLauncher.Helper
{ {
@ -6,8 +6,8 @@ namespace RHLauncher.RHLauncher.Helper
{ {
public static void HandleException(Exception ex, Exception exlog) public static void HandleException(Exception ex, Exception exlog)
{ {
string errorMessage = $"Error: {ex.Message}"; string errorMessage = $"{LocalizedStrings.Error}: {ex.Message}";
string errorLog = $"Error:{ex.Message} {Environment.NewLine} {exlog.Message}"; string errorLog = $"{LocalizedStrings.Error}: {ex.Message} {Environment.NewLine} {exlog.Message}";
Logger.WriteLog(errorLog); Logger.WriteLog(errorLog);
MsgBoxForm.Show(errorMessage, LocalizedStrings.Error); MsgBoxForm.Show(errorMessage, LocalizedStrings.Error);
} }

View file

@ -1,6 +1,6 @@
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace RHLauncher.Helper namespace RHLauncher.RHLauncher.Helper
{ {
public class FormUtils public class FormUtils
{ {

View file

@ -0,0 +1,18 @@
using System.Diagnostics;
namespace RHLauncher.RHLauncher.Helper
{
public class GetLauncherVersion
{
public static string GetVersion()
{
// Get the version information of the application
FileVersionInfo versionInfo = FileVersionInfo.GetVersionInfo(Application.ExecutablePath);
// Extract the version number
string version = $"{versionInfo.FileMajorPart}.{versionInfo.FileMinorPart}.{versionInfo.FileBuildPart}";
return version;
}
}
}

View file

@ -0,0 +1,36 @@
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

@ -3,14 +3,14 @@ using System.Text;
namespace RHLauncher.RHLauncher.Helper namespace RHLauncher.RHLauncher.Helper
{ {
public class IniFile public partial class IniFile
{ {
private readonly string _iniFilePath; private readonly string _iniFilePath;
[DllImport("kernel32")] [LibraryImport("kernel32", EntryPoint = "WritePrivateProfileStringW", StringMarshalling = StringMarshalling.Utf16)]
private static extern long WritePrivateProfileString(string section, string key, string val, string filePath); private static partial long WritePrivateProfileString(string section, string key, string val, string filePath);
[DllImport("kernel32")] [DllImport("kernel32", CharSet = CharSet.Unicode)]
private static extern int GetPrivateProfileString(string section, string key, string def, StringBuilder retVal, int size, string filePath); private static extern int GetPrivateProfileString(string section, string key, string def, StringBuilder retVal, int size, string filePath);
public IniFile(string iniFileName) public IniFile(string iniFileName)
@ -21,16 +21,18 @@ namespace RHLauncher.RHLauncher.Helper
if (!File.Exists(_iniFilePath)) if (!File.Exists(_iniFilePath))
{ {
//Default api url //Default api url
WritePrivateProfileString("Info", "LoginURL", "http://localhost:3000", _iniFilePath); WritePrivateProfileString("Info", "ServerURL", "http://127.0.0.1", _iniFilePath);
//Default client service //Default client service
WritePrivateProfileString("Info", "Service", "usa", _iniFilePath); WritePrivateProfileString("Info", "Service", "jpn", _iniFilePath);
//Default launcher language
WritePrivateProfileString("Launcher", "Lang", "en", _iniFilePath);
} }
} }
public string ReadValue(string section, string key) public string ReadValue(string section, string key)
{ {
StringBuilder sb = new(255); StringBuilder sb = new(255);
GetPrivateProfileString(section, key, "", sb, 255, _iniFilePath); _ = GetPrivateProfileString(section, key, "", sb, 255, _iniFilePath);
return sb.ToString(); return sb.ToString();
} }

View file

@ -1,4 +1,4 @@
namespace RHLauncher.Helper; namespace RHLauncher.RHLauncher.Helper;
public class Logger public class Logger
{ {
@ -13,10 +13,14 @@ public class Logger
// Create log file with today's date // Create log file with today's date
logFilePath = Path.Combine(logFilePath, "Log-" + DateTime.Today.ToString("MM-dd-yyyy") + ".txt"); logFilePath = Path.Combine(logFilePath, "Log-" + DateTime.Today.ToString("MM-dd-yyyy") + ".txt");
FileInfo logFileInfo = new(logFilePath); FileInfo logFileInfo = new(logFilePath);
DirectoryInfo logDirInfo = new(logFileInfo.DirectoryName);
if (!logDirInfo.Exists) if (logFileInfo.DirectoryName != null)
{ {
logDirInfo.Create(); DirectoryInfo logDirInfo = new(logFileInfo.DirectoryName);
if (!logDirInfo.Exists)
{
logDirInfo.Create();
}
} }
// Write log entry to file // Write log entry to file
@ -28,4 +32,5 @@ public class Logger
streamWriter.WriteLine("Message: {0}", message); streamWriter.WriteLine("Message: {0}", message);
streamWriter.WriteLine("---------------------------"); streamWriter.WriteLine("---------------------------");
} }
} }

View file

@ -1,25 +1,26 @@
namespace RHLauncher.RHLauncher namespace RHLauncher.RHLauncher.Helper
{ {
public class ProgressReport public class ProgressReport
{ {
public string? Label { get; set; } public string? Label { get; set; }
public string? Button { get; set; }
public int PercentComplete { get; set; } public int PercentComplete { get; set; }
public string? FileName { get; set; } public string? FileName { get; set; }
public string? ErrorMessage { get; set; } public string? ErrorMessage { get; set; }
public long BytesDownloaded { get; set; } public long Current { get; set; }
public long TotalBytesToDownload { get; set; } public long Total { get; set; }
public double TotalSpeed { get; set; } public double TotalSpeed { get; set; }
public long TimeLeft { get; set; } public long TimeLeft { get; set; }
public int NumFilesDownloaded { get; set; } public int NumFiles { get; set; }
public int TotalNumFiles { get; set; } public int TotalNumFiles { get; set; }
public int NumFilesPacked { get; set; }
public int NumFilesUnpacked { get; set; }
public bool Panel { get; set; } public bool Panel { get; set; }
public CancellationToken CancellationToken { get; set; } public bool CancellButton { get; set; }
public bool ShowFileNameLabel { get; set; } public bool ShowFileNameLabel { get; set; }
public bool ShowSpeedLabel { get; set; } public bool ShowSpeedLabel { get; set; }
public bool ShowTimeLabel { get; set; } public bool ShowTimeLabel { get; set; }
public bool ShowFileSizeLabel { get; set; } public bool ShowFileSizeLabel { get; set; }
public bool ShowFileCountLabel { get; set; } public bool ShowFileCountLabel { get; set; }
public bool IsCheckingFilelist { get; set; }
public CancellationToken CancellationToken { get; set; }
} }
} }

View file

@ -0,0 +1,152 @@
using RHLauncher.RHLauncher.i8n;
using System.Diagnostics;
namespace RHLauncher.RHLauncher.Helper
{
public class ProgressReporter
{
public static void ReportFileListCheckProgress(IProgress<ProgressReport> progress, int checkedFilesCount, int totalFiles, CancellationToken cancellationToken)
{
int percentComplete = totalFiles > 0 ? (int)Math.Round(checkedFilesCount * 100.0 / totalFiles) : 0;
ProgressReport report = new()
{
Panel = true,
CancellButton = true,
ShowFileCountLabel = true,
IsCheckingFilelist = true,
Button = LocalizedStrings.Checking,
Label = LocalizedStrings.CheckingFiles,
Current = checkedFilesCount,
Total = totalFiles,
PercentComplete = percentComplete,
NumFiles = checkedFilesCount,
TotalNumFiles = totalFiles,
CancellationToken = cancellationToken
};
progress.Report(report);
}
public static void ReportDownloadProgress(IProgress<ProgressReport> progress, string fileName, long downloadedSize, long totalBytesToDownload, int downloadedFileCount, int totalFilesToDownload, Stopwatch sw, CancellationToken cancellationToken)
{
int percentComplete = totalBytesToDownload > 0 ? (int)Math.Round(downloadedSize * 100.0 / totalBytesToDownload) : 0;
double totalSpeed = downloadedSize / sw.Elapsed.TotalSeconds;
long timeLeft = totalBytesToDownload > 0 ? (long)((totalBytesToDownload - downloadedSize) / (downloadedSize / sw.Elapsed.TotalSeconds)) : 0;
ProgressReport report = new()
{
Panel = true,
CancellButton = true,
ShowFileNameLabel = true,
ShowSpeedLabel = true,
ShowTimeLabel = true,
ShowFileSizeLabel = true,
ShowFileCountLabel = true,
Button = LocalizedStrings.Downloading,
Label = LocalizedStrings.Downloading,
PercentComplete = percentComplete,
FileName = fileName,
Current = downloadedSize,
Total = totalBytesToDownload,
TotalSpeed = totalSpeed,
TimeLeft = timeLeft,
NumFiles = downloadedFileCount,
TotalNumFiles = totalFilesToDownload,
CancellationToken = cancellationToken
};
progress.Report(report);
}
public static void ReportClientDownloadProgress(IProgress<ProgressReport> progress, long downloadedSize, long totalBytesToDownload, Stopwatch sw, CancellationToken cancellationToken)
{
int percentComplete = totalBytesToDownload > 0 ? (int)Math.Round(downloadedSize * 100.0 / totalBytesToDownload) : 0;
double totalSpeed = downloadedSize / sw.Elapsed.TotalSeconds;
long timeLeft = totalBytesToDownload > 0 ? (long)((totalBytesToDownload - downloadedSize) / (downloadedSize / sw.Elapsed.TotalSeconds)) : 0;
ProgressReport report = new()
{
Panel = true,
CancellButton = true,
ShowSpeedLabel = true,
ShowTimeLabel = true,
ShowFileSizeLabel = true,
Button = LocalizedStrings.Downloading,
Label = LocalizedStrings.Downloading,
PercentComplete = percentComplete,
Current = downloadedSize,
Total = totalBytesToDownload,
TotalSpeed = totalSpeed,
TimeLeft = timeLeft,
CancellationToken = cancellationToken
};
progress.Report(report);
}
public static void ReportFileCheckingProgress(IProgress<ProgressReport> progress, int checkedFiles, int totalFiles, CancellationToken cancellationToken)
{
int percentComplete = totalFiles > 0 ? (int)Math.Round(checkedFiles * 100.0 / totalFiles) : 0;
ProgressReport report = new()
{
Panel = true,
IsCheckingFilelist = true,
Button = LocalizedStrings.Checking,
Label = LocalizedStrings.CheckingFiles,
PercentComplete = percentComplete,
Current = checkedFiles,
Total = totalFiles,
CancellationToken = cancellationToken
};
progress.Report(report);
}
public static void ReportUnzipProgress(IProgress<ProgressReport> progress, long extractedSize, long totalUncompressedSize, CancellationToken cancellationToken)
{
int percentComplete = totalUncompressedSize > 0 ? (int)(extractedSize * 100 / totalUncompressedSize) : 0;
ProgressReport report = new()
{
Panel = true,
CancellButton = true,
Button = LocalizedStrings.Installing,
Label = LocalizedStrings.Installing,
PercentComplete = percentComplete,
Current = extractedSize,
Total = totalUncompressedSize,
CancellationToken = cancellationToken
};
progress.Report(report);
}
public static void ReportErrorProgress(IProgress<ProgressReport> progress, string message, CancellationToken cancellationToken)
{
ProgressReport report = new()
{
Panel = true,
Button = LocalizedStrings.Error,
Label = LocalizedStrings.Error,
ErrorMessage = message,
CancellationToken = cancellationToken
};
progress.Report(report);
}
public static void ReportFinishedProgress(IProgress<ProgressReport> progress, CancellationToken cancellationToken)
{
ProgressReport report = new()
{
Panel = false,
Button = LocalizedStrings.Launch,
CancellationToken = cancellationToken
};
progress.Report(report);
}
}
}

View file

@ -1,4 +1,4 @@
namespace RHLauncher.RHLauncher namespace RHLauncher.RHLauncher.Helper
{ {
public class ProgressThrottler : IProgress<ProgressReport> public class ProgressThrottler : IProgress<ProgressReport>
{ {

View file

@ -0,0 +1,19 @@
using System.Text.RegularExpressions;
namespace RHLauncher.RHLauncher.Helper
{
public static partial class RegexPatterns
{
[GeneratedRegex(@"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$")]
public static partial Regex EmailRegex();
[GeneratedRegex("^(?=.*[a-z])[a-z0-9]+$")]
public static partial Regex UsernameRegex();
[GeneratedRegex("^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d).+$")]
public static partial Regex PWRegex();
[GeneratedRegex("^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[^\\da-zA-Z]).+$")]
public static partial Regex StrongPWRegex();
}
}

View file

@ -2,12 +2,13 @@
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Text; using System.Text;
namespace RHLauncher.Helper namespace RHLauncher.RHLauncher.Helper
{ {
public class RegistryHandler public class RegistryHandler
{ {
private const string KEY_NAME = "RustyHearts\\UserInfo"; private const string KEY_NAME = "RustyHearts\\UserInfo";
private const string INSTALL_DIR_KEY = "InstallDirectory"; private const string INSTALL_DIR_KEY = "InstallDirectory";
private const string TEMP_INSTALL_DIR_KEY = "TempInstallDirectory";
private readonly RegistryKey key; private readonly RegistryKey key;
public RegistryHandler() public RegistryHandler()
@ -56,6 +57,11 @@ namespace RHLauncher.Helper
key.SetValue(INSTALL_DIR_KEY, directory ?? string.Empty); key.SetValue(INSTALL_DIR_KEY, directory ?? string.Empty);
} }
public void SaveTempInstallDirectory(string directory)
{
key.SetValue(TEMP_INSTALL_DIR_KEY, directory ?? string.Empty);
}
public string GetInstallDirectory() public string GetInstallDirectory()
{ {
return key.GetValue(INSTALL_DIR_KEY)?.ToString() ?? string.Empty; return key.GetValue(INSTALL_DIR_KEY)?.ToString() ?? string.Empty;
@ -70,6 +76,20 @@ namespace RHLauncher.Helper
} }
} }
public string GetTempInstallDirectory()
{
return key.GetValue(TEMP_INSTALL_DIR_KEY)?.ToString() ?? string.Empty;
}
public void ClearTempInstallDirectory()
{
var value = key.GetValue(TEMP_INSTALL_DIR_KEY)?.ToString();
if (!string.IsNullOrEmpty(value))
{
key.DeleteValue(TEMP_INSTALL_DIR_KEY);
}
}
public void DeleteValues(string KEY_NAME) public void DeleteValues(string KEY_NAME)
{ {
var value = key.GetValue(KEY_NAME) as string ?? ""; var value = key.GetValue(KEY_NAME) as string ?? "";

View file

@ -1,4 +1,5 @@
using System.Security.Cryptography; using RHLauncher.RHLauncher.i8n;
using System.Security.Cryptography;
namespace RHLauncher.RHLauncher.Helper namespace RHLauncher.RHLauncher.Helper
{ {
@ -19,15 +20,31 @@ namespace RHLauncher.RHLauncher.Helper
string md5 = CalculateMD5(service); string md5 = CalculateMD5(service);
string serviceDatPath = Path.Combine(_installDirectory, "Service.dat"); string serviceDatPath = Path.Combine(_installDirectory, "Service.dat");
string[] lines = File.ReadAllLines(serviceDatPath);
string currentMd5 = lines[0]; try
string currentService = string.Join(Environment.NewLine, lines, 1, lines.Length - 1);
if (currentMd5 != md5)
{ {
lines[0] = md5; if (File.Exists(serviceDatPath))
File.WriteAllLines(serviceDatPath, lines); {
string[] lines = File.ReadAllLines(serviceDatPath);
string currentMd5 = lines[0];
string currentService = string.Join(Environment.NewLine, lines, 1, lines.Length - 1);
if (currentMd5 != md5)
{
lines[0] = md5;
File.WriteAllLines(serviceDatPath, lines);
}
}
else
{
MsgBoxForm.Show(LocalizedStrings.ServiceDatFileMissing, LocalizedStrings.Error);
return;
}
}
catch (Exception ex)
{
MsgBoxForm.Show(LocalizedStrings.ServiceUpdateError + ": " + ex.Message, LocalizedStrings.Error);
} }
} }

View file

@ -0,0 +1,225 @@
using RHLauncher.RHLauncher.Helper;
using RHLauncher.RHLauncher.i8n;
using System.Diagnostics;
using System.Globalization;
using System.IO.Compression;
using System.Net;
namespace RHLauncher.RHLauncher.Http
{
public class ClientDownloader
{
public enum DownloadClientResultStatus
{
Success,
Failed,
Cancelled
}
public class DownloadClientResult
{
public DownloadClientResultStatus Status { get; set; }
public string? InstallDirectoryPath { get; set; }
}
private const int BufferSize = 8192;
private const int TimeoutSeconds = 30;
public static async Task<DownloadClientResult> DownloadClientAsync(string installDirectory, IProgress<ProgressReport> progress, CancellationToken cancellationToken)
{
using HttpClientHandler handler = new() { AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate };
using HttpClient client = new(handler, true) { Timeout = TimeSpan.FromSeconds(TimeoutSeconds) };
try
{
string filelistUrl = Configuration.Default.ClientPartsListUrl;
using HttpResponseMessage filelistResponse = await client.GetAsync(filelistUrl, cancellationToken);
if (!filelistResponse.IsSuccessStatusCode)
{
// Handle the case where the filelist URL is not found
string errorMessage = $"{LocalizedStrings.ClientDownloadErrorMessage}:\n\n{LocalizedStrings.ClientDownloadFilelistError}: {filelistUrl}.\n\n {LocalizedStrings.Error}: {filelistResponse.ReasonPhrase}";
MsgBoxForm.Show($" {LocalizedStrings.Error}: {errorMessage}", LocalizedStrings.Error);
Logger.WriteLog(errorMessage);
return new DownloadClientResult { Status = DownloadClientResultStatus.Failed };
}
string filelistText = await client.GetStringAsync(filelistUrl, cancellationToken).ConfigureAwait(false);
string downloadDir = Path.Combine(installDirectory, "rhclient_download");
if (!Directory.Exists(downloadDir))
{
Directory.CreateDirectory(downloadDir);
}
List<string> filesToBeDownloaded = [];
long totalBytesToDownload = 0L;
List<string> lines = [.. filelistText.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries)];
int totalLines = lines.Count;
int checkedFiles = 0;
foreach (string line in lines)
{
cancellationToken.ThrowIfCancellationRequested();
string[] parts = line.Split(' ');
if (parts.Length != 3)
{
continue;
}
string fileName = parts[0];
long fileSize = long.Parse(parts[1]);
ulong fileHashFromServer = ulong.Parse(parts[2], NumberStyles.HexNumber, CultureInfo.InvariantCulture);
string filePath = Path.Combine(downloadDir, fileName);
if (File.Exists(filePath))
{
string existingFileHash = Crc32.GetFileHash(filePath);
if (existingFileHash.Equals(fileHashFromServer.ToString("X8"), StringComparison.OrdinalIgnoreCase))
{
checkedFiles++;
ProgressReporter.ReportFileCheckingProgress(progress, checkedFiles, totalLines, cancellationToken);
continue; // Skip this file as it already exists and the hash matches
}
}
filesToBeDownloaded.Add(fileName);
totalBytesToDownload += fileSize;
checkedFiles++;
ProgressReporter.ReportFileCheckingProgress(progress, checkedFiles, totalLines, cancellationToken);
}
Stopwatch sw = Stopwatch.StartNew();
long downloadedBytes = 0L;
foreach (string fileName in filesToBeDownloaded)
{
cancellationToken.ThrowIfCancellationRequested();
string fileUrl = $"{Configuration.Default.DownloadClientPartUrl}/{fileName}";
string filePath = Path.Combine(downloadDir, fileName);
using HttpResponseMessage response = await client.GetAsync(fileUrl, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
response.EnsureSuccessStatusCode();
await using Stream contentStream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
await using FileStream fileStream = new(filePath, FileMode.Create, FileAccess.Write, FileShare.None, BufferSize, true);
byte[] buffer = new byte[BufferSize];
int bytesRead;
while ((bytesRead = await contentStream.ReadAsync(buffer, cancellationToken).ConfigureAwait(false)) > 0)
{
cancellationToken.ThrowIfCancellationRequested();
await fileStream.WriteAsync(buffer.AsMemory(0, bytesRead), cancellationToken).ConfigureAwait(false);
downloadedBytes += bytesRead;
ProgressReporter.ReportClientDownloadProgress(progress, downloadedBytes, totalBytesToDownload, sw, cancellationToken);
}
}
ProgressReporter.ReportFinishedProgress(progress, cancellationToken);
string rhExePath = await UnzipFilesAsync(downloadDir, installDirectory, progress, cancellationToken);
ProgressReporter.ReportFinishedProgress(progress, cancellationToken);
return new DownloadClientResult
{
Status = DownloadClientResultStatus.Success,
InstallDirectoryPath = rhExePath
};
}
catch (OperationCanceledException ex)
{
Logger.WriteLog($"Download cancelled: {ex.Message}");
return new DownloadClientResult { Status = DownloadClientResultStatus.Cancelled };
}
catch (Exception ex)
{
ProgressReporter.ReportErrorProgress(progress, ex.Message, cancellationToken);
string errorMessage = LocalizedStrings.ClientDownloadError + "\n" + ex.Message;
string errorLog = LocalizedStrings.ClientDownloadError + ex.Message + ex.StackTrace;
Exception newEx = new(errorMessage, ex);
Exception newLogEx = new(errorLog, ex);
ExceptionHandler.HandleException(newEx, newLogEx);
return new DownloadClientResult { Status = DownloadClientResultStatus.Failed };
}
}
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 rhExeDirectoryPath = "";
// Calculate total uncompressed size of all files in all zip archives
long totalUncompressedSize = fileEntries.Sum(file =>
{
using FileStream fs = new(file, FileMode.Open, FileAccess.Read);
using ZipArchive zip = new(fs, ZipArchiveMode.Read);
static long entryLength(ZipArchiveEntry entry) => entry.Length;
return zip.Entries.Sum(entryLength);
});
long totalExtracted = 0;
try
{
foreach (string file in fileEntries)
{
await Task.Run(() =>
{
using FileStream fs = new(file, FileMode.Open, FileAccess.Read);
using ZipArchive zip = new(fs, ZipArchiveMode.Read);
foreach (var entry in zip.Entries)
{
cancellationToken.ThrowIfCancellationRequested();
string destinationPath = Path.Combine(destinationDirectory, entry.FullName);
string? directoryPath = Path.GetDirectoryName(destinationPath);
if (!string.IsNullOrEmpty(directoryPath) && !Directory.Exists(directoryPath))
{
Directory.CreateDirectory(directoryPath);
}
entry.ExtractToFile(destinationPath, overwrite: true);
totalExtracted += entry.Length;
cancellationToken.ThrowIfCancellationRequested();
ProgressReporter.ReportUnzipProgress(progress, totalExtracted, totalUncompressedSize, cancellationToken);
// Check if the current entry is "rustyhearts.exe" and store its directory path
if (entry.FullName.EndsWith("rustyhearts.exe", StringComparison.OrdinalIgnoreCase))
{
rhExeDirectoryPath = Path.GetDirectoryName(destinationPath) ?? "";
}
}
}, cancellationToken);
}
}
catch (OperationCanceledException)
{
throw;
}
try
{
if (Directory.Exists(sourceDirectory))
{
Directory.Delete(sourceDirectory, true);
}
}
catch (Exception ex)
{
throw new InvalidOperationException($"{LocalizedStrings.ClientFolderErrorMessage}", ex);
}
// Check if 'rustyhearts.exe' directory exists
if (!string.IsNullOrWhiteSpace(rhExeDirectoryPath) && Directory.Exists(rhExeDirectoryPath))
{
return rhExeDirectoryPath;
}
else
{
throw new FileNotFoundException($"{LocalizedStrings.ClientFolderExeErrorMessage}");
}
}
}
}

View file

@ -0,0 +1,69 @@
using RHLauncher.RHLauncher.Helper;
using System.Net;
namespace RHLauncher.RHLauncher.Http
{
public class DownloadHelper
{
public static async Task<long> GetFileSizeAsync(HttpClient client, string fileUrl, CancellationToken cancellationToken)
{
using HttpRequestMessage request = new(HttpMethod.Get, fileUrl);
try
{
using HttpResponseMessage response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
if (response.IsSuccessStatusCode)
{
return response.Content.Headers.ContentLength ?? throw new Exception("Content-Length header not found in response headers.");
}
else if (response.StatusCode == HttpStatusCode.NotFound)
{
Logger.WriteLog($"File not found: {fileUrl}");
return 0;
}
else
{
Logger.WriteLog($"Error getting file size for {fileUrl}: {response.StatusCode}");
return 0;
}
}
catch (HttpRequestException ex) when (ex.StatusCode == HttpStatusCode.NotFound)
{
Logger.WriteLog($"File not found: {fileUrl}");
return 0;
}
catch (Exception ex)
{
Logger.WriteLog($"Error getting file size for {fileUrl}: {ex.Message}");
return 0;
}
}
public static string FormatDownloadSpeed(double totalDownloadSpeed)
{
string[] sizes = { "B/s", "KB/s", "MB/s", "GB/s" };
int order = 0;
while (totalDownloadSpeed >= 1024 && order < sizes.Length - 1)
{
order++;
totalDownloadSpeed /= 1024;
}
return $"{totalDownloadSpeed:0.#} {sizes[order]}";
}
public static string FormatFileSize(long bytes)
{
string[] sizes = { "B", "KB", "MB", "GB" };
int order = 0;
while (bytes >= 1024 && order < sizes.Length - 1)
{
order++;
bytes /= 1024;
}
return $"{bytes:0.#} {sizes[order]}";
}
}
}

View file

@ -0,0 +1,118 @@
using Newtonsoft.Json;
using RHLauncher.RHLauncher.Helper;
using RHLauncher.RHLauncher.i8n;
using System.IO.Compression;
using System.Text;
namespace RHLauncher.RHLauncher.Http
{
public class LauncherUpdater
{
private readonly string LauncherVersionUrl = Configuration.Default.GetLauncherVersion;
private readonly string LauncherUpdateUrl = Configuration.Default.UpdateLauncherVersion;
public class LauncherVersion
{
public string? Version { get; set; }
}
public async Task CheckForLauncherUpdateAsync()
{
try
{
using HttpClient client = new();
using HttpResponseMessage response = await client.GetAsync(LauncherVersionUrl);
response.EnsureSuccessStatusCode();
string json = await response.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<LauncherVersion>(json);
if (result != null)
{
string? newVersion = result.Version;
if (!string.IsNullOrEmpty(newVersion))
{
string currentVersion = GetLauncherVersion.GetVersion();
if (!string.IsNullOrEmpty(currentVersion) && !currentVersion.Equals(newVersion, StringComparison.OrdinalIgnoreCase))
{
string updateMessage = $"{LocalizedStrings.LauncherUpdateText}\n\n" +
$"{LocalizedStrings.Version}: {newVersion}";
MsgBoxForm.Show(updateMessage, LocalizedStrings.Info);
await DownloadLauncherUpdateAsync(json);
}
await Task.Delay(1000);
}
}
}
catch (Exception ex)
{
HandleLauncherUpdateException(ex);
}
}
private async Task DownloadLauncherUpdateAsync(string version)
{
try
{
using HttpClient client = new();
using StringContent content = new(version, Encoding.UTF8, "application/json");
var result = JsonConvert.DeserializeObject<LauncherVersion>(version);
if (result != null)
{
string? v = result.Version;
if (!string.IsNullOrEmpty(version))
{
using HttpResponseMessage response = await client.PostAsync(LauncherUpdateUrl, content);
response.EnsureSuccessStatusCode();
byte[] updateBytes = await response.Content.ReadAsByteArrayAsync();
string tempFilePath = Path.Combine(Path.GetTempPath(), $"launcher_update.zip");
File.WriteAllBytes(tempFilePath, updateBytes);
string executablePath = AppDomain.CurrentDomain.BaseDirectory;
string backupFilePath = Path.Combine(executablePath, $"Launcher_old.exe");
string launcherExePath = Path.Combine(executablePath, "Launcher.exe");
if (File.Exists(backupFilePath))
{
File.Delete(backupFilePath);
}
// Move existing launcher.exe to temporary location
File.Move(launcherExePath, backupFilePath);
// Extract new update files
ZipFile.ExtractToDirectory(tempFilePath, executablePath, true);
// Delete temporary zip file
File.Delete(tempFilePath);
MsgBoxForm.Show(LocalizedStrings.LauncherUpdateSuccess + v, LocalizedStrings.Info);
await Task.Delay(500).ContinueWith(_ =>
{
Application.Restart();
});
}
}
}
catch (Exception ex)
{
HandleLauncherUpdateException(ex);
}
}
private static void HandleLauncherUpdateException(Exception ex)
{
string errorMessage = LocalizedStrings.LauncherUpdateFailed + ex.Message;
string errorLog = LocalizedStrings.LauncherUpdateFailed + ex.Message + ex.StackTrace;
Exception newEx = new(errorMessage, ex);
Exception newLogEx = new(errorLog, ex);
ExceptionHandler.HandleException(newEx, newLogEx);
}
}
}

View file

@ -1,14 +1,21 @@
using RHLauncher.Helper; using RHLauncher.RHLauncher.Helper;
using RHLauncher.PCK; using RHLauncher.RHLauncher.i8n;
using RHLauncher.RHLauncher.Helper; using RHLauncher.RHLauncher.PCK;
using System.Diagnostics; using System.Diagnostics;
using System.Globalization; using System.Globalization;
using System.Net; using System.Net;
namespace RHLauncher.RHLauncher namespace RHLauncher.RHLauncher.Http
{ {
public class UpdateDownloader public class UpdateDownloader
{ {
public enum UpdateState
{
UpdateAvailable,
NoUpdateAvailable,
Error
}
private const int BufferSize = 8192; private const int BufferSize = 8192;
private const int TimeoutSeconds = 30; private const int TimeoutSeconds = 30;
@ -16,8 +23,18 @@ namespace RHLauncher.RHLauncher
{ {
try try
{ {
string fileListUrl = Configuration.Default.FileListUrl;
using var client = new HttpClient(); using var client = new HttpClient();
string fileListUrl = Configuration.Default.FileListUrl;
using HttpResponseMessage filelistResponse = await client.GetAsync(fileListUrl);
if (!filelistResponse.IsSuccessStatusCode)
{
// Handle the case where the filelist URL is not found
return UpdateState.Error;
}
using var response = await client.GetAsync(fileListUrl); using var response = await client.GetAsync(fileListUrl);
using var content = await response.Content.ReadAsStreamAsync(); using var content = await response.Content.ReadAsStreamAsync();
using var reader = new StreamReader(content); using var reader = new StreamReader(content);
@ -69,13 +86,6 @@ namespace RHLauncher.RHLauncher
} }
} }
public enum UpdateState
{
UpdateAvailable,
NoUpdateAvailable,
Error
}
public static async Task DownloadUpdatesAsync(string installDirectory, IProgress<ProgressReport> progress, CancellationToken cancellationToken) public static async Task DownloadUpdatesAsync(string installDirectory, IProgress<ProgressReport> progress, CancellationToken cancellationToken)
{ {
using HttpClientHandler handler = new() { AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate }; using HttpClientHandler handler = new() { AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate };
@ -83,6 +93,12 @@ namespace RHLauncher.RHLauncher
try try
{ {
string archiveDir = Path.Combine(installDirectory, "archive");
if (!Directory.Exists(archiveDir))
{
Directory.CreateDirectory(archiveDir);
}
string filelistUrl = Configuration.Default.FileListUrl; string filelistUrl = Configuration.Default.FileListUrl;
string filelistText = await client.GetStringAsync(filelistUrl, cancellationToken).ConfigureAwait(false); string filelistText = await client.GetStringAsync(filelistUrl, cancellationToken).ConfigureAwait(false);
@ -94,8 +110,13 @@ namespace RHLauncher.RHLauncher
List<string> filesToBeDownloaded = new(); List<string> filesToBeDownloaded = new();
long totalBytesToDownload = 0L; long totalBytesToDownload = 0L;
int totalFilesToDownload = 0; int totalFilesToDownload = 0;
foreach (string line in filelistText.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries))
List<string> lines = filelistText.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries).ToList();
int totalLines = lines.Count;
for (int i = 0; i < totalLines; i++)
{ {
string line = lines[i];
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
string[] parts = line.Split(' '); string[] parts = line.Split(' ');
@ -118,16 +139,12 @@ namespace RHLauncher.RHLauncher
if (!fileHashes.TryGetValue(fileName, out uint fileHash) || fileHash != fileHashFromServer) if (!fileHashes.TryGetValue(fileName, out uint fileHash) || fileHash != fileHashFromServer)
{ {
filesToBeDownloaded.Add(fileName); filesToBeDownloaded.Add(fileName);
long fileSize = await GetFileSizeAsync(client, $"{Configuration.Default.DownloadUpdateFileUrl}/{fileName}.mip", cancellationToken).ConfigureAwait(false); long fileSize = await DownloadHelper.GetFileSizeAsync(client, $"{Configuration.Default.DownloadUpdateFileUrl}/{fileName}.mip", cancellationToken).ConfigureAwait(false);
totalBytesToDownload += fileSize; totalBytesToDownload += fileSize;
totalFilesToDownload++; totalFilesToDownload++;
} }
}
string archiveDir = Path.Combine(installDirectory, "archive"); ProgressReporter.ReportFileListCheckProgress(progress, i + 1, totalLines, cancellationToken);
if (!Directory.Exists(archiveDir))
{
Directory.CreateDirectory(archiveDir);
} }
Stopwatch sw = Stopwatch.StartNew(); Stopwatch sw = Stopwatch.StartNew();
@ -147,9 +164,12 @@ namespace RHLauncher.RHLauncher
response.EnsureSuccessStatusCode(); response.EnsureSuccessStatusCode();
await using Stream contentStream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); await using Stream contentStream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
if (!Directory.Exists(Path.GetDirectoryName(filePath)))
string? directoryPath = Path.GetDirectoryName(filePath);
if (!string.IsNullOrEmpty(directoryPath) && !Directory.Exists(directoryPath))
{ {
Directory.CreateDirectory(Path.GetDirectoryName(filePath)); Directory.CreateDirectory(directoryPath);
} }
await using FileStream fileStream = new(filePath, FileMode.Create, FileAccess.Write, FileShare.None, BufferSize, true); await using FileStream fileStream = new(filePath, FileMode.Create, FileAccess.Write, FileShare.None, BufferSize, true);
@ -166,7 +186,6 @@ namespace RHLauncher.RHLauncher
} }
ProgressReporter.ReportDownloadProgress(progress, finalfileName, downloadedSize, totalBytesToDownload, downloadedFileCount, totalFilesToDownload, sw, cancellationToken); ProgressReporter.ReportDownloadProgress(progress, finalfileName, downloadedSize, totalBytesToDownload, downloadedFileCount, totalFilesToDownload, sw, cancellationToken);
await Task.Yield();
downloadedFileCount++; downloadedFileCount++;
} }
fileHashes.Clear(); fileHashes.Clear();
@ -175,7 +194,7 @@ namespace RHLauncher.RHLauncher
} }
catch (OperationCanceledException ex) catch (OperationCanceledException ex)
{ {
Logger.WriteLog($"Download update cancelled: {ex.Message}"); Logger.WriteLog($"Update download cancelled: {ex.Message}");
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -189,38 +208,5 @@ namespace RHLauncher.RHLauncher
} }
} }
private static async Task<long> GetFileSizeAsync(HttpClient client, string fileUrl, CancellationToken cancellationToken)
{
using HttpRequestMessage request = new(HttpMethod.Get, fileUrl);
using HttpResponseMessage response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
response.EnsureSuccessStatusCode();
return response.Content.Headers.ContentLength ?? throw new Exception("Content-Length header not found in response headers.");
}
public static string FormatDownloadSpeed(double totalDownloadSpeed)
{
string[] sizes = { "B/s", "KB/s", "MB/s", "GB/s" };
int order = 0;
while (totalDownloadSpeed >= 1024 && order < sizes.Length - 1)
{
order++;
totalDownloadSpeed /= 1024;
}
return $"{totalDownloadSpeed:0.#} {sizes[order]}";
}
public static string FormatFileSize(long bytes)
{
string[] sizes = { "B", "KB", "MB", "GB" };
int order = 0;
while (bytes >= 1024 && order < sizes.Length - 1)
{
order++;
bytes /= 1024;
}
return $"{bytes:0.#} {sizes[order]}";
}
} }
} }

View file

@ -1,693 +0,0 @@
using Newtonsoft.Json;
using RHLauncher.Helper;
using RHLauncher.RHLauncher;
using RHLauncher.RHLauncher.Helper;
using System.Diagnostics;
using static RHLauncher.RHLauncher.UpdateDownloader;
using static RHLauncher.RHLauncher.UpdateInstaller;
using static RHLauncher.RHLauncher.UpdateUnpacker;
/*
Rusty Hearts Launcher - Windows Forms Implementation in C#
Author: JuniorDark
GitHub Repository: https://github.com/JuniorDark/RustyHearts-Launcher
This code serves as a starting point for creating your own launcher.
However, it requires further development to improve functionality and
ensure stability. Please check the GitHub repository for updates.
*/
namespace RHLauncher
{
public partial class LauncherForm : Form
{
private RegistryHandler registryHandler = new();
private readonly CancellationTokenSource? cancellationTokenSource;
public string? installDirectory;
private static readonly string DefaultIniFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "config.ini");
private readonly IniFile _iniFile = new(DefaultIniFilePath);
private readonly string _windyCode;
private readonly string _password;
private readonly Image[] images = {
Properties.Resources.character_select_cut_angela,
Properties.Resources.character_select_cut_edgar,
Properties.Resources.character_select_cut_frantz,
Properties.Resources.character_select_cut_ian,
Properties.Resources.character_select_cut_leila,
Properties.Resources.character_select_cut_meilinchen,
Properties.Resources.character_select_cut_natasha,
Properties.Resources.character_select_cut_roselle,
Properties.Resources.character_select_cut_tude
};
public LauncherForm(string windyCode, string password)
{
InitializeComponent();
LabelNews.Text = LocalizedStrings.LabelNews;
_windyCode = windyCode;
_password = password;
installDirectory = registryHandler.GetInstallDirectory();
}
#region Methods
private async void LauncherForm_Load(object sender, EventArgs e)
{
NameLabel.Text = LocalizedStrings.Welcome + ", " + _windyCode;
ChangeCharPictureBox();
getUpdatePanel.Hide();
if (string.IsNullOrEmpty(installDirectory))
{
LaunchOptionsButton.Enabled = false;
LaunchButton.Text = LocalizedStrings.Install;
LaunchButton.Click += (s, e) =>
{
Install();
};
}
else
{
var updater = new ServiceFileHandler("config.ini", installDirectory);
updater.UpdateService();
await CheckForUpdates();
}
await WebView2Async();
}
private async Task WebView2Async()
{
await webView21.EnsureCoreWebView2Async();
webView21.Source = new Uri(Configuration.Default.LauncherNewsUrl);
webView21.CoreWebView2.NavigationStarting += (sender, args) =>
{
// Check if the URL being navigated to is an external link
if (!args.Uri.ToString().StartsWith(Configuration.Default.LauncherNewsUrl))
{
// Cancel the navigation
args.Cancel = true;
// Launch the URL in the user's default browser
Process.Start(new ProcessStartInfo(args.Uri) { UseShellExecute = true });
}
};
}
private async void Install()
{
try
{
if (string.IsNullOrEmpty(installDirectory))
{
OpenFileDialog openFileDialog1 = new()
{
InitialDirectory = AppDomain.CurrentDomain.BaseDirectory,
Filter = "RustyHearts.exe|RustyHearts.exe",
Title = "Select RustyHearts.exe"
};
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
installDirectory = Path.GetDirectoryName(openFileDialog1.FileName);
registryHandler.SaveInstallDirectory(installDirectory);
await CheckForUpdates();
}
}
}
catch (Exception ex)
{
HandleException(ex);
}
}
private async Task CheckForUpdates()
{
try
{
LaunchButton.Enabled = false;
LaunchButton.Text = LocalizedStrings.Checking;
LaunchOptionsButton.Enabled = false;
switch (await CheckForUpdatesAsync())
{
case UpdateState.UpdateAvailable:
LaunchButton.Text = LocalizedStrings.Update;
LaunchButton.Enabled = true;
LaunchButton.Click -= LaunchGameButton_Click;
LaunchButton.Click += InstallUpdateButton_Click;
break;
case UpdateState.NoUpdateAvailable:
LaunchButton.Text = LocalizedStrings.Launch;
LaunchButton.Click -= LaunchGameButton_Click;
LaunchButton.Click += LaunchGameButton_Click;
break;
}
}
catch (Exception ex)
{
HandleException(ex);
}
finally
{
LaunchButton.Enabled = true;
LaunchOptionsButton.Enabled = true;
AccOptionsButton.Enabled = true;
}
}
private readonly SemaphoreSlim _semaphore = new(1);
public async Task InstallUpdate()
{
await _semaphore.WaitAsync();
_cancellationTokenSource = new CancellationTokenSource();
try
{
Progress<ProgressReport> progress = new(ReportProgress);
ProgressThrottler progressThrottler = new(progress, 200);
Progress<ProgressReport> packProgress = new(ReportInstallProgress);
ProgressThrottler packProgressThrottler = new(packProgress, 200);
await DownloadUpdatesAsync(installDirectory, progressThrottler, _cancellationTokenSource.Token);
await UnpackDownloadedFilesAsync(installDirectory, packProgressThrottler, _cancellationTokenSource.Token);
await PackDownloadedFilesAsync(installDirectory, packProgressThrottler, _cancellationTokenSource.Token);
}
catch (OperationCanceledException ex)
{
Logger.WriteLog($"Update installation canceled: {ex.Message}");
}
catch (Exception ex)
{
HandleException(ex);
}
finally
{
_semaphore.Release();
LaunchButton.Enabled = true;
LaunchOptionsButton.Enabled = true;
LaunchButton.Text = LocalizedStrings.Launch;
LaunchButton.Click -= InstallUpdateButton_Click;
LaunchButton.Click += LaunchGameButton_Click;
if (_cancellationTokenSource.IsCancellationRequested)
{
await CheckForUpdates();
}
}
}
private static void HandleException(Exception ex)
{
string errorMessage = ex.Message;
string errorLog = ex.Message + ex.StackTrace;
Exception newEx = new(errorMessage, ex);
Exception newLogEx = new(errorLog, ex);
ExceptionHandler.HandleException(newEx, newLogEx);
}
private void ReportProgress(ProgressReport progressReport)
{
if (InvokeRequired)
{
Invoke(new Action<ProgressReport>(ReportProgress), progressReport);
return;
}
FileNameLabel.Visible = progressReport.ShowFileNameLabel;
SpeedLabel.Visible = progressReport.ShowSpeedLabel;
TimeLabel.Visible = progressReport.ShowTimeLabel;
FileSizeLabel.Visible = progressReport.ShowFileSizeLabel;
FileCountLabel.Visible = progressReport.ShowFileCountLabel;
DownloadingLabel.Text = progressReport.Label;
PercentLabel.Text = $"{progressReport.PercentComplete}%";
progressBar1.Maximum = (int)progressReport.TotalBytesToDownload;
progressBar1.Value = (int)Math.Min(progressReport.BytesDownloaded, progressReport.TotalBytesToDownload);
FileNameLabel.Text = progressReport.FileName;
SpeedLabel.Text = FormatDownloadSpeed(progressReport.TotalSpeed);
TimeSpan t = TimeSpan.FromSeconds(progressReport.TimeLeft);
TimeLabel.Text = $"{t.Hours:00}:{t.Minutes:00}:{t.Seconds:00}";
FileSizeLabel.Text = $"({FormatFileSize(progressReport.BytesDownloaded)} / {FormatFileSize(progressReport.TotalBytesToDownload)})";
FileCountLabel.Text = $"({progressReport.NumFilesDownloaded}/{progressReport.TotalNumFiles})";
if (!string.IsNullOrEmpty(progressReport.FileName))
{
FileNameLabel.Refresh();
}
getUpdatePanel.Visible = progressReport.Panel;
}
private void ReportInstallProgress(ProgressReport progressReport)
{
if (InvokeRequired)
{
Invoke(new Action<ProgressReport>(ReportInstallProgress), progressReport);
return;
}
FileNameLabel.Visible = progressReport.ShowFileNameLabel;
SpeedLabel.Visible = progressReport.ShowSpeedLabel;
TimeLabel.Visible = progressReport.ShowTimeLabel;
FileSizeLabel.Visible = progressReport.ShowFileSizeLabel;
FileCountLabel.Visible = progressReport.ShowFileCountLabel;
DownloadingLabel.Text = progressReport.Label;
PercentLabel.Text = $"{progressReport.PercentComplete}%";
progressBar1.Maximum = progressReport.TotalNumFiles;
progressBar1.Value = progressReport.NumFilesPacked;
FileNameLabel.Text = progressReport.FileName;
FileCountLabel.Text = $"({progressReport.NumFilesPacked}/{progressReport.TotalNumFiles})";
if (!string.IsNullOrEmpty(progressReport.FileName))
{
FileNameLabel.Refresh();
}
getUpdatePanel.Visible = progressReport.Panel;
}
public void ChangeCharPictureBox()
{
Random rnd = new();
int index = rnd.Next(images.Length);
CharPictureBox.Image = images[index];
}
private static async Task<bool> CheckServerStatusAsync()
{
try
{
using HttpClient client = new();
using HttpResponseMessage response = await client.GetAsync(Configuration.Default.GateStatusUrl);
response.EnsureSuccessStatusCode();
string json = await response.Content.ReadAsStringAsync();
dynamic result = JsonConvert.DeserializeObject(json);
string status = result.status;
return (status == "online");
}
catch
{
return false;
}
}
private void CharPictureBox_Click(object sender, EventArgs e)
{
ChangeCharPictureBox();
}
private static void HidePanel(Panel panel)
{
if (panel.Visible)
{
panel.Visible = false;
}
}
private void HidePanels()
{
HidePanel(AccPanel);
HidePanel(LaunchPanel);
HidePanel(InstallPanel);
}
#endregion
#region Button Click Events
private CancellationTokenSource? _cancellationTokenSource;
private void StopButton_Click(object sender, EventArgs e)
{
_cancellationTokenSource?.Cancel();
getUpdatePanel.Visible = false;
LaunchButton.Text = LocalizedStrings.Cancelling;
LaunchButton.Click -= InstallUpdateButton_Click;
}
private async void InstallUpdateButton_Click(object? sender, EventArgs e)
{
try
{
LaunchButton.Text = LocalizedStrings.Updating;
LaunchButton.Enabled = false;
LaunchOptionsButton.Enabled = false;
await InstallUpdate();
}
catch (Exception ex)
{
HandleException(ex);
}
}
private async void LaunchGameButton_Click(object? sender, EventArgs e)
{
try
{
HidePanels();
LaunchButton.Text = LocalizedStrings.Launching;
LaunchButton.Enabled = false;
LaunchOptionsButton.Enabled = false;
AccOptionsButton.Enabled = false;
// Check if RustyHearts.exe is already running
if (Process.GetProcessesByName("RustyHearts").Length > 0)
{
MsgBoxForm.Show(LocalizedStrings.AlreadyExecute, LocalizedStrings.Error);
await CheckForUpdates();
return;
}
// Check if server is online
bool serverOnline = await CheckServerStatusAsync();
if (!serverOnline)
{
MsgBoxForm.Show(LocalizedStrings.ServerOffline, LocalizedStrings.Error);
await CheckForUpdates();
return;
}
LaunchButton.Text = LocalizedStrings.Running;
LaunchButton.Enabled = false;
LaunchOptionsButton.Enabled = false;
AccOptionsButton.Enabled = false;
string service = _iniFile.ReadValue("Info", "Service");
string arguments = string.Empty;
switch (service.ToLower())
{
case "usa":
arguments = "server=" + Configuration.Default.GateXMLUrl;
break;
case "chn":
arguments = $"-serverurl{Configuration.Default.GateInfoUrl} id={_windyCode} password={_password}";
break;
default:
// handle unsupported service
MsgBoxForm.Show(LocalizedStrings.UnsupportedService, LocalizedStrings.Error);
await CheckForUpdates();
return;
}
ProcessStartInfo startInfo = new()
{
FileName = Path.Combine(installDirectory, "RustyHearts.exe"),
Arguments = arguments,
WorkingDirectory = installDirectory
};
Process? process = Process.Start(startInfo);
WindowState = FormWindowState.Minimized;
await process.WaitForExitAsync();
WindowState = FormWindowState.Maximized;
await CheckForUpdates();
}
catch (Exception ex)
{
HandleException(ex);
}
}
private void OnMouseDown(object sender, MouseEventArgs e)
{
HidePanels();
if (e.Button == MouseButtons.Left)
{
FormUtils.MoveForm(Handle);
}
}
private void CloseButton_Click(object sender, EventArgs e)
{
Close();
}
private void MinimizeButton_Click(object sender, EventArgs e)
{
WindowState = FormWindowState.Minimized;
}
private void LauncherForm_FormClosing(object sender, FormClosingEventArgs e)
{
if (e.CloseReason == CloseReason.UserClosing)
{
Application.Exit();
}
}
private void LogoutButton_Click(object sender, EventArgs e)
{
HidePanels();
DialogResult result = MsgBoxForm.ShowYN(LocalizedStrings.LogoutText, LocalizedStrings.Confirmation);
if (result == DialogResult.Yes)
{
registryHandler = new RegistryHandler();
registryHandler.SaveValues(_windyCode, "", false, false);
Logout();
}
}
public void Logout()
{
LoginForm? loginForm = Application.OpenForms.OfType<LoginForm>().FirstOrDefault();
if (loginForm != null)
{
Application.Restart();
}
else
{
LoginForm newLoginForm = new();
newLoginForm.Show();
Close();
}
}
private async void UpdateCheckButton_Click(object sender, EventArgs e)
{
HidePanels();
await CheckForUpdates();
}
private async void InstallButton_Click(object? sender, EventArgs e)
{
HidePanels();
OpenFileDialog openFileDialog1 = new()
{
InitialDirectory = AppDomain.CurrentDomain.BaseDirectory,
Filter = "RustyHearts.exe|RustyHearts.exe",
Title = "Select RustyHearts.exe"
};
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
installDirectory = Path.GetDirectoryName(openFileDialog1.FileName);
registryHandler.SaveInstallDirectory(installDirectory);
await CheckForUpdates();
}
}
private void ManageButton_Click(object sender, EventArgs e)
{
InstallPanel.Visible = !InstallPanel.Visible;
}
private void OpenInstallDirButton_Click(object sender, EventArgs e)
{
HidePanels();
if (!string.IsNullOrEmpty(installDirectory))
{
Process.Start("explorer.exe", installDirectory);
}
}
private void OpenSettingsButton_Click(object sender, EventArgs e)
{
HidePanels();
if (!string.IsNullOrEmpty(installDirectory))
{
string rustyHeartsConfigPath = Path.Combine(installDirectory, "rustyheartsconfig.exe");
if (File.Exists(rustyHeartsConfigPath))
{
ProcessStartInfo startInfo = new()
{
FileName = rustyHeartsConfigPath,
WorkingDirectory = installDirectory
};
Process.Start(startInfo);
}
else
{
MsgBoxForm.Show(LocalizedStrings.rustyheartsconfig, LocalizedStrings.Error);
}
}
}
private void UninstallButton_Click(object sender, EventArgs e)
{
HidePanels();
if (!string.IsNullOrEmpty(installDirectory))
{
DialogResult result = MsgBoxForm.ShowYN(LocalizedStrings.ConfirmUninstallText, LocalizedStrings.ConfirmUninstall);
if (result == DialogResult.Yes)
{
try
{
LaunchButton.Enabled = false;
LaunchOptionsButton.Enabled = false;
LaunchButton.Text = LocalizedStrings.Uninstalling;
Directory.Delete(installDirectory, true);
MsgBoxForm.Show(LocalizedStrings.UninstallText, LocalizedStrings.Uninstall);
registryHandler.ClearInstallDirectory();
LaunchButton.Enabled = true;
LaunchButton.Text = LocalizedStrings.Install;
LaunchButton.Click -= LaunchGameButton_Click;
LaunchButton.Click += InstallButton_Click;
}
catch (Exception ex)
{
HandleException(ex);
}
}
}
}
private void ChangePwdButton_Click(object sender, EventArgs e)
{
HidePanels();
ChangePwd changePwd = new(true);
changePwd.FormClosing += ChangePwd_FormClosing;
changePwd.ShowDialog();
}
private async void ChangePwd_FormClosing(object sender, FormClosingEventArgs e)
{
if (sender is ChangePwd changePwd)
{
changePwd.Dispose();
}
}
private void LaunchOptionsButton_Click(object sender, EventArgs e)
{
LaunchPanel.Visible = !LaunchPanel.Visible;
if (InstallPanel.Visible)
{
InstallPanel.Visible = false;
}
}
#endregion
#region Button Events
private void MenuButton_MouseHover(object sender, EventArgs e)
{
Button button = (Button)sender;
button.ImageIndex = 1;
}
private void MenuButton_MouseLeave(object sender, EventArgs e)
{
Button button = (Button)sender;
button.ImageIndex = 0;
}
private void MenuButton_MouseDown(object sender, MouseEventArgs e)
{
Button button = (Button)sender;
button.ImageIndex = 2;
}
private void AccOptionsButton_Click(object sender, EventArgs e)
{
AccPanel.Visible = !AccPanel.Visible;
}
private void MinimizeButton_MouseHover(object sender, EventArgs e)
{
MinimizeButton.ImageIndex = 1;
}
private void MinimizeButton_MouseLeave(object sender, EventArgs e)
{
MinimizeButton.ImageIndex = 0;
}
private void MinimizeButton_OnMouseDown(object sender, MouseEventArgs e)
{
MinimizeButton.ImageIndex = 2;
}
private void CloseButton_MouseHover(object sender, EventArgs e)
{
CloseButton.ImageIndex = 1;
}
private void CloseButton_MouseLeave(object sender, EventArgs e)
{
CloseButton.ImageIndex = 0;
}
private void CloseButton_OnMouseDown(object sender, MouseEventArgs e)
{
CloseButton.ImageIndex = 2;
}
private void LaunchButton_MouseHover(object sender, EventArgs e)
{
LaunchButton.ImageIndex = 1;
}
private void LaunchButton_MouseLeave(object sender, EventArgs e)
{
LaunchButton.ImageIndex = 0;
}
private void LaunchButton_OnMouseDown(object sender, MouseEventArgs e)
{
LaunchButton.ImageIndex = 2;
}
private void AccOptionsButton_MouseHover(object sender, EventArgs e)
{
AccOptionsButton.ImageIndex = 1;
}
private void AccOptionsButton_MouseLeave(object sender, EventArgs e)
{
AccOptionsButton.ImageIndex = 0;
}
private void LaunchOptionsButton_MouseHover(object sender, EventArgs e)
{
LaunchOptionsButton.ImageIndex = 1;
}
private void LaunchOptionsButton_MouseLeave(object sender, EventArgs e)
{
LaunchOptionsButton.ImageIndex = 0;
}
private void LaunchOptionsButton_OnMouseDown(object sender, MouseEventArgs e)
{
LaunchOptionsButton.ImageIndex = 2;
}
private void StopButton_MouseHover(object sender, EventArgs e)
{
StopButton.ImageIndex = 1;
}
private void StopButton_MouseLeave(object sender, EventArgs e)
{
StopButton.ImageIndex = 0;
}
private void StopButton_OnMouseDown(object sender, MouseEventArgs e)
{
StopButton.ImageIndex = 2;
}
#endregion
}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,70 +0,0 @@
using System.IO.Compression;
namespace RHLauncher
{
internal class MIPDecoder
{
private static readonly byte[] codeMip = new byte[] {
0x30, 0x22, 0x41, 0xa8, 0x5b, 0xa6, 0x6a, 0x49, 0xbf, 0x53, 0x35, 0xe5, 0x9e, 14, 0xec, 0xb8,
0x5e, 0x15, 0x1f, 0xc1, 0x4f, 0xec, 0x77, 0xe8, 0xb7, 0x4e, 0x87, 230, 0xf5, 60, 0xb3, 0x43,
0xcc, 0x53, 0x36, 0xac, 90, 0x77, 0xb8, 0xdd, 0x30, 0x74, 140, 0x4a, 0x9a, 0x9b, 0xbc, 10,
0xa4, 0xad, 0xbb, 0x13, 0x4b, 140, 0xd4, 0x80, 0xce, 0x65, 0x1d, 8, 90, 0x6a, 0x6f, 0x25,
0xf9, 0x3f, 0xef, 0x1b, 0xa4, 0x72, 20, 0xed, 0x97, 0x22, 0x4a, 0x2e, 0xb8, 150, 0x4b, 0x8e,
150, 0x93, 0xf1, 40, 0xb2, 11, 60, 0xf8, 0x5d, 170, 0xa9, 130, 0x13, 110, 0xc1, 0xa9,
0x20, 0x57, 0xb2, 0x5b, 0x16, 0xcf, 0x9e, 0x5f, 0xd4, 0xcc, 0x2e, 0xf5, 0xc9, 0x4c, 0x1c, 0xee,
0xe3, 0x3f, 0x29, 0xb3, 6, 0x70, 0x43, 0x3d, 0xf5, 0x90, 0xa2, 0x42, 2, 0x98, 80, 0xfd,
0x5d, 0x4e, 0x92, 0xad, 0xad, 0x7f, 0xab, 0x60, 0x2c, 0xb8, 0x43, 0x76, 0x8f, 0x5f, 230, 0xa7,
0x19, 0xe0, 0xb9, 0xb5, 0x62, 0x6b, 0xd4, 0x47, 0x69, 0x34, 14, 0x6d, 0xa4, 0x52, 0xe3, 100,
0x4a, 0x65, 0x47, 0xf5, 0x3f, 0x53, 0x5e, 0x8b, 0x1b, 0xfd, 0x21, 0xf7, 0xba, 0x68, 0xf9, 0xdf,
0x68, 0xa8, 150, 15, 0x8b, 1, 0x97, 0x58, 140, 30, 0xef, 0xb3, 0x41, 0x44, 0x21, 0xda,
0xe0, 0xf4, 0xe0, 0x2d, 0xcd, 11, 240, 0x5c, 0x59, 0xd6, 0x99, 0xe7, 1, 0x15, 0x67, 50,
0xe0, 0x12, 0x2f, 0xcd, 0xa2, 0xde, 0x52, 0xce, 0xec, 0xef, 0x77, 14, 0xbc, 0x38, 100, 0x8d,
180, 0xdb, 0x67, 0xff, 200, 0x66, 12, 0x8a, 0x60, 0xe1, 0x2e, 0, 0x43, 0xa9, 0x37, 0x9c,
0x11, 170, 0xb9, 0x98, 0xed, 0x21, 0x35, 0xd4, 0xc3, 0xde, 0x65, 0x54, 0x9d, 0x1c, 0xb0, 0xa9
};
private static void BytesWithCodeMip(byte[] toBytes)
{
for (int i = 0; i < toBytes.Length; i++)
{
toBytes[i] = (byte)(toBytes[i] ^ codeMip[i & 0xff]);
}
}
public static async Task DecompressFileAsync(string filePath, string outputPath, CancellationToken cancellationToken)
{
byte[] buffer;
using (FileStream fileStream = new(filePath, FileMode.Open, FileAccess.Read))
{
buffer = new byte[fileStream.Length];
await fileStream.ReadAsync(buffer, 0, (int)fileStream.Length, cancellationToken);
}
BytesWithCodeMip(buffer);
buffer = DecompressBytes(buffer);
using FileStream outputFileStream = new(outputPath, FileMode.Create, FileAccess.Write);
await outputFileStream.WriteAsync(buffer, 0, buffer.Length, cancellationToken);
}
private static byte[] DecompressBytes(byte[] toBytes)
{
using MemoryStream inputStream = new(toBytes);
using DeflateStream deflateStream = new(inputStream, CompressionMode.Decompress);
using MemoryStream outputStream = new();
deflateStream.CopyTo(outputStream);
return outputStream.ToArray();
}
//Zlib have issues with some files
private static byte[] DecompressBytes1(byte[] toBytes)
{
int num = (toBytes.Length << 4) - toBytes.Length;
byte[] buffer = new byte[num];
int err = ZLibDll.Decompress(toBytes, toBytes.Length, buffer, ref num);
if (err != 0) throw new Exception(string.Format("Decompress returned error code {0}.", err));
toBytes = new byte[num];
Buffer.BlockCopy(buffer, 0, toBytes, 0, num);
return toBytes;
}
}
}

View file

@ -1,4 +1,4 @@
namespace RHLauncher.PCK namespace RHLauncher.RHLauncher.PCK
{ {
public class PCKFile public class PCKFile
{ {
@ -12,10 +12,6 @@
public long Offset { get; private set; } public long Offset { get; private set; }
public bool IsChecked { get; set; }
public string[] PathElements { get { return Name.Split(new char[] { '\\' }); } }
public PCKFile(string name, byte archive, int size, uint hash, long offset) public PCKFile(string name, byte archive, int size, uint hash, long offset)
{ {
Name = name; Name = name;

View file

@ -1,22 +1,9 @@
namespace RHLauncher.PCK namespace RHLauncher.RHLauncher.PCK
{ {
public class PCKFileNode public class PCKFileNode
{ {
public string Name { get; private set; } public string Name { get; private set; }
public PCKFile PCKFile { get; set; } public PCKFile PCKFile { get; set; }
public bool IsDir { get { return PCKFile == null; } }
public SortedDictionary<string, PCKFileNode> Nodes { get; set; }
private bool isChecked;
public bool IsChecked
{
get { return isChecked; }
set
{
isChecked = value;
if (PCKFile != null) PCKFile.IsChecked = isChecked;
}
}
public PCKFileNode(string name, PCKFile file) public PCKFileNode(string name, PCKFile file)
{ {

View file

@ -1,12 +1,11 @@
using RHLauncher.Helper; using System.IO.Compression;
using RHLauncher.RHLauncher.Helper; using RHLauncher.RHLauncher.Helper;
using System.Text; using System.Text;
namespace RHLauncher.PCK namespace RHLauncher.RHLauncher.PCK
{ {
public static class PCKReader public static class PCKReader
{ {
public static readonly byte[] BufferTable = new byte[] public static readonly byte[] BufferTable = new byte[]
{ {
0x30, 0x22, 0x41, 0xA8, 0x5B, 0xA6, 0x6A, 0x49, 0xBF, 0x53, 0x35, 0xE5, 0x9E, 0x0E, 0xEC, 0xB8, 0x5E, 0x15, 0x1F, 0xC1, 0x4F, 0xEC, 0x77, 0xE8, 0xB7, 0x4E, 0x87, 0xE6, 0xF5, 0x3C, 0xB3, 0x43 0x30, 0x22, 0x41, 0xA8, 0x5B, 0xA6, 0x6A, 0x49, 0xBF, 0x53, 0x35, 0xE5, 0x9E, 0x0E, 0xEC, 0xB8, 0x5E, 0x15, 0x1F, 0xC1, 0x4F, 0xEC, 0x77, 0xE8, 0xB7, 0x4E, 0x87, 0xE6, 0xF5, 0x3C, 0xB3, 0x43
@ -30,19 +29,20 @@ namespace RHLauncher.PCK
compressedBytes = compressedBytes.Select((b, i) => (byte)(b ^ BufferTable[i & 0xFF])).ToArray(); compressedBytes = compressedBytes.Select((b, i) => (byte)(b ^ BufferTable[i & 0xFF])).ToArray();
int decompressedSize = (compressedBytes.Length << 4) - compressedBytes.Length;
byte[] decompressedBytes = new byte[decompressedSize];
int result = ZLibDll.Decompress(compressedBytes, compressedBytes.Length, decompressedBytes, ref decompressedSize);
if (result != 0) throw new Exception("Error decoding f00x.dat");
List<PCKFile> pckFileList = new(100000); List<PCKFile> pckFileList = new(100000);
using (MemoryStream memoryStream = new(decompressedBytes, 0, decompressedSize, false)) string fileName = string.Empty;
try
{ {
using BinaryReader binaryReader = new(memoryStream); using MemoryStream compressedStream = new(compressedBytes);
using ZLibStream deflateStream = new(compressedStream, CompressionMode.Decompress);
using MemoryStream decompressedStream = new();
deflateStream.CopyTo(decompressedStream);
decompressedStream.Seek(0, SeekOrigin.Begin);
using BinaryReader binaryReader = new(decompressedStream);
while (binaryReader.BaseStream.Position < binaryReader.BaseStream.Length) while (binaryReader.BaseStream.Position < binaryReader.BaseStream.Length)
{ {
string fileName = string.Empty;
try try
{ {
ushort nameLength = binaryReader.ReadUInt16(); ushort nameLength = binaryReader.ReadUInt16();
@ -74,11 +74,17 @@ namespace RHLauncher.PCK
} }
} }
} }
catch (Exception ex)
{
string errorMessage = $"Error decompressing PCK file: {ex.Message}";
string errorLog = $"Error decompressing PCK file: {ex.Message}|{ex.StackTrace}";
Exception newEx = new(errorMessage, ex);
Exception newLogEx = new(errorLog, ex);
ExceptionHandler.HandleException(newEx, newLogEx);
}
return pckFileList; return pckFileList;
} }
} }
} }

View file

@ -1,262 +0,0 @@
using Newtonsoft.Json;
using RHLauncher.Helper;
using System.Text;
namespace RHLauncher.PCK
{
public static class PCKWriter
{
private static readonly byte[] BufferTable = new byte[] {
0x30, 0x22, 0x41, 0xa8, 0x5b, 0xa6, 0x6a, 0x49, 0xbf, 0x53, 0x35, 0xe5, 0x9e, 14, 0xec, 0xb8,
0x5e, 0x15, 0x1f, 0xc1, 0x4f, 0xec, 0x77, 0xe8, 0xb7, 0x4e, 0x87, 230, 0xf5, 60, 0xb3, 0x43,
0xcc, 0x53, 0x36, 0xac, 90, 0x77, 0xb8, 0xdd, 0x30, 0x74, 140, 0x4a, 0x9a, 0x9b, 0xbc, 10,
0xa4, 0xad, 0xbb, 0x13, 0x4b, 140, 0xd4, 0x80, 0xce, 0x65, 0x1d, 8, 90, 0x6a, 0x6f, 0x25,
0xf9, 0x3f, 0xef, 0x1b, 0xa4, 0x72, 20, 0xed, 0x97, 0x22, 0x4a, 0x2e, 0xb8, 150, 0x4b, 0x8e,
150, 0x93, 0xf1, 40, 0xb2, 11, 60, 0xf8, 0x5d, 170, 0xa9, 130, 0x13, 110, 0xc1, 0xa9,
0x20, 0x57, 0xb2, 0x5b, 0x16, 0xcf, 0x9e, 0x5f, 0xd4, 0xcc, 0x2e, 0xf5, 0xc9, 0x4c, 0x1c, 0xee,
0xe3, 0x3f, 0x29, 0xb3, 6, 0x70, 0x43, 0x3d, 0xf5, 0x90, 0xa2, 0x42, 2, 0x98, 80, 0xfd,
0x5d, 0x4e, 0x92, 0xad, 0xad, 0x7f, 0xab, 0x60, 0x2c, 0xb8, 0x43, 0x76, 0x8f, 0x5f, 230, 0xa7,
0x19, 0xe0, 0xb9, 0xb5, 0x62, 0x6b, 0xd4, 0x47, 0x69, 0x34, 14, 0x6d, 0xa4, 0x52, 0xe3, 100,
0x4a, 0x65, 0x47, 0xf5, 0x3f, 0x53, 0x5e, 0x8b, 0x1b, 0xfd, 0x21, 0xf7, 0xba, 0x68, 0xf9, 0xdf,
0x68, 0xa8, 150, 15, 0x8b, 1, 0x97, 0x58, 140, 30, 0xef, 0xb3, 0x41, 0x44, 0x21, 0xda,
0xe0, 0xf4, 0xe0, 0x2d, 0xcd, 11, 240, 0x5c, 0x59, 0xd6, 0x99, 0xe7, 1, 0x15, 0x67, 50,
0xe0, 0x12, 0x2f, 0xcd, 0xa2, 0xde, 0x52, 0xce, 0xec, 0xef, 0x77, 14, 0xbc, 0x38, 100, 0x8d,
180, 0xdb, 0x67, 0xff, 200, 0x66, 12, 0x8a, 0x60, 0xe1, 0x2e, 0, 0x43, 0xa9, 0x37, 0x9c,
0x11, 170, 0xb9, 0x98, 0xed, 0x21, 0x35, 0xd4, 0xc3, 0xde, 0x65, 0x54, 0x9d, 0x1c, 0xb0, 0xa9
};
private static readonly uint[] CodeHash = new uint[]
{
0, 0x77073096, 0xee0e612c, 0x990951ba, 0x76dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0xedb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x9b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
0x76dc4190, 0x1db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x6b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0xf00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x86d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
0xedb88320, 0x9abfb3b6, 0x3b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x4db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0xd6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0xa00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x26d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x5005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0xcb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0xbdbdf21,
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
public static uint BytesWithCodeHash(byte[] toBytes)
{
int num = -1;
for (int i = 0; i < toBytes.Length; i++)
{
num = (int)CodeHash[num & 0xff ^ toBytes[i]] ^ num >> 8 & 0xffffff;
}
return (uint)num;
}
public delegate void GetFilesDelegate(string path, bool isComplete);
public static List<string> GetFiles(string dir, GetFilesDelegate gfDelegate)
{
List<string> listFile = new();
foreach (string file in Directory.EnumerateFiles(dir, "*", SearchOption.AllDirectories))
{
if (File.GetAttributes(file).HasFlag(FileAttributes.Directory))
{
continue;
}
listFile.Add(file);
gfDelegate(file, false);
}
return listFile;
}
public delegate void PackingDelegate(string fileName, int pos, int count);
public static async Task Packing(string rootDir, List<string> listFile, List<PCKFile> listPckFile, bool replace, PackingDelegate pDelegate, CancellationToken cancellationToken)
{
RegistryHandler registryHandler = new();
string installDirectory = registryHandler.GetInstallDirectory();
SortedDictionary<string, PCKFile> dicPckFile = new();
foreach (PCKFile file in listPckFile)
{
dicPckFile.Add(file.Name, file);
}
SortedDictionary<string, string> dicInputFile = new();
string s = rootDir.Substring(rootDir.Length - 1, 1);
if (s != "\\") rootDir += "\\";
foreach (string file in listFile)
{
dicInputFile.Add(file.Replace(rootDir, ""), file);
}
Dictionary<int, FileStream> archives = new(10);
Dictionary<int, BinaryWriter> writers = new(10);
try
{
for (int i = 0; i < 10; i++)
{
string pathPCK = Path.Combine(installDirectory, string.Format("{0:000}.pck", i));
FileMode mode = File.Exists(pathPCK) ? FileMode.Open : FileMode.Create;
FileStream ofs = new(pathPCK, mode, FileAccess.Write);
ofs.Position = ofs.Length;
BinaryWriter obr = new(ofs);
archives.Add(i, ofs);
writers.Add(i, obr);
}
// Read the f00x.dat file to get the archive numbers
Dictionary<string, int> dicArchive = new();
string pathF00X = Path.Combine(installDirectory, "f00x.dat");
if (File.Exists(pathF00X))
{
byte[] buffer = await File.ReadAllBytesAsync(pathF00X);
int numDecompressed = buffer.Length << 4;
byte[] decompressed = new byte[numDecompressed];
int result = ZLibDll.Decompress(buffer, buffer.Length, decompressed, ref numDecompressed);
if (result == 0)
{
string json = Encoding.UTF8.GetString(decompressed);
dicArchive = JsonConvert.DeserializeObject<Dictionary<string, int>>(json);
}
}
int pos = 0;
int count = dicInputFile.Count;
foreach (KeyValuePair<string, string> file in dicInputFile)
{
if (cancellationToken.IsCancellationRequested)
{
WriteF00XDAT(dicPckFile);
throw new OperationCanceledException();
}
pos++;
pDelegate(file.Key, pos, count);
PCKFile? pckFile = null;
if (dicPckFile.ContainsKey(file.Key))
{
if (!replace) continue;
pckFile = dicPckFile[file.Key];
}
if (!File.Exists(file.Value)) continue;
byte[] fileBytes;
using (FileStream fileStream = File.OpenRead(file.Value))
{
fileStream.Seek(0, SeekOrigin.Begin);
fileBytes = new byte[fileStream.Length];
await fileStream.ReadAsync(fileBytes, 0, fileBytes.Length);
}
uint fileHash = BytesWithCodeHash(fileBytes);
int arc = 0;
if (pckFile != null)
{
if (pckFile.Hash == fileHash) continue;
arc = pckFile.Archive;
dicPckFile.Remove(file.Key);
}
else
{
if (dicArchive.ContainsKey(file.Key)) arc = dicArchive[file.Key];
else
{
long pckLen = archives[0].Length;
for (byte i = 1; i < 10; i++)
{
long x = archives[i].Length;
if (x < pckLen)
{
pckLen = x;
arc = i;
}
}
}
}
pckFile = new PCKFile(file.Key, (byte)arc, fileBytes.Length, fileHash, archives[arc].Length);
dicPckFile.Add(file.Key, pckFile);
BinaryWriter bw = writers[pckFile.Archive];
bw.Write(fileBytes);
bw.Flush();
}
WriteF00XDAT(dicPckFile);
}
catch (Exception)
{
throw;
}
finally
{
foreach (KeyValuePair<int, FileStream> kvp in archives)
{
kvp.Value.Close();
kvp.Value.Dispose();
}
listFile.Clear();
listPckFile.Clear();
}
}
public static void WriteF00XDAT(SortedDictionary<string, PCKFile> dicPckFile)
{
try
{
RegistryHandler registryHandler = new();
string installDirectory = registryHandler.GetInstallDirectory();
byte[]? bufferF00XDAT = null;
using (MemoryStream streamF00X = new())
{
using BinaryWriter writerF00X = new(streamF00X);
foreach (KeyValuePair<string, PCKFile> kvFile in dicPckFile)
{
PCKFile pckFile = kvFile.Value;
byte[] bytes = Encoding.Unicode.GetBytes(pckFile.Name);
int numNameLen = Convert.ToInt32(bytes.Length / 2);
writerF00X.Write((ushort)numNameLen);
writerF00X.Write(bytes);
writerF00X.Write(pckFile.Archive);
writerF00X.Write((uint)pckFile.FileSize);
writerF00X.Write(pckFile.Hash);
writerF00X.Write((ulong)pckFile.Offset);
}
writerF00X.Flush();
bufferF00XDAT = streamF00X.ToArray();
}
int numCompress = (bufferF00XDAT.Length >> 4) + bufferF00XDAT.Length;
byte[] bufferCompress = new byte[numCompress];
if (ZLibDll.Compress(bufferF00XDAT, bufferF00XDAT.Length, bufferCompress, ref numCompress) == 0)
{
for (int i = 0; i < numCompress; i++)
{
bufferCompress[i] = (byte)(bufferCompress[i] ^ BufferTable[i & 0xff]);
}
string pathF00XDAT = Path.Combine(installDirectory, "f00X.dat");
File.Delete(pathF00XDAT + ".old");
File.Move(pathF00XDAT, pathF00XDAT + ".old");
using FileStream streamF00XDAT = new(pathF00XDAT, FileMode.Create, FileAccess.Write);
using BinaryWriter writerF00XDAT = new(streamF00XDAT);
writerF00XDAT.Write(bufferCompress, 0, numCompress);
writerF00XDAT.Flush();
}
}
catch (Exception)
{
throw;
}
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup Label="Globals"> <PropertyGroup Label="Globals">
<WebView2LoaderPreference>Static</WebView2LoaderPreference> <WebView2LoaderPreference>Static</WebView2LoaderPreference>
@ -6,7 +6,7 @@
<PropertyGroup> <PropertyGroup>
<OutputType>WinExe</OutputType> <OutputType>WinExe</OutputType>
<TargetFramework>net7.0-windows7.0</TargetFramework> <TargetFramework>net9.0-windows</TargetFramework>
<SatelliteResourceLanguages>en</SatelliteResourceLanguages> <SatelliteResourceLanguages>en</SatelliteResourceLanguages>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<UseWindowsForms>true</UseWindowsForms> <UseWindowsForms>true</UseWindowsForms>
@ -18,9 +18,9 @@
<Product>Rusty Hearts Launcher</Product> <Product>Rusty Hearts Launcher</Product>
<AssemblyName>Launcher</AssemblyName> <AssemblyName>Launcher</AssemblyName>
<Description>Rusty Hearts Launcher</Description> <Description>Rusty Hearts Launcher</Description>
<PlatformTarget>x86</PlatformTarget> <PlatformTarget>x64</PlatformTarget>
<AssemblyVersion>1.0.0</AssemblyVersion> <AssemblyVersion>1.4.0</AssemblyVersion>
<FileVersion>1.0.0</FileVersion> <FileVersion>1.4.0</FileVersion>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
@ -31,34 +31,23 @@
<DebugType>full</DebugType> <DebugType>full</DebugType>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<None Remove="RHLauncher.LauncherForm\LauncherForm.resx~RF3c0dbfb.TMP" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<Content Include="Resources\rhicon.ico" /> <Content Include="Resources\rhicon.ico" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.1774.30" /> <PackageReference Include="Microsoft.Web.WebView2" Version="1.0.3179.45" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="WindowsAPICodePack" Version="8.0.6" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Update="RegForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Update="Properties\Resources.Designer.cs"> <Compile Update="Properties\Resources.Designer.cs">
<DesignTime>True</DesignTime> <DesignTime>True</DesignTime>
<AutoGen>True</AutoGen> <AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon> <DependentUpon>Resources.resx</DependentUpon>
</Compile> </Compile>
<Compile Update="Properties\Settings.Designer.cs"> <Compile Update="RHLauncher.i8n\LocalizedStrings.Designer.cs">
<DesignTimeSharedInput>True</DesignTimeSharedInput>
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
</Compile>
<Compile Update="RHLauncher\LocalizedStrings.Designer.cs">
<DesignTime>True</DesignTime> <DesignTime>True</DesignTime>
<AutoGen>True</AutoGen> <AutoGen>True</AutoGen>
<DependentUpon>LocalizedStrings.resx</DependentUpon> <DependentUpon>LocalizedStrings.resx</DependentUpon>
@ -70,19 +59,15 @@
<Generator>ResXFileCodeGenerator</Generator> <Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput> <LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource> </EmbeddedResource>
<EmbeddedResource Update="RHLauncher\LocalizedStrings.resx"> <EmbeddedResource Update="RHLauncher.i8n\LocalizedStrings.ko.resx">
<Generator>PublicResXFileCodeGenerator</Generator>
</EmbeddedResource>
<EmbeddedResource Update="RHLauncher.i8n\LocalizedStrings.resx">
<Generator>PublicResXFileCodeGenerator</Generator> <Generator>PublicResXFileCodeGenerator</Generator>
<LastGenOutput>LocalizedStrings.Designer.cs</LastGenOutput> <LastGenOutput>LocalizedStrings.Designer.cs</LastGenOutput>
</EmbeddedResource> </EmbeddedResource>
</ItemGroup> </ItemGroup>
<ItemGroup>
<None Update="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
</ItemGroup>
<PropertyGroup> <PropertyGroup>
<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract> <IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
<Authors>Rusty Hearts Launcher</Authors> <Authors>Rusty Hearts Launcher</Authors>

View file

@ -0,0 +1,44 @@
using System.Globalization;
using System.Resources;
namespace RHLauncher.RHLauncher.i8n
{
public class LocalizationHelper
{
public static void LoadLocalizedStrings(
string lang,
List<Button> buttons,
List<ImageList> imageLists,
Dictionary<string, List<ImageList>> languageImageLists)
{
CultureInfo cultureInfo;
if (languageImageLists.TryGetValue(lang, out List<ImageList>? value))
{
// If the language is supported, get the corresponding image lists
List<ImageList> langSpecificImageLists = value;
for (int i = 0; i < buttons.Count && i < langSpecificImageLists.Count; i++)
{
buttons[i].ImageList = langSpecificImageLists[i];
}
cultureInfo = new CultureInfo(lang);
}
else
{
// Default to English if the language is not supported
cultureInfo = new CultureInfo("en-US"); // English culture
for (int i = 0; i < buttons.Count && i < imageLists.Count; i++)
{
buttons[i].ImageList = imageLists[i];
}
}
Thread.CurrentThread.CurrentUICulture = cultureInfo;
// Load the appropriate resource file based on the selected language
_ = new
ResourceManager(typeof(LocalizedStrings));
LocalizedStrings.Culture = cultureInfo;
}
}
}

View file

@ -8,7 +8,7 @@
// </auto-generated> // </auto-generated>
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
namespace RHLauncher.RHLauncher { namespace RHLauncher.RHLauncher.i8n {
using System; using System;
@ -39,7 +39,7 @@ namespace RHLauncher.RHLauncher {
public static global::System.Resources.ResourceManager ResourceManager { public static global::System.Resources.ResourceManager ResourceManager {
get { get {
if (object.ReferenceEquals(resourceMan, null)) { if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("RHLauncher.RHLauncher.LocalizedStrings", typeof(LocalizedStrings).Assembly); global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("RHLauncher.RHLauncher.i8n.LocalizedStrings", typeof(LocalizedStrings).Assembly);
resourceMan = temp; resourceMan = temp;
} }
return resourceMan; return resourceMan;
@ -69,6 +69,60 @@ namespace RHLauncher.RHLauncher {
} }
} }
/// <summary>
/// Looks up a localized string similar to Account created successfully..
/// </summary>
public static string AccountCreateSuccess {
get {
return ResourceManager.GetString("AccountCreateSuccess", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Account Details.
/// </summary>
public static string AccountDetails {
get {
return ResourceManager.GetString("AccountDetails", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Account Email.
/// </summary>
public static string AccountEmail {
get {
return ResourceManager.GetString("AccountEmail", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to A account with this email already exists..
/// </summary>
public static string AccountEmailExists {
get {
return ResourceManager.GetString("AccountEmailExists", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to A account with this username already exists..
/// </summary>
public static string AccountExists {
get {
return ResourceManager.GetString("AccountExists", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Account Name.
/// </summary>
public static string AccountName {
get {
return ResourceManager.GetString("AccountName", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to A account with this email was not found. /// Looks up a localized string similar to A account with this email was not found.
/// </summary> /// </summary>
@ -78,6 +132,15 @@ namespace RHLauncher.RHLauncher {
} }
} }
/// <summary>
/// Looks up a localized string similar to Agree and accept the.
/// </summary>
public static string AgreeTerms {
get {
return ResourceManager.GetString("AgreeTerms", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to rustyhearts.exe is already running.. /// Looks up a localized string similar to rustyhearts.exe is already running..
/// </summary> /// </summary>
@ -87,6 +150,15 @@ namespace RHLauncher.RHLauncher {
} }
} }
/// <summary>
/// Looks up a localized string similar to Installed?.
/// </summary>
public static string AlreadyInstalled {
get {
return ResourceManager.GetString("AlreadyInstalled", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Cancelling. /// Looks up a localized string similar to Cancelling.
/// </summary> /// </summary>
@ -96,6 +168,15 @@ namespace RHLauncher.RHLauncher {
} }
} }
/// <summary>
/// Looks up a localized string similar to The launcher needs to be restarted to change the language. Restart now?.
/// </summary>
public static string ChangeLanguageMessage {
get {
return ResourceManager.GetString("ChangeLanguageMessage", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Change Password. /// Looks up a localized string similar to Change Password.
/// </summary> /// </summary>
@ -105,6 +186,15 @@ namespace RHLauncher.RHLauncher {
} }
} }
/// <summary>
/// Looks up a localized string similar to Change Password.
/// </summary>
public static string ChangePwdFormTitle {
get {
return ResourceManager.GetString("ChangePwdFormTitle", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Auto Login. /// Looks up a localized string similar to Auto Login.
/// </summary> /// </summary>
@ -132,6 +222,69 @@ namespace RHLauncher.RHLauncher {
} }
} }
/// <summary>
/// Looks up a localized string similar to Checking files....
/// </summary>
public static string CheckingFiles {
get {
return ResourceManager.GetString("CheckingFiles", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Check for Updates.
/// </summary>
public static string CheckUpdate {
get {
return ResourceManager.GetString("CheckUpdate", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to An error occurred while downloading client..
/// </summary>
public static string ClientDownloadError {
get {
return ResourceManager.GetString("ClientDownloadError", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Error downloading game client..
/// </summary>
public static string ClientDownloadErrorMessage {
get {
return ResourceManager.GetString("ClientDownloadErrorMessage", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Could not retrieve file list from.
/// </summary>
public static string ClientDownloadFilelistError {
get {
return ResourceManager.GetString("ClientDownloadFilelistError", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Failed to delete download directory..
/// </summary>
public static string ClientFolderErrorMessage {
get {
return ResourceManager.GetString("ClientFolderErrorMessage", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to The directory containing &apos;rustyhearts.exe&apos; was not found after extraction..
/// </summary>
public static string ClientFolderExeErrorMessage {
get {
return ResourceManager.GetString("ClientFolderExeErrorMessage", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Insert the verification code. /// Looks up a localized string similar to Insert the verification code.
/// </summary> /// </summary>
@ -150,6 +303,15 @@ namespace RHLauncher.RHLauncher {
} }
} }
/// <summary>
/// Looks up a localized string similar to Launcher Settings.
/// </summary>
public static string ConfigFormTitle {
get {
return ResourceManager.GetString("ConfigFormTitle", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Confirmation. /// Looks up a localized string similar to Confirmation.
/// </summary> /// </summary>
@ -222,6 +384,15 @@ namespace RHLauncher.RHLauncher {
} }
} }
/// <summary>
/// Looks up a localized string similar to Enter the password.
/// </summary>
public static string EnterPassword {
get {
return ResourceManager.GetString("EnterPassword", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Error. /// Looks up a localized string similar to Error.
/// </summary> /// </summary>
@ -258,6 +429,33 @@ namespace RHLauncher.RHLauncher {
} }
} }
/// <summary>
/// Looks up a localized string similar to Game Settings.
/// </summary>
public static string GameSettings {
get {
return ResourceManager.GetString("GameSettings", resourceCulture);
}
}
/// <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>
@ -276,6 +474,51 @@ namespace RHLauncher.RHLauncher {
} }
} }
/// <summary>
/// Looks up a localized string similar to Installing.
/// </summary>
public static string Installing {
get {
return ResourceManager.GetString("Installing", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Install Location.
/// </summary>
public static string InstallLocation {
get {
return ResourceManager.GetString("InstallLocation", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Invalid Install Directory.
/// </summary>
public static string InvalidDirectory {
get {
return ResourceManager.GetString("InvalidDirectory", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Invalid email format.
/// </summary>
public static string InvalidEmailFormat {
get {
return ResourceManager.GetString("InvalidEmailFormat", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Invalid username format.
/// </summary>
public static string InvalidUserNameFormat {
get {
return ResourceManager.GetString("InvalidUserNameFormat", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Invalid Verification Code. /// Looks up a localized string similar to Invalid Verification Code.
/// </summary> /// </summary>
@ -303,6 +546,33 @@ namespace RHLauncher.RHLauncher {
} }
} }
/// <summary>
/// Looks up a localized string similar to Only one instance of the launcher can run at a time..
/// </summary>
public static string LauncherAlreadyRunning {
get {
return ResourceManager.GetString("LauncherAlreadyRunning", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Rusty Hearts Launcher.
/// </summary>
public static string LauncherFormTitle {
get {
return ResourceManager.GetString("LauncherFormTitle", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Launcher Language.
/// </summary>
public static string LauncherLanguage {
get {
return ResourceManager.GetString("LauncherLanguage", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Error checking for launcher update: . /// Looks up a localized string similar to Error checking for launcher update: .
/// </summary> /// </summary>
@ -348,6 +618,15 @@ namespace RHLauncher.RHLauncher {
} }
} }
/// <summary>
/// Looks up a localized string similar to Locate Game.
/// </summary>
public static string LocateGame {
get {
return ResourceManager.GetString("LocateGame", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Login Info. /// Looks up a localized string similar to Login Info.
/// </summary> /// </summary>
@ -420,6 +699,15 @@ namespace RHLauncher.RHLauncher {
} }
} }
/// <summary>
/// Looks up a localized string similar to Logout.
/// </summary>
public static string Logout {
get {
return ResourceManager.GetString("Logout", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Are you sure you want to logout?. /// Looks up a localized string similar to Are you sure you want to logout?.
/// </summary> /// </summary>
@ -429,6 +717,33 @@ namespace RHLauncher.RHLauncher {
} }
} }
/// <summary>
/// Looks up a localized string similar to &lt; Manage.
/// </summary>
public static string Manage {
get {
return ResourceManager.GetString("Manage", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Error installing update. Could not find MPatcher.exe.
/// </summary>
public static string MPatcher {
get {
return ResourceManager.GetString("MPatcher", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Message.
/// </summary>
public static string MsgBoxFormTitle {
get {
return ResourceManager.GetString("MsgBoxFormTitle", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Enter the new password. /// Looks up a localized string similar to Enter the new password.
/// </summary> /// </summary>
@ -439,7 +754,7 @@ namespace RHLauncher.RHLauncher {
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to 6-16 characters. /// Looks up a localized string similar to 8-16 characters.
/// </summary> /// </summary>
public static string NewPasswordDesc { public static string NewPasswordDesc {
get { get {
@ -447,6 +762,24 @@ namespace RHLauncher.RHLauncher {
} }
} }
/// <summary>
/// Looks up a localized string similar to No.
/// </summary>
public static string No {
get {
return ResourceManager.GetString("No", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Open Install Directory.
/// </summary>
public static string OpenInstallDir {
get {
return ResourceManager.GetString("OpenInstallDir", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Packing. /// Looks up a localized string similar to Packing.
/// </summary> /// </summary>
@ -511,7 +844,7 @@ namespace RHLauncher.RHLauncher {
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to Password must be between 6-16 characters!. /// Looks up a localized string similar to Password must be between 8-16 characters!.
/// </summary> /// </summary>
public static string PwdDescLabelSize { public static string PwdDescLabelSize {
get { get {
@ -547,7 +880,34 @@ namespace RHLauncher.RHLauncher {
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to Re-enter the new password. /// Looks up a localized string similar to Register Account.
/// </summary>
public static string RegFormTitle {
get {
return ResourceManager.GetString("RegFormTitle", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Register Account.
/// </summary>
public static string RegisterAccount {
get {
return ResourceManager.GetString("RegisterAccount", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Register Window.
/// </summary>
public static string RegisterWindow {
get {
return ResourceManager.GetString("RegisterWindow", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Repeat the new password.
/// </summary> /// </summary>
public static string RepeatPassword { public static string RepeatPassword {
get { get {
@ -609,6 +969,24 @@ namespace RHLauncher.RHLauncher {
} }
} }
/// <summary>
/// Looks up a localized string similar to Select RustyHearts.exe.
/// </summary>
public static string SelectExe {
get {
return ResourceManager.GetString("SelectExe", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Select Install Location.
/// </summary>
public static string SelectInstallLocation {
get {
return ResourceManager.GetString("SelectInstallLocation", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Cannot connect to the game server.. /// Looks up a localized string similar to Cannot connect to the game server..
/// </summary> /// </summary>
@ -618,6 +996,42 @@ namespace RHLauncher.RHLauncher {
} }
} }
/// <summary>
/// Looks up a localized string similar to Service.
/// </summary>
public static string Service {
get {
return ResourceManager.GetString("Service", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Could not find Service.dat. Please check if the Install Directory is correct..
/// </summary>
public static string ServiceDatFileMissing {
get {
return ResourceManager.GetString("ServiceDatFileMissing", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to An error occurred while updating service.
/// </summary>
public static string ServiceUpdateError {
get {
return ResourceManager.GetString("ServiceUpdateError", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Settings.
/// </summary>
public static string Settings {
get {
return ResourceManager.GetString("Settings", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Success. /// Looks up a localized string similar to Success.
/// </summary> /// </summary>
@ -708,6 +1122,24 @@ namespace RHLauncher.RHLauncher {
} }
} }
/// <summary>
/// Looks up a localized string similar to &quot;User Agreement&quot;.
/// </summary>
public static string UserAgreement {
get {
return ResourceManager.GetString("UserAgreement", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to 6-16 alphanumeric characters.
/// </summary>
public static string UsernameDesc {
get {
return ResourceManager.GetString("UsernameDesc", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Name cannot be empty. /// Looks up a localized string similar to Name cannot be empty.
/// </summary> /// </summary>
@ -735,6 +1167,15 @@ namespace RHLauncher.RHLauncher {
} }
} }
/// <summary>
/// Looks up a localized string similar to Username must not contain uppercase letters. Please use only lowercase letters and digits..
/// </summary>
public static string UsernameDescLabelUppercase {
get {
return ResourceManager.GetString("UsernameDescLabelUppercase", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Username/Email. /// Looks up a localized string similar to Username/Email.
/// </summary> /// </summary>
@ -779,5 +1220,23 @@ namespace RHLauncher.RHLauncher {
return ResourceManager.GetString("Welcome", resourceCulture); return ResourceManager.GetString("Welcome", resourceCulture);
} }
} }
/// <summary>
/// Looks up a localized string similar to A game account with this username already exists..
/// </summary>
public static string WindyCodeExists {
get {
return ResourceManager.GetString("WindyCodeExists", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Yes.
/// </summary>
public static string Yes {
get {
return ResourceManager.GetString("Yes", resourceCulture);
}
}
} }
} }

View file

@ -0,0 +1,513 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Account" xml:space="preserve">
<value>계정</value>
</data>
<data name="AccountCreateSuccess" xml:space="preserve">
<value>계정이 성공적으로 생성되었습니다.</value>
</data>
<data name="AccountDetails" xml:space="preserve">
<value>계정 정보</value>
</data>
<data name="AccountEmail" xml:space="preserve">
<value>계정 이메일</value>
</data>
<data name="AccountEmailExists" xml:space="preserve">
<value>이 이메일을 사용하는 계정이 이미 존재합니다.</value>
</data>
<data name="AccountExists" xml:space="preserve">
<value>이 사용자 이름을 사용하는 계정이 이미 존재합니다.</value>
</data>
<data name="AccountName" xml:space="preserve">
<value>계정 이름</value>
</data>
<data name="AccountNotFound" xml:space="preserve">
<value>이 이메일을 사용한 계정을 찾을 수 없습니다</value>
</data>
<data name="AgreeTerms" xml:space="preserve">
<value>나는 에 동의하고 수락합니다</value>
</data>
<data name="AlreadyExecute" xml:space="preserve">
<value>RustyHearts.exe가 이미 실행 중입니다.</value>
</data>
<data name="AlreadyInstalled" xml:space="preserve">
<value>설치되었나요?</value>
</data>
<data name="Cancelling" xml:space="preserve">
<value>취소 중</value>
</data>
<data name="ChangeLanguageMessage" xml:space="preserve">
<value>언어를 변경하려면 런처를 다시 시작해야 합니다. 지금 다시 시작하시겠습니까?</value>
</data>
<data name="ChangePassword" xml:space="preserve">
<value>비밀번호 변경</value>
</data>
<data name="ChangePwdFormTitle" xml:space="preserve">
<value>비밀번호 변경</value>
</data>
<data name="CheckBoxAutoLogin" xml:space="preserve">
<value>자동 로그인</value>
</data>
<data name="CheckBoxSaveUser" xml:space="preserve">
<value>사용자 이름 기억</value>
</data>
<data name="Checking" xml:space="preserve">
<value>확인 중</value>
</data>
<data name="CheckingFiles" xml:space="preserve">
<value>파일을 확인하는 중...</value>
</data>
<data name="CheckUpdate" xml:space="preserve">
<value>업데이트 확인</value>
</data>
<data name="ClientDownloadError" xml:space="preserve">
<value>클라이언트를 다운로드하는 동안 오류가 발생했습니다.</value>
</data>
<data name="ClientDownloadErrorMessage" xml:space="preserve">
<value>게임 클라이언트 다운로드 중 오류가 발생했습니다.</value>
</data>
<data name="ClientDownloadFilelistError" xml:space="preserve">
<value>에서 파일 목록을 검색할 수 없습니다</value>
</data>
<data name="ClientFolderErrorMessage" xml:space="preserve">
<value>다운로드 디렉터리를 삭제하지 못했습니다.</value>
</data>
<data name="ClientFolderExeErrorMessage" xml:space="preserve">
<value>추출 후 'rustyhearts.exe'가 포함된 디렉터리를 찾을 수 없습니다.</value>
</data>
<data name="CodeDescLabel" xml:space="preserve">
<value>인증코드를 입력하세요</value>
</data>
<data name="CodeDescLabelInvalid" xml:space="preserve">
<value>잘못된 인증 코드 형식</value>
</data>
<data name="ConfigFormTitle" xml:space="preserve">
<value>런처 설정</value>
</data>
<data name="Confirmation" xml:space="preserve">
<value>확증</value>
</data>
<data name="ConfirmUninstall" xml:space="preserve">
<value>설치 제거 확인</value>
</data>
<data name="ConfirmUninstallText" xml:space="preserve">
<value>설치 디렉토리를 설치 제거하고 삭제하시겠습니까?</value>
</data>
<data name="DescLabelS2Email" xml:space="preserve">
<value>확인 이메일이 다음으로 전송되었습니다</value>
</data>
<data name="Downloading" xml:space="preserve">
<value>다운로드 중</value>
</data>
<data name="EmailDescLabelEmpty" xml:space="preserve">
<value>이메일은 비워둘 수 없습니다</value>
</data>
<data name="EmailDescLabelInvalid" xml:space="preserve">
<value>잘못된 이메일 주소</value>
</data>
<data name="EnterEmail" xml:space="preserve">
<value>당신의 이메일 주소를 입력 해주세요</value>
</data>
<data name="EnterPassword" xml:space="preserve">
<value>비밀번호를 입력하세요</value>
</data>
<data name="Error" xml:space="preserve">
<value>오류</value>
</data>
<data name="ExpiredVerificationCode" xml:space="preserve">
<value>이 인증 코드는 만료되었습니다. 새 인증 코드를 요청하세요.</value>
</data>
<data name="Failed" xml:space="preserve">
<value>실패한</value>
</data>
<data name="ForgotPwdLabel" xml:space="preserve">
<value>비밀번호를 잊으 셨나요?</value>
</data>
<data name="GameSettings" xml:space="preserve">
<value>게임 설정</value>
</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">
<value>정보</value>
</data>
<data name="Install" xml:space="preserve">
<value>설치하다</value>
</data>
<data name="Installing" xml:space="preserve">
<value>설치 중</value>
</data>
<data name="InstallLocation" xml:space="preserve">
<value>설치 위치</value>
</data>
<data name="InvalidDirectory" xml:space="preserve">
<value>잘못된 설치 디렉터리</value>
</data>
<data name="InvalidEmailFormat" xml:space="preserve">
<value>잘못된 이메일 형식</value>
</data>
<data name="InvalidUserNameFormat" xml:space="preserve">
<value>잘못된 사용자 이름 형식</value>
</data>
<data name="InvalidVerificationCode" xml:space="preserve">
<value>잘못된 인증 코드</value>
</data>
<data name="LabelNews" xml:space="preserve">
<value>소식</value>
</data>
<data name="Launch" xml:space="preserve">
<value>시작하다</value>
</data>
<data name="LauncherAlreadyRunning" xml:space="preserve">
<value>한 번에 하나의 런처 인스턴스만 실행할 수 있습니다.</value>
</data>
<data name="LauncherFormTitle" xml:space="preserve">
<value>러스티하츠 런처</value>
</data>
<data name="LauncherLanguage" xml:space="preserve">
<value>런처 언어</value>
</data>
<data name="LauncherUpdateCheckFailed" xml:space="preserve">
<value>런처 업데이트 확인 중 오류가 발생했습니다:</value>
</data>
<data name="LauncherUpdateFailed" xml:space="preserve">
<value>런처 업데이트를 다운로드하는 중 오류가 발생했습니다:</value>
</data>
<data name="LauncherUpdateSuccess" xml:space="preserve">
<value>런처가 버전으로 업데이트되었습니다</value>
</data>
<data name="LauncherUpdateText" xml:space="preserve">
<value>새로운 버전의 런처를 사용할 수 있습니다. 자동으로 다운로드되어 설치됩니다.</value>
</data>
<data name="Launching" xml:space="preserve">
<value>진수</value>
</data>
<data name="LocateGame" xml:space="preserve">
<value>게임 위치</value>
</data>
<data name="LoginInfoTitle" xml:space="preserve">
<value>로그인 정보</value>
</data>
<data name="LoginInsertPassword" xml:space="preserve">
<value>비밀번호를 입력해주세요.</value>
</data>
<data name="LoginInsertUsername" xml:space="preserve">
<value>사용자 이름을 입력하세요.</value>
</data>
<data name="LoginInvalidCredentials" xml:space="preserve">
<value>사용자 이름 또는 비밀번호가 잘못되었습니다.</value>
</data>
<data name="LoginInvalidUsernameFormat" xml:space="preserve">
<value>사용자 이름 형식이 잘못되었습니다.</value>
</data>
<data name="LoginLocked" xml:space="preserve">
<value>귀하의 계정이 잠겨 있습니다. 고객지원팀에 문의하세요.</value>
</data>
<data name="LoginTooManyAttempts" xml:space="preserve">
<value>로그인 시도 횟수가 너무 많습니다. 나중에 다시 시도 해주십시오.</value>
</data>
<data name="LoginWindowTitle" xml:space="preserve">
<value>로그인 창</value>
</data>
<data name="Logout" xml:space="preserve">
<value>로그 아웃</value>
</data>
<data name="LogoutText" xml:space="preserve">
<value>정말로 로그아웃하시겠습니까?</value>
</data>
<data name="Manage" xml:space="preserve">
<value>&lt; 관리</value>
</data>
<data name="MPatcher" xml:space="preserve">
<value>업데이트 설치 중 오류가 발생했습니다. MPatcher.exe를 찾을 수 없습니다.</value>
</data>
<data name="MsgBoxFormTitle" xml:space="preserve">
<value>메시지</value>
</data>
<data name="NewPassword" xml:space="preserve">
<value>새 비밀번호를 입력하세요</value>
</data>
<data name="NewPasswordDesc" xml:space="preserve">
<value>8~16자</value>
</data>
<data name="No" xml:space="preserve">
<value>아니요</value>
</data>
<data name="OpenInstallDir" xml:space="preserve">
<value>설치 디렉토리 열기</value>
</data>
<data name="Packing" xml:space="preserve">
<value>포장</value>
</data>
<data name="PasswordChanged" xml:space="preserve">
<value>비밀번호가 성공적으로 변경되었습니다! 다시 로그인해주세요.</value>
</data>
<data name="PasswordLabel" xml:space="preserve">
<value>비밀번호</value>
</data>
<data name="PwdConfirmDescLabelEmpty" xml:space="preserve">
<value>비밀번호 확인은 비워둘 수 없습니다!</value>
</data>
<data name="PwdConfirmDescLabelMatch" xml:space="preserve">
<value>비밀번호가 일치하지 않습니다!</value>
</data>
<data name="PwdDescLabelCriteria" xml:space="preserve">
<value>비밀번호에는 대문자, 소문자, 숫자가 하나 이상 포함되어야 합니다.</value>
</data>
<data name="PwdDescLabelEmpty" xml:space="preserve">
<value>비밀번호는 비워둘 수 없습니다!</value>
</data>
<data name="PwdDescLabelSize" xml:space="preserve">
<value>비밀번호는 8~16자 사이여야 합니다!</value>
</data>
<data name="PwdStrengthLabelMedium" xml:space="preserve">
<value>매질</value>
</data>
<data name="PwdStrengthLabelStrong" xml:space="preserve">
<value>강한</value>
</data>
<data name="PwdStrengthLabelWeak" xml:space="preserve">
<value>약한</value>
</data>
<data name="RegFormTitle" xml:space="preserve">
<value>계좌등록</value>
</data>
<data name="RegisterAccount" xml:space="preserve">
<value>계좌등록</value>
</data>
<data name="RegisterWindow" xml:space="preserve">
<value>등록 창</value>
</data>
<data name="RepeatPassword" xml:space="preserve">
<value>새 비밀번호를 다시 입력하세요.</value>
</data>
<data name="RepeatPasswordDesc" xml:space="preserve">
<value>비밀번호를 반복하세요</value>
</data>
<data name="Return" xml:space="preserve">
<value>&lt; 반품</value>
</data>
<data name="Running" xml:space="preserve">
<value>달리기</value>
</data>
<data name="RustyHearts" xml:space="preserve">
<value>러스티하츠</value>
</data>
<data name="rustyheartsconfig" xml:space="preserve">
<value>Rustyheartsconfig.exe를 찾을 수 없습니다.</value>
</data>
<data name="SamePassword" xml:space="preserve">
<value>동일한 비밀번호. 다른 비밀번호를 사용해 주세요.</value>
</data>
<data name="SelectExe" xml:space="preserve">
<value>RustyHearts.exe를 선택하세요.</value>
</data>
<data name="SelectInstallLocation" xml:space="preserve">
<value>설치 위치 선택</value>
</data>
<data name="ServerOffline" xml:space="preserve">
<value>게임 서버에 연결할 수 없습니다.</value>
</data>
<data name="Service" xml:space="preserve">
<value>서비스</value>
</data>
<data name="ServiceDatFileMissing" xml:space="preserve">
<value>Service.dat를 찾을 수 없습니다. 설치 디렉터리가 올바른지 확인하세요.</value>
</data>
<data name="ServiceUpdateError" xml:space="preserve">
<value>서비스를 업데이트하는 중 오류가 발생했습니다.</value>
</data>
<data name="Settings" xml:space="preserve">
<value>설정</value>
</data>
<data name="Success" xml:space="preserve">
<value>성공</value>
</data>
<data name="Uninstall" xml:space="preserve">
<value>제거</value>
</data>
<data name="Uninstalling" xml:space="preserve">
<value>제거 중</value>
</data>
<data name="UninstallText" xml:space="preserve">
<value>제거가 완료되었습니다.</value>
</data>
<data name="Unpacking" xml:space="preserve">
<value>포장 풀기</value>
</data>
<data name="UnsupportedService" xml:space="preserve">
<value>지원되지 않는 클라이언트 지역입니다.</value>
</data>
<data name="Update" xml:space="preserve">
<value>업데이트</value>
</data>
<data name="UpdateCheckError" xml:space="preserve">
<value>업데이트를 확인하는 동안 오류가 발생했습니다.</value>
</data>
<data name="UpdateDownloadError" xml:space="preserve">
<value>업데이트를 다운로드하는 동안 오류가 발생했습니다.</value>
</data>
<data name="Updating" xml:space="preserve">
<value>업데이트 중</value>
</data>
<data name="UserAgreement" xml:space="preserve">
<value>"사용자 계약"</value>
</data>
<data name="UsernameDesc" xml:space="preserve">
<value>6~16자의 영숫자</value>
</data>
<data name="UsernameDescLabelEmpty" xml:space="preserve">
<value>사용자 이름은 비워둘 수 없습니다.</value>
</data>
<data name="UsernameDescLabelInvalid" xml:space="preserve">
<value>사용자 이름은 하나 이상의 문자가 포함된 영숫자여야 합니다.</value>
</data>
<data name="UsernameDescLabelSize" xml:space="preserve">
<value>사용자 이름은 6~16자 사이여야 합니다.</value>
</data>
<data name="UsernameDescLabelUppercase" xml:space="preserve">
<value>사용자 이름에는 대문자가 포함될 수 없습니다. 소문자와 숫자만 사용해주세요.</value>
</data>
<data name="UsernameLabel" xml:space="preserve">
<value>아이디 또는 이메일</value>
</data>
<data name="VerificationCode" xml:space="preserve">
<value>확인 코드</value>
</data>
<data name="VerificationEmailSent" xml:space="preserve">
<value>확인 이메일이 다음으로 전송되었습니다</value>
</data>
<data name="Version" xml:space="preserve">
<value>런처 버전</value>
</data>
<data name="Welcome" xml:space="preserve">
<value>환영하다</value>
</data>
<data name="WindyCodeExists" xml:space="preserve">
<value>이 사용자 이름을 가진 게임 계정이 이미 존재합니다.</value>
</data>
<data name="Yes" xml:space="preserve">
<value>예</value>
</data>
</root>

View file

@ -120,18 +120,48 @@
<data name="Account" xml:space="preserve"> <data name="Account" xml:space="preserve">
<value>Account</value> <value>Account</value>
</data> </data>
<data name="AccountCreateSuccess" xml:space="preserve">
<value>Account created successfully.</value>
</data>
<data name="AccountDetails" xml:space="preserve">
<value>Account Details</value>
</data>
<data name="AccountEmail" xml:space="preserve">
<value>Account Email</value>
</data>
<data name="AccountEmailExists" xml:space="preserve">
<value>A account with this email already exists.</value>
</data>
<data name="AccountExists" xml:space="preserve">
<value>A account with this username already exists.</value>
</data>
<data name="AccountName" xml:space="preserve">
<value>Account Name</value>
</data>
<data name="AccountNotFound" xml:space="preserve"> <data name="AccountNotFound" xml:space="preserve">
<value>A account with this email was not found</value> <value>A account with this email was not found</value>
</data> </data>
<data name="AgreeTerms" xml:space="preserve">
<value>Agree and accept the</value>
</data>
<data name="AlreadyExecute" xml:space="preserve"> <data name="AlreadyExecute" xml:space="preserve">
<value>rustyhearts.exe is already running.</value> <value>rustyhearts.exe is already running.</value>
</data> </data>
<data name="AlreadyInstalled" xml:space="preserve">
<value>Installed?</value>
</data>
<data name="Cancelling" xml:space="preserve"> <data name="Cancelling" xml:space="preserve">
<value>Cancelling</value> <value>Cancelling</value>
</data> </data>
<data name="ChangeLanguageMessage" xml:space="preserve">
<value>The launcher needs to be restarted to change the language. Restart now?</value>
</data>
<data name="ChangePassword" xml:space="preserve"> <data name="ChangePassword" xml:space="preserve">
<value>Change Password</value> <value>Change Password</value>
</data> </data>
<data name="ChangePwdFormTitle" xml:space="preserve">
<value>Change Password</value>
</data>
<data name="CheckBoxAutoLogin" xml:space="preserve"> <data name="CheckBoxAutoLogin" xml:space="preserve">
<value>Auto Login</value> <value>Auto Login</value>
</data> </data>
@ -141,12 +171,36 @@
<data name="Checking" xml:space="preserve"> <data name="Checking" xml:space="preserve">
<value>Checking</value> <value>Checking</value>
</data> </data>
<data name="CheckingFiles" xml:space="preserve">
<value>Checking files...</value>
</data>
<data name="CheckUpdate" xml:space="preserve">
<value>Check for Updates</value>
</data>
<data name="ClientDownloadError" xml:space="preserve">
<value>An error occurred while downloading client.</value>
</data>
<data name="ClientDownloadErrorMessage" xml:space="preserve">
<value>Error downloading game client.</value>
</data>
<data name="ClientDownloadFilelistError" xml:space="preserve">
<value>Could not retrieve file list from</value>
</data>
<data name="ClientFolderErrorMessage" xml:space="preserve">
<value>Failed to delete download directory.</value>
</data>
<data name="ClientFolderExeErrorMessage" xml:space="preserve">
<value>The directory containing 'rustyhearts.exe' was not found after extraction.</value>
</data>
<data name="CodeDescLabel" xml:space="preserve"> <data name="CodeDescLabel" xml:space="preserve">
<value>Insert the verification code</value> <value>Insert the verification code</value>
</data> </data>
<data name="CodeDescLabelInvalid" xml:space="preserve"> <data name="CodeDescLabelInvalid" xml:space="preserve">
<value>Invalid Verification Code format</value> <value>Invalid Verification Code format</value>
</data> </data>
<data name="ConfigFormTitle" xml:space="preserve">
<value>Launcher Settings</value>
</data>
<data name="Confirmation" xml:space="preserve"> <data name="Confirmation" xml:space="preserve">
<value>Confirmation</value> <value>Confirmation</value>
</data> </data>
@ -171,6 +225,9 @@
<data name="EnterEmail" xml:space="preserve"> <data name="EnterEmail" xml:space="preserve">
<value>Enter your Email address</value> <value>Enter your Email address</value>
</data> </data>
<data name="EnterPassword" xml:space="preserve">
<value>Enter the password</value>
</data>
<data name="Error" xml:space="preserve"> <data name="Error" xml:space="preserve">
<value>Error</value> <value>Error</value>
</data> </data>
@ -183,12 +240,36 @@
<data name="ForgotPwdLabel" xml:space="preserve"> <data name="ForgotPwdLabel" xml:space="preserve">
<value>Forgot Password?</value> <value>Forgot Password?</value>
</data> </data>
<data name="GameSettings" xml:space="preserve">
<value>Game Settings</value>
</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>
<data name="Install" xml:space="preserve"> <data name="Install" xml:space="preserve">
<value>Install</value> <value>Install</value>
</data> </data>
<data name="Installing" xml:space="preserve">
<value>Installing</value>
</data>
<data name="InstallLocation" xml:space="preserve">
<value>Install Location</value>
</data>
<data name="InvalidDirectory" xml:space="preserve">
<value>Invalid Install Directory</value>
</data>
<data name="InvalidEmailFormat" xml:space="preserve">
<value>Invalid email format</value>
</data>
<data name="InvalidUserNameFormat" xml:space="preserve">
<value>Invalid username format</value>
</data>
<data name="InvalidVerificationCode" xml:space="preserve"> <data name="InvalidVerificationCode" xml:space="preserve">
<value>Invalid Verification Code</value> <value>Invalid Verification Code</value>
</data> </data>
@ -198,6 +279,15 @@
<data name="Launch" xml:space="preserve"> <data name="Launch" xml:space="preserve">
<value>Launch</value> <value>Launch</value>
</data> </data>
<data name="LauncherAlreadyRunning" xml:space="preserve">
<value>Only one instance of the launcher can run at a time.</value>
</data>
<data name="LauncherFormTitle" xml:space="preserve">
<value>Rusty Hearts Launcher</value>
</data>
<data name="LauncherLanguage" xml:space="preserve">
<value>Launcher Language</value>
</data>
<data name="LauncherUpdateCheckFailed" xml:space="preserve"> <data name="LauncherUpdateCheckFailed" xml:space="preserve">
<value>Error checking for launcher update: </value> <value>Error checking for launcher update: </value>
</data> </data>
@ -213,6 +303,9 @@
<data name="Launching" xml:space="preserve"> <data name="Launching" xml:space="preserve">
<value>Launching</value> <value>Launching</value>
</data> </data>
<data name="LocateGame" xml:space="preserve">
<value>Locate Game</value>
</data>
<data name="LoginInfoTitle" xml:space="preserve"> <data name="LoginInfoTitle" xml:space="preserve">
<value>Login Info</value> <value>Login Info</value>
</data> </data>
@ -237,14 +330,32 @@
<data name="LoginWindowTitle" xml:space="preserve"> <data name="LoginWindowTitle" xml:space="preserve">
<value>Login Window</value> <value>Login Window</value>
</data> </data>
<data name="Logout" xml:space="preserve">
<value>Logout</value>
</data>
<data name="LogoutText" xml:space="preserve"> <data name="LogoutText" xml:space="preserve">
<value>Are you sure you want to logout?</value> <value>Are you sure you want to logout?</value>
</data> </data>
<data name="Manage" xml:space="preserve">
<value>&lt; Manage</value>
</data>
<data name="MPatcher" xml:space="preserve">
<value>Error installing update. Could not find MPatcher.exe</value>
</data>
<data name="MsgBoxFormTitle" xml:space="preserve">
<value>Message</value>
</data>
<data name="NewPassword" xml:space="preserve"> <data name="NewPassword" xml:space="preserve">
<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>6-16 characters</value> <value>8-16 characters</value>
</data>
<data name="No" xml:space="preserve">
<value>No</value>
</data>
<data name="OpenInstallDir" xml:space="preserve">
<value>Open Install Directory</value>
</data> </data>
<data name="Packing" xml:space="preserve"> <data name="Packing" xml:space="preserve">
<value>Packing</value> <value>Packing</value>
@ -268,7 +379,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 6-16 characters!</value> <value>Password must be between 8-16 characters!</value>
</data> </data>
<data name="PwdStrengthLabelMedium" xml:space="preserve"> <data name="PwdStrengthLabelMedium" xml:space="preserve">
<value>Medium</value> <value>Medium</value>
@ -279,8 +390,17 @@
<data name="PwdStrengthLabelWeak" xml:space="preserve"> <data name="PwdStrengthLabelWeak" xml:space="preserve">
<value>Weak</value> <value>Weak</value>
</data> </data>
<data name="RegFormTitle" xml:space="preserve">
<value>Register Account</value>
</data>
<data name="RegisterAccount" xml:space="preserve">
<value>Register Account</value>
</data>
<data name="RegisterWindow" xml:space="preserve">
<value>Register Window</value>
</data>
<data name="RepeatPassword" xml:space="preserve"> <data name="RepeatPassword" xml:space="preserve">
<value>Re-enter the new password</value> <value>Repeat the new password</value>
</data> </data>
<data name="RepeatPasswordDesc" xml:space="preserve"> <data name="RepeatPasswordDesc" xml:space="preserve">
<value>Repeat the password</value> <value>Repeat the password</value>
@ -300,9 +420,27 @@
<data name="SamePassword" xml:space="preserve"> <data name="SamePassword" xml:space="preserve">
<value>Same password. Please use another password.</value> <value>Same password. Please use another password.</value>
</data> </data>
<data name="SelectExe" xml:space="preserve">
<value>Select RustyHearts.exe</value>
</data>
<data name="SelectInstallLocation" xml:space="preserve">
<value>Select Install Location</value>
</data>
<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">
<value>Could not find Service.dat. Please check if the Install Directory is correct.</value>
</data>
<data name="ServiceUpdateError" xml:space="preserve">
<value>An error occurred while updating service</value>
</data>
<data name="Settings" xml:space="preserve">
<value>Settings</value>
</data>
<data name="Success" xml:space="preserve"> <data name="Success" xml:space="preserve">
<value>Success</value> <value>Success</value>
</data> </data>
@ -333,6 +471,12 @@
<data name="Updating" xml:space="preserve"> <data name="Updating" xml:space="preserve">
<value>Updating</value> <value>Updating</value>
</data> </data>
<data name="UserAgreement" xml:space="preserve">
<value>"User Agreement"</value>
</data>
<data name="UsernameDesc" xml:space="preserve">
<value>6-16 alphanumeric characters</value>
</data>
<data name="UsernameDescLabelEmpty" xml:space="preserve"> <data name="UsernameDescLabelEmpty" xml:space="preserve">
<value>Name cannot be empty</value> <value>Name cannot be empty</value>
</data> </data>
@ -342,6 +486,9 @@
<data name="UsernameDescLabelSize" xml:space="preserve"> <data name="UsernameDescLabelSize" xml:space="preserve">
<value>Username must be between 6-16 characters</value> <value>Username must be between 6-16 characters</value>
</data> </data>
<data name="UsernameDescLabelUppercase" xml:space="preserve">
<value>Username must not contain uppercase letters. Please use only lowercase letters and digits.</value>
</data>
<data name="UsernameLabel" xml:space="preserve"> <data name="UsernameLabel" xml:space="preserve">
<value>Username/Email</value> <value>Username/Email</value>
</data> </data>
@ -357,4 +504,10 @@
<data name="Welcome" xml:space="preserve"> <data name="Welcome" xml:space="preserve">
<value>Welcome</value> <value>Welcome</value>
</data> </data>
<data name="WindyCodeExists" xml:space="preserve">
<value>A game account with this username already exists.</value>
</data>
<data name="Yes" xml:space="preserve">
<value>Yes</value>
</data>
</root> </root>

View file

@ -1,104 +0,0 @@
using Newtonsoft.Json;
using RHLauncher.RHLauncher;
using RHLauncher.RHLauncher.Helper;
using System.Diagnostics;
using System.IO.Compression;
using System.Text;
namespace RHLauncher
{
public class LauncherUpdater
{
private readonly string LauncherVersionUrl = Configuration.Default.GetLauncherVersion;
private readonly string LauncherUpdateUrl = Configuration.Default.UpdateLauncherVersion;
public async Task CheckForLauncherUpdateAsync()
{
try
{
using HttpClient client = new();
HttpResponseMessage response = await client.GetAsync(LauncherVersionUrl);
response.EnsureSuccessStatusCode();
string json = await response.Content.ReadAsStringAsync();
dynamic result = JsonConvert.DeserializeObject(json);
string version = result.version;
if (!string.IsNullOrEmpty(version))
{
string currentVersion = GetLauncherVersion();
if (!string.IsNullOrEmpty(currentVersion) && !currentVersion.Equals(version, StringComparison.OrdinalIgnoreCase))
{
MsgBoxForm.Show(LocalizedStrings.LauncherUpdateText, LocalizedStrings.Info);
await DownloadLauncherUpdateAsync(json);
}
await Task.Delay(1000);
}
}
catch (Exception ex)
{
string errorMessage = LocalizedStrings.LauncherUpdateCheckFailed + ex.Message;
string errorLog = LocalizedStrings.LauncherUpdateCheckFailed + ex.Message + ex.StackTrace;
Exception newEx = new(errorMessage, ex);
Exception newLogEx = new(errorLog, ex);
ExceptionHandler.HandleException(newEx, newLogEx);
}
}
private async Task DownloadLauncherUpdateAsync(string version)
{
try
{
using HttpClient client = new();
using StringContent content = new(version, Encoding.UTF8, "application/json");
dynamic result = JsonConvert.DeserializeObject(version);
string v = result.version;
using HttpResponseMessage response = await client.PostAsync(LauncherUpdateUrl, content);
response.EnsureSuccessStatusCode();
byte[] updateBytes = await response.Content.ReadAsByteArrayAsync();
string tempFilePath = Path.Combine(Path.GetTempPath(), $"launcher_update.zip");
File.WriteAllBytes(tempFilePath, updateBytes);
string executablePath = AppDomain.CurrentDomain.BaseDirectory;
string backupFilePath = Path.Combine(executablePath, $"Launcher_old.exe");
string launcherExePath = Path.Combine(executablePath, "Launcher.exe");
if (File.Exists(backupFilePath))
{
File.Delete(backupFilePath);
}
// Move existing launcher.exe to temporary location
File.Move(launcherExePath, backupFilePath);
// Extract new update files
ZipFile.ExtractToDirectory(tempFilePath, executablePath, true);
// Delete temporary zip file
File.Delete(tempFilePath);
MsgBoxForm.Show(LocalizedStrings.LauncherUpdateSuccess + v, LocalizedStrings.Info);
Application.Restart();
}
catch (Exception ex)
{
string errorMessage = LocalizedStrings.LauncherUpdateFailed + ex.Message;
string errorLog = LocalizedStrings.LauncherUpdateFailed + ex.Message + ex.StackTrace;
Exception newEx = new(errorMessage, ex);
Exception newLogEx = new(errorLog, ex);
ExceptionHandler.HandleException(newEx, newLogEx);
}
}
public static string GetLauncherVersion()
{
// Get the version information of the application
FileVersionInfo versionInfo = FileVersionInfo.GetVersionInfo(Application.ExecutablePath);
// Extract the version number
string version = $"{versionInfo.FileMajorPart}.{versionInfo.FileMinorPart}.{versionInfo.FileBuildPart}";
return version;
}
}
}

View file

@ -1,86 +0,0 @@
using System.Diagnostics;
namespace RHLauncher.RHLauncher
{
internal class ProgressReporter
{
public static void ReportInstallProgress(IProgress<ProgressReport> progress, string label, string file, int pos, int count, CancellationToken cancellationToken)
{
ProgressReport report = new()
{
Panel = true,
ShowFileNameLabel = true,
ShowSpeedLabel = false,
ShowTimeLabel = false,
ShowFileSizeLabel = false,
ShowFileCountLabel = true,
Label = label,
FileName = Path.GetFileName(file),
PercentComplete = (int)Math.Round(pos * 100.0 / count),
NumFilesPacked = pos,
TotalNumFiles = count,
CancellationToken = cancellationToken
};
progress.Report(report);
}
public static void ReportDownloadProgress(IProgress<ProgressReport> progress, string fileName, long downloadedSize, long totalBytesToDownload, int downloadedFileCount, int totalFilesToDownload, Stopwatch sw, CancellationToken cancellationToken)
{
int percentComplete = totalBytesToDownload > 0 ? (int)Math.Round(downloadedSize * 100.0 / totalBytesToDownload) : 0;
double totalSpeed = downloadedSize / sw.Elapsed.TotalSeconds;
long timeLeft = totalBytesToDownload > 0 ? (long)((totalBytesToDownload - downloadedSize) / (downloadedSize / sw.Elapsed.TotalSeconds)) : 0;
ProgressReport report = new()
{
Panel = true,
ShowFileNameLabel = true,
ShowSpeedLabel = true,
ShowTimeLabel = true,
ShowFileSizeLabel = true,
ShowFileCountLabel = true,
Label = LocalizedStrings.Downloading,
PercentComplete = percentComplete,
FileName = fileName,
BytesDownloaded = downloadedSize,
TotalBytesToDownload = totalBytesToDownload,
TotalSpeed = totalSpeed,
TimeLeft = timeLeft,
NumFilesDownloaded = downloadedFileCount,
TotalNumFiles = totalFilesToDownload,
CancellationToken = cancellationToken
};
progress.Report(report);
}
public static void ReportErrorProgress(IProgress<ProgressReport> progress, string message, CancellationToken cancellationToken)
{
ProgressReport report = new()
{
Panel = true,
ShowFileNameLabel = false,
ShowSpeedLabel = false,
ShowTimeLabel = false,
ShowFileSizeLabel = false,
ShowFileCountLabel = false,
Label = LocalizedStrings.Error,
ErrorMessage = message,
CancellationToken = cancellationToken
};
progress.Report(report);
}
public static void ReportFinishedProgress(IProgress<ProgressReport> progress, CancellationToken cancellationToken)
{
ProgressReport report = new()
{
Panel = false,
CancellationToken = cancellationToken
};
progress.Report(report);
}
}
}

View file

@ -1,86 +0,0 @@
using RHLauncher.Helper;
using RHLauncher.PCK;
namespace RHLauncher.RHLauncher
{
public class UpdateInstaller
{
public static async Task PackDownloadedFilesAsync(string installDir, IProgress<ProgressReport> progress, CancellationToken cancellationToken)
{
string archiveDir = Path.Combine(installDir, "archive");
string updateRootFolder = Path.Combine(installDir, "Update");
if (!Directory.Exists(updateRootFolder))
{
return;
}
List<string> fileList = Directory.EnumerateFiles(updateRootFolder, "*", SearchOption.AllDirectories).ToList();
List<PCKFile> existingFiles = PCKReader.GetPCKFileList();
int count = fileList.Count;
int pos = 0;
try
{
await PCKWriter.Packing(updateRootFolder, fileList, existingFiles, true,
(string fileName, int curPos, int totalCount) =>
{
cancellationToken.ThrowIfCancellationRequested();
pos++;
ProgressReporter.ReportInstallProgress(progress, LocalizedStrings.Packing, fileName, pos, count, cancellationToken);
},
cancellationToken
).ConfigureAwait(false);
}
catch (OperationCanceledException ex)
{
if (Directory.Exists(archiveDir))
{
Directory.Delete(archiveDir, true);
Directory.CreateDirectory(archiveDir);
}
if (Directory.Exists(updateRootFolder))
{
GC.Collect();
GC.WaitForPendingFinalizers();
Directory.Delete(updateRootFolder, true);
}
Logger.WriteLog($"Update installation canceled: {ex.Message}");
}
catch (Exception ex)
{
Logger.WriteLog($"An error occurred while packing: {ex.Message}");
ProgressReporter.ReportErrorProgress(progress, ex.Message, cancellationToken);
throw;
}
finally
{
fileList.Clear();
existingFiles.Clear();
}
ProgressReporter.ReportFinishedProgress(progress, cancellationToken);
// Pause for a short time to allow other tasks to run
await Task.Delay(1000, cancellationToken).ConfigureAwait(false);
if (Directory.Exists(archiveDir))
{
Directory.Delete(archiveDir, true);
Directory.CreateDirectory(archiveDir);
}
if (Directory.Exists(updateRootFolder))
{
GC.Collect();
GC.WaitForPendingFinalizers();
Directory.Delete(updateRootFolder, true);
}
}
}
}

View file

@ -1,74 +0,0 @@
using RHLauncher.Helper;
namespace RHLauncher.RHLauncher
{
public class UpdateUnpacker
{
public static async Task UnpackDownloadedFilesAsync(string installDir, IProgress<ProgressReport> progress, CancellationToken cancellationToken)
{
if (installDir == null)
throw new ArgumentNullException(nameof(installDir));
if (progress == null)
throw new ArgumentNullException(nameof(progress));
string archiveDir = Path.Combine(installDir, "archive");
string updateRootFolder = Path.Combine(installDir, "Update");
if (!Directory.Exists(archiveDir))
{
return;
}
if (!Directory.Exists(updateRootFolder))
{
Directory.CreateDirectory(updateRootFolder);
}
List<string> files = Directory.EnumerateFiles(archiveDir, "*.mip", SearchOption.AllDirectories)
.OrderBy(f => f, StringComparer.OrdinalIgnoreCase)
.ToList();
int count = files.Count;
int pos = 0;
await Task.Run(async () =>
{
foreach (string file in files)
{
cancellationToken.ThrowIfCancellationRequested();
string relativePath = Path.GetRelativePath(archiveDir, file);
string outputPath = Path.Combine(updateRootFolder, relativePath.Substring(0, relativePath.Length - 4)); // Remove the ".mip" extension
try
{
Directory.CreateDirectory(Path.GetDirectoryName(outputPath));
await MIPDecoder.DecompressFileAsync(file, outputPath, cancellationToken);
pos++;
ProgressReporter.ReportInstallProgress(progress, LocalizedStrings.Unpacking, file, pos, count, cancellationToken);
}
catch (OperationCanceledException ex)
{
Logger.WriteLog($"Update unpack canceled: {ex.Message}");
}
catch (ArgumentException ex)
{
Logger.WriteLog($"An error occurred while unpacking: {file} {ex}");
ProgressReporter.ReportErrorProgress(progress, ex.Message, cancellationToken);
}
catch (Exception ex)
{
Logger.WriteLog($"Error: {ex.Message} {ex.StackTrace} ");
throw;
}
}
ProgressReporter.ReportFinishedProgress(progress, cancellationToken);
}, cancellationToken);
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 301 KiB

After

Width:  |  Height:  |  Size: 132 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 306 KiB

After

Width:  |  Height:  |  Size: 76 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 233 KiB

After

Width:  |  Height:  |  Size: 58 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 284 KiB

After

Width:  |  Height:  |  Size: 84 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 427 KiB

After

Width:  |  Height:  |  Size: 125 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 256 KiB

After

Width:  |  Height:  |  Size: 76 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 303 KiB

After

Width:  |  Height:  |  Size: 67 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 284 KiB

After

Width:  |  Height:  |  Size: 65 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 257 KiB

After

Width:  |  Height:  |  Size: 73 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 263 KiB

After

Width:  |  Height:  |  Size: 68 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 373 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 979 KiB

After

Width:  |  Height:  |  Size: 336 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 667 KiB

After

Width:  |  Height:  |  Size: 160 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

After

Width:  |  Height:  |  Size: 1 KiB

Before After
Before After

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Some files were not shown because too many files have changed in this diff Show more