diff --git a/Assets/Images/BackgroundImage.png b/Assets/Images/BackgroundImage.png
new file mode 100644
index 0000000..0c075ee
Binary files /dev/null and b/Assets/Images/BackgroundImage.png differ
diff --git a/Assets/Images/Button_Preload.png b/Assets/Images/Button_Preload.png
new file mode 100644
index 0000000..55babbb
Binary files /dev/null and b/Assets/Images/Button_Preload.png differ
diff --git a/Assets/Images/Button_Preload_Checkmark.png b/Assets/Images/Button_Preload_Checkmark.png
new file mode 100644
index 0000000..43cf633
Binary files /dev/null and b/Assets/Images/Button_Preload_Checkmark.png differ
diff --git a/Assets/Images/Button_Preload_Circle.png b/Assets/Images/Button_Preload_Circle.png
new file mode 100644
index 0000000..9b97d97
Binary files /dev/null and b/Assets/Images/Button_Preload_Circle.png differ
diff --git a/Assets/Images/Button_Preload_Highlighted.png b/Assets/Images/Button_Preload_Highlighted.png
new file mode 100644
index 0000000..c1588d8
Binary files /dev/null and b/Assets/Images/Button_Preload_Highlighted.png differ
diff --git a/Assets/Images/Button_Preload_Pause.png b/Assets/Images/Button_Preload_Pause.png
new file mode 100644
index 0000000..ac6cae4
Binary files /dev/null and b/Assets/Images/Button_Preload_Pause.png differ
diff --git a/Assets/Images/Button_Preload_Pressed.png b/Assets/Images/Button_Preload_Pressed.png
new file mode 100644
index 0000000..1bbc3f6
Binary files /dev/null and b/Assets/Images/Button_Preload_Pressed.png differ
diff --git a/Assets/Images/Button_Preload_Resume.png b/Assets/Images/Button_Preload_Resume.png
new file mode 100644
index 0000000..7f6c2b2
Binary files /dev/null and b/Assets/Images/Button_Preload_Resume.png differ
diff --git a/BetterHI3Launcher.csproj b/BetterHI3Launcher.csproj
index ba5601b..66b3766 100644
--- a/BetterHI3Launcher.csproj
+++ b/BetterHI3Launcher.csproj
@@ -101,6 +101,7 @@
packages\System.Diagnostics.DiagnosticSource.5.0.1\lib\net46\System.Diagnostics.DiagnosticSource.dll
+
packages\System.Globalization.Calendars.4.3.0\lib\net46\System.Globalization.Calendars.dll
True
@@ -175,6 +176,7 @@
packages\System.Text.Encoding.CodePages.5.0.0\lib\net461\System.Text.Encoding.CodePages.dll
+
@@ -188,6 +190,7 @@
True
True
+
@@ -281,48 +284,34 @@
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
-
+
+
+
+
-
-
+
+
+
+
+
+
+
diff --git a/DialogWindow.xaml b/DialogWindow.xaml
index 4b39c70..b0e1d48 100644
--- a/DialogWindow.xaml
+++ b/DialogWindow.xaml
@@ -13,10 +13,9 @@
TextOptions.TextRenderingMode="ClearType"
ShowInTaskbar="False"
UseLayoutRounding="True"
- Title="DialogWindow" Width="1280" Height="590">
+ Title="DialogWindow" Width="1280" Height="730">
/BetterHI3Launcher;component/Assets/Fonts/#FZLanTingHei-B-GBK
- /BetterHI3Launcher;component/Assets/Fonts/#FZLanTingHei-B-GBK
@@ -29,7 +28,7 @@
-
+
+
+
-
+
-
-
+
+
-
-
+
+
@@ -255,15 +340,89 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
@@ -385,7 +544,7 @@
-
+
diff --git a/MainWindow.xaml.cs b/MainWindow.xaml.cs
index 6c085f6..f818613 100644
--- a/MainWindow.xaml.cs
+++ b/MainWindow.xaml.cs
@@ -20,7 +20,10 @@
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
+using System.Web;
using System.Windows;
+using System.Windows.Automation.Peers;
+using System.Windows.Automation.Provider;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
@@ -32,7 +35,7 @@ namespace BetterHI3Launcher
{
enum LauncherStatus
{
- Ready, Error, CheckingUpdates, Downloading, Updating, Verifying, Unpacking, CleaningUp, UpdateAvailable, Uninstalling, Working, DownloadPaused, Running
+ Ready, Error, CheckingUpdates, Downloading, Updating, Verifying, Unpacking, CleaningUp, UpdateAvailable, Uninstalling, Working, DownloadPaused, Running, Preloading, PreloadVerifying
}
enum HI3Server
{
@@ -45,7 +48,7 @@ enum HI3Mirror
public partial class MainWindow : Window
{
- public static readonly Version LocalLauncherVersion = new Version("1.1.20210513.0");
+ public static readonly Version LocalLauncherVersion = new Version("1.2.20210527.0");
public static readonly string RootPath = Directory.GetCurrentDirectory();
public static readonly string LocalLowPath = $"{Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)}Low";
public static readonly string LauncherDataPath = Path.Combine(LocalLowPath, @"Bp\Better HI3 Launcher");
@@ -62,6 +65,7 @@ public partial class MainWindow : Window
public static string[] CommandLineArgs = Environment.GetCommandLineArgs();
public static bool FirstLaunch = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Bp\Better HI3 Launcher") == null ? true : false;
public static bool DisableAutoUpdate, DisableLogging, DisableSounds, AdvancedFeatures, DownloadPaused, PatchDownload;
+ public static int PatchDownloadInt;
public static Dictionary textStrings = new Dictionary();
public dynamic LocalVersionInfo, OnlineVersionInfo, OnlineRepairInfo, miHoYoVersionInfo, GameGraphicSettings, GameScreenSettings, GameCacheMetadata, GameCacheMetadataNumeric;
LauncherStatus _status;
@@ -111,6 +115,7 @@ void ToggleProgressBar(bool val)
break;
case LauncherStatus.CheckingUpdates:
ProgressText.Text = textStrings["progresstext_checkingupdate"];
+ PreloadGrid.Visibility = Visibility.Collapsed;
ToggleUI(false);
ToggleProgressBar(true);
break;
@@ -130,6 +135,27 @@ void ToggleProgressBar(bool val)
ToggleProgressBar(false);
ToggleContextMenuItems(false);
break;
+ case LauncherStatus.Preloading:
+ PreloadBottomText.Text = textStrings["button_downloading"];
+ PreloadButton.Visibility = Visibility.Collapsed;
+ PreloadPauseButton.IsEnabled = true;
+ PreloadPauseButton.Visibility = Visibility.Visible;
+ PreloadPauseButton.Background = (ImageBrush)Resources["PreloadPauseButton"];
+ PreloadCircle.Visibility = Visibility.Visible;
+ PreloadCircleProgressBar.Visibility = Visibility.Visible;
+ TaskbarItemInfo.ProgressState = TaskbarItemProgressState.Normal;
+ ServerDropdown.IsEnabled = false;
+ MirrorDropdown.IsEnabled = false;
+ ToggleContextMenuItems(false);
+ break;
+ case LauncherStatus.PreloadVerifying:
+ PreloadPauseButton.IsEnabled = false;
+ PreloadCircleProgressBar.Value = 0;
+ PreloadBottomText.Text = textStrings["label_verifying"];
+ PreloadStatusMiddleRightText.Text = string.Empty;
+ PreloadStatusBottomRightText.Text = string.Empty;
+ TaskbarItemInfo.ProgressState = TaskbarItemProgressState.Indeterminate;
+ break;
case LauncherStatus.Working:
ToggleUI(false);
ToggleProgressBar(true);
@@ -180,14 +206,14 @@ internal HI3Server Server
{
case HI3Server.Global:
RegistryVersionInfo = "VersionInfoGlobal";
- GameRegistryPath = @"SOFTWARE\miHoYo\Honkai Impact 3rd";
GameFullName = "Honkai Impact 3rd";
+ GameRegistryPath = $@"SOFTWARE\miHoYo\{GameFullName}";
GameWebProfileURL = "https://global.user.honkaiimpact3.com";
break;
case HI3Server.SEA:
RegistryVersionInfo = "VersionInfoSEA";
- GameRegistryPath = @"SOFTWARE\miHoYo\Honkai Impact 3";
GameFullName = "Honkai Impact 3";
+ GameRegistryPath = $@"SOFTWARE\miHoYo\{GameFullName}";
GameWebProfileURL = "https://asia.user.honkaiimpact3.com";
break;
}
@@ -271,14 +297,14 @@ public MainWindow()
{
if(File.Exists(LauncherLogFile))
{
- string old_log_path_1 = Path.Combine(LauncherDataPath, $"BetterHI3Launcher-old1.log");
+ string old_log_path_1 = Path.Combine(LauncherDataPath, "BetterHI3Launcher-old1.log");
for(int i = 9; i > 0; i--)
{
string old_log_path_2 = Path.Combine(LauncherDataPath, $"BetterHI3Launcher-old{i}.log");
if(File.Exists(old_log_path_2))
{
string old_log_path_3 = Path.Combine(LauncherDataPath, $"BetterHI3Launcher-old{i + 1}.log");
- string old_log_path_4 = Path.Combine(LauncherDataPath, $"BetterHI3Launcher-old10.log");
+ string old_log_path_4 = Path.Combine(LauncherDataPath, "BetterHI3Launcher-old10.log");
if(File.Exists(old_log_path_4))
{
File.Delete(old_log_path_4);
@@ -291,7 +317,7 @@ public MainWindow()
}
catch
{
- Log($"WARNING: Unable to rename log files", true, 2);
+ Log("WARNING: Unable to rename log files", true, 2);
}
}
DeleteFile(LauncherLogFile, true);
@@ -428,12 +454,18 @@ public MainWindow()
ChangelogBoxMessageTextBlock.Text = textStrings["changelogbox_1_msg"];
ChangelogBoxOKButton.Content = textStrings["button_ok"];
AboutBoxTitleTextBlock.Text = textStrings["contextmenu_about"];
+ AboutBoxAppNameTextBlock.Text += $" v{LocalLauncherVersion}";
AboutBoxMessageTextBlock.Text = $"{textStrings["aboutbox_msg"]}\n\nMade by Bp (BuIlDaLiBlE production).";
AboutBoxGitHubButton.Content = textStrings["button_github"];
AboutBoxOKButton.Content = textStrings["button_ok"];
ShowLogLabel.Text = textStrings["label_log"];
+ PreloadTopText.Text = textStrings["label_preload"];
+ PreloadStatusTopLeftText.Text = textStrings["label_downloaded_2"];
+ PreloadStatusMiddleLeftText.Text = textStrings["label_eta"];
+ PreloadStatusBottomLeftText.Text = textStrings["label_speed"];
Grid.MouseLeftButtonDown += delegate{DragMove();};
+ PreloadGrid.Visibility = Visibility.Collapsed;
LogBox.Visibility = Visibility.Collapsed;
LogBoxRichTextBox.Document.PageWidth = LogBox.Width;
IntroBox.Visibility = Visibility.Collapsed;
@@ -524,6 +556,7 @@ public MainWindow()
var CMAbout = new MenuItem{Header = textStrings["contextmenu_about"]};
CMAbout.Click += (sender, e) => CM_About_Click(sender, e);
OptionsContextMenu.Items.Add(CMAbout);
+
if(LanguageRegValue == null)
{
CMLanguageSystem.IsChecked = true;
@@ -672,9 +705,9 @@ public MainWindow()
private void FetchOnlineVersionInfo()
{
#if DEBUG
- var version_info_url = new[]{"https://bpnet.host/bh3?launcherstatus_debug"};
+ var version_info_url = new[]{"https://bpnet.host/bh3?launcher_status=debug"};
#else
- var version_info_url = new[]{"https://bpnet.host/bh3?launcherstatus", "https://serioussam.ucoz.ru/bbh3l_prod.json"};
+ var version_info_url = new[]{"https://bpnet.host/bh3?launcher_status=prod", "https://serioussam.ucoz.ru/bbh3l_prod.json"};
#endif
string version_info;
var webClient = new BpWebClient();
@@ -689,16 +722,10 @@ private void FetchOnlineVersionInfo()
OnlineVersionInfo = JsonConvert.DeserializeObject(version_info);
if(OnlineVersionInfo.status == "success")
{
- OnlineVersionInfo = OnlineVersionInfo.launcherstatus;
+ OnlineVersionInfo = OnlineVersionInfo.launcher_status;
LauncherExeName = OnlineVersionInfo.launcher_info.name;
LauncherPath = Path.Combine(RootPath, LauncherExeName);
LauncherArchivePath = Path.Combine(RootPath, OnlineVersionInfo.launcher_info.url.ToString().Substring(OnlineVersionInfo.launcher_info.url.ToString().LastIndexOf('/') + 1));
- Dispatcher.Invoke(() =>
- {
- LauncherVersionText.Text = $"{textStrings["launcher_version"]}: v{LocalLauncherVersion}";
- ShowLogStackPanel.Margin = new Thickness((double)OnlineVersionInfo.launcher_info.ui.ShowLogStackPanel_Margin.left, 0, 0, (double)OnlineVersionInfo.launcher_info.ui.ShowLogStackPanel_Margin.bottom);
- LogBox.Margin = new Thickness((double)OnlineVersionInfo.launcher_info.ui.LogBox_Margin.left, (double)OnlineVersionInfo.launcher_info.ui.LogBox_Margin.top, (double)OnlineVersionInfo.launcher_info.ui.LogBox_Margin.right, (double)OnlineVersionInfo.launcher_info.ui.LogBox_Margin.bottom);
- });
}
else
{
@@ -741,9 +768,9 @@ private void FetchmiHoYoVersionInfo()
{
string url;
if(Server == HI3Server.Global)
- url = OnlineVersionInfo.game_info.mirror.mihoyo.version_info.global.ToString();
+ url = OnlineVersionInfo.game_info.mirror.mihoyo.resource_info.global.ToString();
else
- url = OnlineVersionInfo.game_info.mirror.mihoyo.version_info.os.ToString();
+ url = OnlineVersionInfo.game_info.mirror.mihoyo.resource_info.os.ToString();
var webRequest = BpUtility.CreateWebRequest(url);
using(var webResponse = (HttpWebResponse)webRequest.GetResponse())
@@ -752,19 +779,33 @@ private void FetchmiHoYoVersionInfo()
{
webResponse.GetResponseStream().CopyTo(data);
miHoYoVersionInfo = JsonConvert.DeserializeObject(Encoding.UTF8.GetString(data.ToArray()));
- miHoYoVersionInfo.last_modified = webResponse.LastModified.ToUniversalTime().ToString();
+ if(miHoYoVersionInfo.retcode == 0)
+ {
+ if(miHoYoVersionInfo.data != null)
+ {
+ miHoYoVersionInfo = miHoYoVersionInfo.data;
+ }
+ else
+ {
+ throw new WebException();
+ }
+ }
+ else
+ {
+ throw new WebException(miHoYoVersionInfo.message.ToString());
+ }
}
}
- GameArchiveName = miHoYoVersionInfo.full_version_file.name.ToString();
- webRequest = BpUtility.CreateWebRequest($"{miHoYoVersionInfo.download_url}/{GameArchiveName}", "HEAD");
+ GameArchiveName = Path.GetFileName(HttpUtility.UrlDecode(miHoYoVersionInfo.game.latest.path.ToString()));
+ webRequest = BpUtility.CreateWebRequest(miHoYoVersionInfo.game.latest.path.ToString(), "HEAD");
using(var webResponse = (HttpWebResponse)webRequest.GetResponse())
{
miHoYoVersionInfo.size = webResponse.ContentLength;
+ miHoYoVersionInfo.last_modified = webResponse.LastModified.ToUniversalTime().ToString();
}
Dispatcher.Invoke(() =>
{
- GameVersionText.Visibility = Visibility.Visible;
- GameVersionText.Text = $"{textStrings["version"]}: v{miHoYoVersionInfo.cur_version.ToString()}";
+ GameVersionText.Text = $"{textStrings["version"]}: v{miHoYoVersionInfo.game.latest.version.ToString()}";
});
}
@@ -897,7 +938,7 @@ private dynamic FetchGDFileMetadata(string id)
private bool LauncherUpdateCheck()
{
var OnlineLauncherVersion = new Version(OnlineVersionInfo.launcher_info.version.ToString());
- if(LocalLauncherVersion.IsDifferentThan(OnlineLauncherVersion))
+ if(OnlineLauncherVersion.IsNewerThan(LocalLauncherVersion))
{
return true;
}
@@ -925,29 +966,41 @@ await Task.Run(() =>
if(Mirror == HI3Mirror.miHoYo)
{
// space_usage is probably when archive is unpacked, here I get the download size instead
- // download_size = miHoYoVersionInfo.space_usage;
+ // download_size = (long)miHoYoVersionInfo.game.latest.size;
download_size = miHoYoVersionInfo.size;
}
else if(Mirror == HI3Mirror.MediaFire)
{
dynamic mediafire_metadata;
if(Server == HI3Server.Global)
+ {
mediafire_metadata = FetchMediaFireFileMetadata(OnlineVersionInfo.game_info.mirror.mediafire.game_archive.global.id.ToString(), false);
+ }
else
+ {
mediafire_metadata = FetchMediaFireFileMetadata(OnlineVersionInfo.game_info.mirror.mediafire.game_archive.os.id.ToString(), false);
+ }
if(mediafire_metadata == null)
+ {
return;
+ }
download_size = mediafire_metadata.fileSize;
}
else if(Mirror == HI3Mirror.GoogleDrive)
{
dynamic gd_metadata;
if(Server == HI3Server.Global)
+ {
gd_metadata = FetchGDFileMetadata(OnlineVersionInfo.game_info.mirror.gd.game_archive.global.ToString());
+ }
else
+ {
gd_metadata = FetchGDFileMetadata(OnlineVersionInfo.game_info.mirror.gd.game_archive.os.ToString());
+ }
if(gd_metadata == null)
+ {
return;
+ }
download_size = gd_metadata.fileSize;
}
if(LauncherRegKey.GetValue(RegistryVersionInfo) != null)
@@ -959,7 +1012,9 @@ await Task.Run(() =>
{
var data = new FileIniDataParser().ReadFile(config_ini_file);
if(data["General"]["game_version"] != null)
+ {
LocalVersionInfo.game_info.version = data["General"]["game_version"];
+ }
}
var LocalGameVersion = new GameVersion(LocalVersionInfo.game_info.version.ToString());
game_needs_update = GameUpdateCheckSimple(LocalGameVersion);
@@ -973,12 +1028,13 @@ await Task.Run(() =>
PatchDownload = false;
if(game_needs_update == 2 && Mirror == HI3Mirror.miHoYo)
{
- var webRequest = BpUtility.CreateWebRequest($"{miHoYoVersionInfo.download_url}/{miHoYoVersionInfo.patch_list[LocalGameVersion.ToString()].name.ToString()}", "HEAD");
+ var url = miHoYoVersionInfo.game.diffs[PatchDownloadInt].path.ToString();
+ var webRequest = BpUtility.CreateWebRequest(url, "HEAD");
using(var webResponse = (HttpWebResponse)webRequest.GetResponse())
{
download_size = webResponse.ContentLength;
}
- GameArchiveName = miHoYoVersionInfo.patch_list[LocalGameVersion.ToString()].name.ToString();
+ GameArchiveName = Path.GetFileName(HttpUtility.UrlDecode(url));
GameArchivePath = Path.Combine(GameInstallPath, GameArchiveName);
PatchDownload = true;
}
@@ -992,7 +1048,7 @@ await Task.Run(() =>
}
else if(!File.Exists(GameExePath))
{
- Log($"WARNING: Game executable is missing, resetting game version info...", true, 2);
+ Log("WARNING: Game executable is missing, resetting game version info...", true, 2);
DeleteGameFiles();
GameUpdateCheck();
return;
@@ -1021,9 +1077,13 @@ await Task.Run(() =>
Dispatcher.Invoke(() =>
{
if(remaining_size > 0)
+ {
ProgressText.Text = $"{textStrings["progresstext_downloadsize"]}: {BpUtility.ToBytesCount(remaining_size)}";
+ }
else
- ProgressText.Text = String.Empty;
+ {
+ ProgressText.Text = string.Empty;
+ }
LaunchButton.Content = textStrings["button_update"];
});
}
@@ -1036,12 +1096,48 @@ await Task.Run(() =>
});
}
}
+ else
+ {
+ Dispatcher.Invoke(() =>
+ {
+ if(miHoYoVersionInfo.pre_download_game != null)
+ {
+ var path = Path.Combine(GameInstallPath, Path.GetFileName(HttpUtility.UrlDecode(miHoYoVersionInfo.pre_download_game.latest.path.ToString())));
+ if(File.Exists(path))
+ {
+ PreloadButton.Visibility = Visibility.Collapsed;
+ PreloadCheckmark.Visibility = Visibility.Visible;
+ PreloadCircle.Visibility = Visibility.Visible;
+ PreloadCircleProgressBar.Visibility = Visibility.Visible;
+ PreloadCircleProgressBar.Value = 100;
+ PreloadBottomText.Text = textStrings["label_done"];
+ }
+ else
+ {
+ PreloadButton.Visibility = Visibility.Visible;
+ PreloadCheckmark.Visibility = Visibility.Collapsed;
+ PreloadCircle.Visibility = Visibility.Collapsed;
+ PreloadCircleProgressBar.Visibility = Visibility.Collapsed;
+ PreloadCircleProgressBar.Value = 0;
+ PreloadBottomText.Text = textStrings["label_get_now"];
+ }
+ PreloadPauseButton.Visibility = Visibility.Collapsed;
+ PreloadGrid.Visibility = Visibility.Visible;
+ }
+ else
+ {
+ PreloadGrid.Visibility = Visibility.Collapsed;
+ }
+ });
+ }
}
else
{
Log("Game is not installed :^(");
if(serverChanged)
+ {
FetchmiHoYoVersionInfo();
+ }
Status = LauncherStatus.Ready;
Dispatcher.Invoke(() =>
{
@@ -1067,7 +1163,9 @@ await Task.Run(() =>
if(server >= 0)
{
if((int)Server != server)
+ {
ServerDropdown.SelectedIndex = server;
+ }
WriteVersionInfo(true, true);
GameUpdateCheck();
}
@@ -1084,7 +1182,9 @@ await Task.Run(() =>
});
}
if(serverChanged)
+ {
DownloadBackgroundImage();
+ }
}
catch(Exception ex)
{
@@ -1104,12 +1204,16 @@ private int GameUpdateCheckSimple(GameVersion LocalGameVersion)
if(LocalVersionInfo != null)
{
FetchmiHoYoVersionInfo();
- var onlineGameVersion = new GameVersion(miHoYoVersionInfo.cur_version.ToString());
- if(onlineGameVersion.IsDifferentThan(LocalGameVersion))
+ var onlineGameVersion = new GameVersion(miHoYoVersionInfo.game.latest.version.ToString());
+ if(onlineGameVersion.IsNewerThan(LocalGameVersion))
{
- if(miHoYoVersionInfo.patch_list[LocalGameVersion.ToString()] != null)
+ for(var i = 0; i < miHoYoVersionInfo.game.diffs.Count; i++)
{
- return 2;
+ if(miHoYoVersionInfo.game.diffs[i].version == LocalGameVersion.ToString())
+ {
+ PatchDownloadInt = i;
+ return 2;
+ }
}
return 1;
}
@@ -1158,29 +1262,63 @@ private void DownloadLauncherUpdate()
private void DownloadBackgroundImage()
{
- string backgroundImageName = miHoYoVersionInfo.bg_file_name.ToString();
- string backgroundImagePath = Path.Combine(LauncherDataPath, backgroundImageName);
- if(File.Exists(backgroundImagePath))
- {
- Log($"Background image {backgroundImageName} exists, using it");
- Dispatcher.Invoke(() => {BackgroundImage.Source = new BitmapImage(new Uri(backgroundImagePath));});
- }
- else
+ try
{
- Log($"Background image {backgroundImageName} doesn't exist, downloading...");
- try
+ string url = miHoYoVersionInfo.data.adv.background.ToString();
+ string background_image_url;
+ var webRequest = BpUtility.CreateWebRequest(url);
+ using(var webResponse = (HttpWebResponse)webRequest.GetResponse())
{
- var webClient = new BpWebClient();
- Directory.CreateDirectory(LauncherDataPath);
- webClient.DownloadFile(new Uri($"{miHoYoVersionInfo.download_url.ToString()}/{miHoYoVersionInfo.bg_file_name.ToString()}"), backgroundImagePath);
- Dispatcher.Invoke(() => {BackgroundImage.Source = new BitmapImage(new Uri(backgroundImagePath));});
- Log("success!", false);
+ using(var data = new MemoryStream())
+ {
+ webResponse.GetResponseStream().CopyTo(data);
+ var json = JsonConvert.DeserializeObject(Encoding.UTF8.GetString(data.ToArray()));
+ if(json.retcode == 0)
+ {
+ if(json.data.adv.background != null)
+ {
+ background_image_url = json.data.adv.background.ToString();
+ }
+ else
+ {
+ throw new WebException();
+ }
+ }
+ else
+ {
+ Log($"WARNING: Failed to fetch background image info: {json.message.ToString()}", true, 2);
+ throw new WebException();
+ }
+ }
}
- catch(Exception ex)
+ string background_image_name = Path.GetFileName(HttpUtility.UrlDecode(background_image_url));
+ string background_image_path = Path.Combine(LauncherDataPath, background_image_name);
+ if(File.Exists(background_image_path))
{
- Log($"ERROR: Failed to download background image:\n{ex}", true, 1);
+ Dispatcher.Invoke(() => {BackgroundImage.Source = new BitmapImage(new Uri(background_image_path));});
+ }
+ else
+ {
+ Log("Downloading background image...");
+ try
+ {
+ var webClient = new BpWebClient();
+ Directory.CreateDirectory(LauncherDataPath);
+ webClient.DownloadFile(background_image_url, background_image_path);
+ Dispatcher.Invoke(() => {BackgroundImage.Source = new BitmapImage(new Uri(background_image_path));});
+ Log("success!", false);
+ }
+ catch(Exception ex)
+ {
+ Log($"WARNING: Failed to download background image:\n{ex}", true, 2);
+ throw new WebException();
+ }
}
}
+ catch
+ {
+ Dispatcher.Invoke(() => {BackgroundImage.Source = (BitmapImage)Resources["BackgroundImage"];});
+ }
}
private async Task DownloadGameFile()
@@ -1196,11 +1334,11 @@ private async Task DownloadGameFile()
{
title = GameArchiveName;
time = -1;
- url = $"{miHoYoVersionInfo.download_url.ToString()}/{GameArchiveName}";
+ url = miHoYoVersionInfo.game.latest.path.ToString();
if(PatchDownload)
- md5 = miHoYoVersionInfo.patch_list[LocalVersionInfo.game_info.version.ToString()].md5.ToString();
+ md5 = miHoYoVersionInfo.game.diffs[PatchDownloadInt].md5.ToString();
else
- md5 = miHoYoVersionInfo.full_version_file.md5.ToString();
+ md5 = miHoYoVersionInfo.game.latest.md5.ToString();
}
else if(Mirror == HI3Mirror.MediaFire)
{
@@ -1216,10 +1354,10 @@ private async Task DownloadGameFile()
url = mediafire_metadata.downloadUrl.ToString();
md5 = mediafire_metadata.md5Checksum.ToString();
GameArchivePath = Path.Combine(GameInstallPath, title);
- if(!mediafire_metadata.title.Contains(miHoYoVersionInfo.cur_version.ToString().Substring(0, 17)))
+ if(!mediafire_metadata.title.Contains(miHoYoVersionInfo.game.latest.version.ToString()))
{
Status = LauncherStatus.Error;
- Log($"ERROR: Mirror is outdated!", true, 1);
+ Log("ERROR: Mirror is outdated!", true, 1);
new DialogWindow(textStrings["msgbox_gamedownloaderror_title"], textStrings["msgbox_gamedownloadmirrorold_msg"]).ShowDialog();
Status = LauncherStatus.Ready;
return;
@@ -1255,7 +1393,7 @@ private async Task DownloadGameFile()
if(DateTime.Compare(DateTime.Parse(miHoYoVersionInfo.last_modified.ToString()), DateTime.Parse(gd_metadata.modifiedDate.ToString())) > 0)
{
Status = LauncherStatus.Error;
- Log($"ERROR: Mirror is outdated!", true, 1);
+ Log("ERROR: Mirror is outdated!", true, 1);
new DialogWindow(textStrings["msgbox_gamedownloaderror_title"], textStrings["msgbox_gamedownloadmirrorold_msg"]).ShowDialog();
Status = LauncherStatus.Ready;
return;
@@ -1324,7 +1462,9 @@ await Task.Run(() =>
download = null;
Log("Successfully downloaded game archive");
while(BpUtility.IsFileLocked(new FileInfo(GameArchivePath)))
+ {
Thread.Sleep(10);
+ }
Dispatcher.Invoke(() =>
{
ProgressText.Text = string.Empty;
@@ -1334,7 +1474,9 @@ await Task.Run(() =>
try
{
if(abort)
+ {
return;
+ }
await Task.Run(() =>
{
Log("Validating game archive...");
@@ -1426,7 +1568,9 @@ await Task.Run(() =>
GameUpdateCheck();
});
if(time != -1)
+ {
SendStatistics(title, time);
+ }
});
}
catch(Exception ex)
@@ -1461,9 +1605,13 @@ private void WriteVersionInfo(bool CheckForLocalVersion = false, bool IsInstalle
dynamic versionInfo = new ExpandoObject();
versionInfo.game_info = new ExpandoObject();
if(!PatchDownload)
- versionInfo.game_info.version = miHoYoVersionInfo.cur_version.ToString();
+ {
+ versionInfo.game_info.version = miHoYoVersionInfo.game.latest.version.ToString();
+ }
else
+ {
versionInfo.game_info.version = LocalVersionInfo.game_info.version.ToString();
+ }
versionInfo.game_info.install_path = GameInstallPath;
versionInfo.game_info.installed = IsInstalled;
@@ -1478,23 +1626,29 @@ private void WriteVersionInfo(bool CheckForLocalVersion = false, bool IsInstalle
{
var data = ini_parser.ReadFile(config_ini_file);
if(data["General"]["game_version"] != null)
+ {
versionInfo.game_info.version = data["General"]["game_version"];
+ }
}
else if(LauncherRegKey.GetValue(RegistryVersionInfo) == null && (key != null && key.GetValue(GameRegistryLocalVersionRegValue) != null && key.GetValueKind(GameRegistryLocalVersionRegValue) == RegistryValueKind.Binary))
{
var version = Encoding.UTF8.GetString((byte[])key.GetValue(GameRegistryLocalVersionRegValue)).TrimEnd('\u0000');
- if(!miHoYoVersionInfo.cur_version.ToString().Contains(version))
- versionInfo.game_info.version = $"{version}_xxxxxxxxxx";
+ if(!miHoYoVersionInfo.game.latest.version.ToString().Contains(version))
+ {
+ versionInfo.game_info.version = version;
+ }
}
else
{
if(new DialogWindow(textStrings["msgbox_install_title"], textStrings["msgbox_install_existing_no_local_version_msg"], true).ShowDialog() == false)
{
- versionInfo.game_info.version = "0.0.0_xxxxxxxxxx";
+ versionInfo.game_info.version = new GameVersion();
}
}
if(key != null)
+ {
key.Close();
+ }
}
Log("Writing game version info...");
LauncherRegKey.SetValue(RegistryVersionInfo, Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(versionInfo)), RegistryValueKind.Binary);
@@ -1771,6 +1925,7 @@ private async void Window_ContentRendered(object sender, EventArgs e)
return;
}
DeleteFile(Path.Combine(RootPath, oldExeName), true);
+ DeleteFile(Path.Combine(RootPath, "BetterHI3Launcher.exe.bak"), true); // legacy name
await Task.Run(() =>
{
if(DisableAutoUpdate)
@@ -1834,11 +1989,14 @@ await Task.Run(() =>
{
IntroBox.Visibility = Visibility.Visible;
}
- if(LauncherRegKey != null && LauncherRegKey.GetValue("LauncherVersion") != null && LauncherRegKey.GetValue("LauncherVersion").ToString() != LocalLauncherVersion.ToString())
+ if(LauncherRegKey != null && LauncherRegKey.GetValue("LauncherVersion") != null)
{
- ChangelogBox.Visibility = Visibility.Visible;
- ChangelogBoxMessageTextBlock.Visibility = Visibility.Visible;
- FetchChangelog();
+ if(new Version(LocalLauncherVersion.ToString()).IsNewerThan(new Version(LauncherRegKey.GetValue("LauncherVersion").ToString())))
+ {
+ ChangelogBox.Visibility = Visibility.Visible;
+ ChangelogBoxMessageTextBlock.Visibility = Visibility.Visible;
+ FetchChangelog();
+ }
}
try
{
@@ -1847,8 +2005,8 @@ await Task.Run(() =>
// legacy values
if(LauncherRegKey.GetValue("RanOnce") != null)
LauncherRegKey.DeleteValue("RanOnce");
- if(LauncherRegKey.GetValue("BackgroundImageName") != null)
- LauncherRegKey.DeleteValue("BackgroundImageName");
+ if(LauncherRegKey.GetValue("background_image_name") != null)
+ LauncherRegKey.DeleteValue("background_image_name");
}
catch(Exception ex)
{
@@ -1877,7 +2035,7 @@ private void MinimizeButton_Click(object sender, RoutedEventArgs e)
private async void LaunchButton_Click(object sender, RoutedEventArgs e)
{
BpUtility.PlaySound(Properties.Resources.Click);
- if(Status == LauncherStatus.Ready)
+ if(Status == LauncherStatus.Ready || Status == LauncherStatus.Preloading || Status == LauncherStatus.PreloadVerifying)
{
if(DownloadPaused)
{
@@ -1969,7 +2127,7 @@ string SelectGameInstallDirectory()
}
else
{
- var path = CheckForExistingGameDirectory(GameInstallPath);
+ var path = CheckForExistingGameDirectory(dialog.FileName);
if(path.Length < 4)
{
path = string.Empty;
@@ -2014,7 +2172,7 @@ string SelectGameInstallDirectory()
new DialogWindow(textStrings["msgbox_installerror_title"], textStrings["msgbox_install_wrong_drive_type_msg"]).ShowDialog();
return;
}
- else if(gameInstallDrive.TotalFreeSpace < 24696061952)
+ else if(gameInstallDrive.TotalFreeSpace < (long)miHoYoVersionInfo.game.latest.size)
{
if(new DialogWindow(textStrings["msgbox_install_title"], textStrings["msgbox_install_little_space_msg"], true).ShowDialog() == false)
return;
@@ -2038,13 +2196,15 @@ string SelectGameInstallDirectory()
else if(Status == LauncherStatus.UpdateAvailable)
{
var gameInstallDrive = DriveInfo.GetDrives().Where(x => x.Name == Path.GetPathRoot(GameInstallPath) && x.IsReady).FirstOrDefault();
- if(gameInstallDrive.TotalFreeSpace < 24696061952)
+ if(gameInstallDrive.TotalFreeSpace < (long)miHoYoVersionInfo.game.latest.size)
{
if(new DialogWindow(textStrings["msgbox_install_title"], textStrings["msgbox_install_little_space_msg"], true).ShowDialog() == false)
return;
}
if(!PatchDownload)
+ {
Directory.CreateDirectory(GameInstallPath);
+ }
await DownloadGameFile();
}
else if(Status == LauncherStatus.Downloading || Status == LauncherStatus.DownloadPaused)
@@ -2077,6 +2237,171 @@ private void OptionsButton_Click(object sender, RoutedEventArgs e)
BpUtility.PlaySound(Properties.Resources.Click);
}
+ private async void PreloadButton_Click(object sender, RoutedEventArgs e)
+ {
+ if(Status != LauncherStatus.Ready)
+ return;
+
+ try
+ {
+ string url = miHoYoVersionInfo.pre_download_game.latest.path.ToString();
+ string title = Path.GetFileName(HttpUtility.UrlDecode(url));
+ long size;
+ string md5 = miHoYoVersionInfo.pre_download_game.latest.md5.ToString();
+ string path = Path.Combine(GameInstallPath, $"{title}_tmp");
+ bool abort = false;
+
+ var webRequest = BpUtility.CreateWebRequest(url, "HEAD");
+ using(var webResponse = (HttpWebResponse) webRequest.GetResponse())
+ {
+ size = webResponse.ContentLength;
+ }
+ if(!File.Exists(path))
+ {
+ if(new DialogWindow(textStrings["label_preload"], $"{textStrings["msgbox_preload_msg"]}\n{textStrings["progresstext_downloadsize"]}: {BpUtility.ToBytesCount(size)}", true).ShowDialog() == false)
+ {
+ return;
+ }
+ var gameInstallDrive = DriveInfo.GetDrives().Where(x => x.Name == Path.GetPathRoot(GameInstallPath) && x.IsReady).FirstOrDefault();
+ if(gameInstallDrive.TotalFreeSpace < (long)miHoYoVersionInfo.pre_download_game.latest.size)
+ {
+ if(new DialogWindow(textStrings["msgbox_install_title"], textStrings["msgbox_install_little_space_msg"], true).ShowDialog() == false)
+ {
+ return;
+ }
+ }
+ Log($"Starting to preload game: {title} ({url})");
+ }
+ else
+ {
+ Log("Preload resumed");
+ }
+ Status = LauncherStatus.Preloading;
+ await Task.Run(() =>
+ {
+ tracker.NewFile();
+ var eta_calc = new ETACalculator(1, 1);
+ download = new DownloadPauseable(url, path);
+ download.Start();
+ while(download != null && !download.Done)
+ {
+ tracker.SetProgress(download.BytesWritten, download.ContentLength);
+ eta_calc.Update((float)download.BytesWritten / (float)download.ContentLength);
+ Dispatcher.Invoke(() =>
+ {
+ var progress = tracker.GetProgress();
+ PreloadCircleProgressBar.Value = progress;
+ TaskbarItemInfo.ProgressValue = progress;
+ PreloadBottomText.Text = string.Format(textStrings["label_downloaded_1"], Math.Round(progress * 100));
+ PreloadStatusTopRightText.Text = $"{BpUtility.ToBytesCount(download.BytesWritten)}/{BpUtility.ToBytesCount(download.ContentLength)}";
+ PreloadStatusMiddleRightText.Text = eta_calc.ETR.ToString("hh\\:mm\\:ss");
+ PreloadStatusBottomRightText.Text = tracker.GetBytesPerSecondString();
+ });
+ Thread.Sleep(100);
+ }
+ if(download == null)
+ {
+ abort = true;
+ Status = LauncherStatus.Ready;
+ return;
+ }
+ Log("Downloaded preload archive");
+ while(BpUtility.IsFileLocked(new FileInfo(path)))
+ {
+ Thread.Sleep(10);
+ }
+ });
+ if(abort)
+ {
+ return;
+ }
+ Status = LauncherStatus.PreloadVerifying;
+ try
+ {
+ await Task.Run(() =>
+ {
+ Log("Validating preload archive...");
+ string actual_md5 = BpUtility.CalculateMD5(path);
+ if(actual_md5 == md5.ToUpper())
+ {
+ Log("success!", false);
+ var new_path = path.Substring(0, path.Length - 4);
+ if(!File.Exists(new_path))
+ {
+ File.Move(path, new_path);
+ }
+ else if(File.Exists(new_path) && new FileInfo(new_path).Length != size)
+ {
+ DeleteFile(new_path, true);
+ File.Move(path, new_path);
+ }
+ else
+ {
+ DeleteFile(path);
+ }
+ Log("Successfully preloaded the game");
+ GameUpdateCheck();
+ }
+ else
+ {
+ Status = LauncherStatus.Error;
+ Log($"ERROR: Validation failed. Expected MD5: {md5}, got MD5: {actual_md5}", true, 1);
+ DeleteFile(path);
+ Dispatcher.Invoke(() =>
+ {
+ PreloadBottomText.Text = textStrings["label_retry"];
+ });
+ Status = LauncherStatus.Ready;
+ }
+ });
+ }
+ catch(Exception ex)
+ {
+ Status = LauncherStatus.Error;
+ Log($"ERROR: Failed to preload the game:\n{ex}", true, 1);
+ new DialogWindow(textStrings["msgbox_installerror_title"], textStrings["msgbox_installerror_msg"]).ShowDialog();
+ Status = LauncherStatus.Ready;
+ }
+ }
+ catch(Exception ex)
+ {
+ Status = LauncherStatus.Error;
+ Log($"ERROR: Failed to download game preload archive:\n{ex}", true, 1);
+ new DialogWindow(textStrings["msgbox_gamedownloaderror_title"], textStrings["msgbox_gamedownloaderror_msg"]).ShowDialog();
+ Status = LauncherStatus.Ready;
+ }
+ TaskbarItemInfo.ProgressState = TaskbarItemProgressState.None;
+ WindowState = WindowState.Normal;
+ }
+
+ private void PreloadPauseButton_Click(object sender, RoutedEventArgs e)
+ {
+ if(download != null)
+ {
+ Log("Preload paused");
+ download.Pause();
+ download = null;
+ PreloadPauseButton.Background = (ImageBrush)Resources["PreloadResumeButton"];
+ PreloadBottomText.Text = PreloadBottomText.Text.Replace(textStrings["label_downloaded_1"], textStrings["label_paused"]);
+ PreloadStatusMiddleRightText.Text = string.Empty;
+ PreloadStatusBottomRightText.Text = string.Empty;
+ TaskbarItemInfo.ProgressState = TaskbarItemProgressState.None;
+ }
+ else
+ {
+ try
+ {
+ var peer = new ButtonAutomationPeer(PreloadButton);
+ var inv_prov = peer.GetPattern(PatternInterface.Invoke) as IInvokeProvider;
+ inv_prov.Invoke();
+ }
+ catch(Exception ex)
+ {
+ Log($"ERROR: Failed to resume downloading game preload archive:\n{ex}", true, 1);
+ }
+ }
+ }
+
private async Task CM_DownloadCache_Click(object sender, RoutedEventArgs e)
{
if(Status != LauncherStatus.Ready)
@@ -2121,6 +2446,43 @@ await Task.Run(() =>
}
}
});
+ if(GameCacheMetadata == null || GameCacheMetadataNumeric == null)
+ {
+ Status = LauncherStatus.Ready;
+ return;
+ }
+ Dispatcher.Invoke(() =>
+ {
+ DownloadCacheBox.Visibility = Visibility.Visible;
+ string mirror;
+ string time;
+ string last_updated;
+ if(Mirror == HI3Mirror.GoogleDrive)
+ {
+ mirror = "Google Drive";
+ time = GameCacheMetadataNumeric.modifiedDate.ToString();
+ }
+ else
+ {
+ mirror = "MediaFire";
+ time = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddSeconds((double)OnlineVersionInfo.game_info.mirror.mediafire.last_updated).ToString();
+ }
+ try
+ {
+ if(DateTime.Compare(FetchmiHoYoResourceVersionDateModified(), DateTime.Parse(time)) >= 0)
+ last_updated = $"{DateTime.Parse(time).ToLocalTime()} ({textStrings["outdated"].ToLower()})";
+ else
+ last_updated = DateTime.Parse(time).ToLocalTime().ToString();
+ }
+ catch
+ {
+ last_updated = textStrings["msgbox_genericerror_title"];
+ Log("WARNING: Failed to load last cache update time", true, 2);
+ }
+ DownloadCacheBoxMessageTextBlock.Text = string.Format(textStrings["downloadcachebox_msg"], mirror, last_updated, OnlineVersionInfo.game_info.mirror.maintainer.ToString());
+ Log("success!", false);
+ Status = LauncherStatus.Ready;
+ });
}
catch(Exception ex)
{
@@ -2130,35 +2492,6 @@ await Task.Run(() =>
Status = LauncherStatus.Ready;
return;
}
- if(GameCacheMetadata == null || GameCacheMetadataNumeric == null)
- {
- Status = LauncherStatus.Ready;
- return;
- }
- Dispatcher.Invoke(() =>
- {
- DownloadCacheBox.Visibility = Visibility.Visible;
- string mirror;
- string time;
- string last_updated;
- if(Mirror == HI3Mirror.GoogleDrive)
- {
- mirror = "Google Drive";
- time = GameCacheMetadataNumeric.modifiedDate.ToString();
- }
- else
- {
- mirror = "MediaFire";
- time = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddSeconds((double)OnlineVersionInfo.game_info.mirror.mediafire.last_updated).ToString();
- }
- if(DateTime.Compare(FetchmiHoYoResourceVersionDateModified(), DateTime.Parse(time)) >= 0)
- last_updated = $"{DateTime.Parse(time).ToLocalTime()} ({textStrings["outdated"].ToLower()})";
- else
- last_updated = DateTime.Parse(time).ToLocalTime().ToString();
- DownloadCacheBoxMessageTextBlock.Text = string.Format(textStrings["downloadcachebox_msg"], mirror, last_updated, OnlineVersionInfo.game_info.mirror.maintainer.ToString());
- Log("success!", false);
- Status = LauncherStatus.Ready;
- });
}
private async Task CM_Repair_Click(object sender, RoutedEventArgs e)
@@ -2355,7 +2688,7 @@ private async Task CM_Uninstall_Click(object sender, RoutedEventArgs e)
return;
Status = LauncherStatus.Uninstalling;
- Log($"Deleting game files...");
+ Log("Deleting game files...");
await Task.Run(() =>
{
try
@@ -2851,6 +3184,8 @@ private void CM_Language_Click(object sender, RoutedEventArgs e)
var item = sender as MenuItem;
if(item.IsChecked)
return;
+ if(Status == LauncherStatus.Downloading || Status == LauncherStatus.Verifying || Status == LauncherStatus.Unpacking || Status == LauncherStatus.Uninstalling || Status == LauncherStatus.Working || Status == LauncherStatus.Preloading || Status == LauncherStatus.PreloadVerifying)
+ return;
string lang = item.Header.ToString();
string msg;
@@ -2867,24 +3202,8 @@ private void CM_Language_Click(object sender, RoutedEventArgs e)
if(new DialogWindow(textStrings["msgbox_abort_title"], $"{textStrings["msgbox_abort_1_msg"]}\n{textStrings["msgbox_abort_2_msg"]}", true).ShowDialog() == false)
return;
Status = LauncherStatus.CleaningUp;
- try
- {
- if(File.Exists(GameArchivePath))
- File.Delete(GameArchivePath);
- }
- catch
- {
- Log($"WARNING: Failed to delete {GameArchivePath}", true, 2);
- }
- try
- {
- if(File.Exists(CacheArchivePath))
- File.Delete(CacheArchivePath);
- }
- catch
- {
- Log($"WARNING: Failed to delete {CacheArchivePath}", true, 2);
- }
+ DeleteFile(GameArchivePath);
+ DeleteFile(CacheArchivePath);
}
try
@@ -2934,7 +3253,7 @@ private void CM_Language_Click(object sender, RoutedEventArgs e)
}
LauncherRegKey.SetValue("Language", LauncherLanguage);
}
- Log($"Set language to {lang}");
+ Log($"Set language to {LauncherLanguage}");
BpUtility.StartProcess(LauncherExeName, string.Join(" ", CommandLineArgs), RootPath, true);
Application.Current.Shutdown();
}
@@ -2988,7 +3307,9 @@ private void ServerDropdown_Changed(object sender, SelectionChangedEventArgs e)
DownloadPaused = false;
DeleteFile(GameArchivePath);
if(!PatchDownload)
+ {
DeleteGameFiles();
+ }
}
switch(index)
{
@@ -3032,7 +3353,9 @@ private void MirrorDropdown_Changed(object sender, SelectionChangedEventArgs e)
DownloadPaused = false;
DeleteFile(GameArchivePath);
if(!PatchDownload)
+ {
DeleteGameFiles();
+ }
}
else if(Mirror == HI3Mirror.miHoYo && index != 0)
{
@@ -3287,7 +3610,7 @@ await Task.Run(async () =>
}
else
{
- Log($"Finished verifying files, no files need repair");
+ Log("Finished verifying files, no files need repair");
Dispatcher.Invoke(() =>
{
ProgressText.Text = string.Empty;
@@ -3344,7 +3667,7 @@ async Task Generate()
var files = new DirectoryInfo(GameInstallPath).GetFiles("*", SearchOption.AllDirectories).Where(x => !x.Attributes.HasFlag(FileAttributes.Hidden) && x.Name != "config.ini" && x.Name != "UniFairy.sys" && x.Name != "Version.txt" && x.Name != "blockVerifiedVersion.txt" && !x.Name.Contains("Blocks_") && !x.Name.Contains("AUDIO_DLC") && !x.Name.Contains("AUDIO_EVENT") && !x.DirectoryName.Contains("Video") && !x.DirectoryName.Contains("webCaches") && x.Extension != ".log").ToList();
dynamic json = new ExpandoObject();
json.repair_info = new ExpandoObject();
- json.repair_info.game_version = miHoYoVersionInfo.cur_version;
+ json.repair_info.game_version = miHoYoVersionInfo.game.latest.version;
json.repair_info.mirrors = string.Empty;
json.repair_info.zip_urls = Array.Empty();
json.repair_info.files = new ExpandoObject();
@@ -3582,59 +3905,40 @@ private void MainWindow_Closing(object sender, CancelEventArgs e)
{
if(Status == LauncherStatus.Downloading || Status == LauncherStatus.DownloadPaused)
{
- try
+ if(download == null)
{
- if(download == null)
+ if(new DialogWindow(textStrings["msgbox_abort_title"], $"{textStrings["msgbox_abort_1_msg"]}\n{textStrings["msgbox_abort_2_msg"]}", true).ShowDialog() == true)
{
- if(new DialogWindow(textStrings["msgbox_abort_title"], $"{textStrings["msgbox_abort_1_msg"]}\n{textStrings["msgbox_abort_2_msg"]}", true).ShowDialog() == true)
- {
- Status = LauncherStatus.CleaningUp;
- try
- {
- if(File.Exists(GameArchivePath))
- File.Delete(GameArchivePath);
- }
- catch
- {
- Log($"WARNING: Failed to delete {GameArchivePath}", true, 2);
- }
- try
- {
- if(File.Exists(CacheArchivePath))
- File.Delete(CacheArchivePath);
- }
- catch
- {
- Log($"WARNING: Failed to delete {CacheArchivePath}", true, 2);
- }
- }
- else
- {
- e.Cancel = true;
- }
+ Status = LauncherStatus.CleaningUp;
+ DeleteFile(GameArchivePath);
+ DeleteFile(CacheArchivePath);
}
else
{
- if(new DialogWindow(textStrings["msgbox_abort_title"], $"{textStrings["msgbox_abort_1_msg"]}\n{textStrings["msgbox_abort_3_msg"]}", true).ShowDialog() == true)
- {
- download.Pause();
- WriteVersionInfo();
- }
- else
- {
- e.Cancel = true;
- }
+ e.Cancel = true;
}
}
- catch(Exception ex)
+ else
{
- Status = LauncherStatus.Error;
- Log($"ERROR: Failed to install the game:\n{ex}", true, 1);
- new DialogWindow(textStrings["msgbox_installerror_title"], textStrings["msgbox_installerror_msg"]).ShowDialog();
- return;
+ if(new DialogWindow(textStrings["msgbox_abort_title"], $"{textStrings["msgbox_abort_1_msg"]}\n{textStrings["msgbox_abort_3_msg"]}", true).ShowDialog() == true)
+ {
+ download.Pause();
+ WriteVersionInfo();
+ }
+ else
+ {
+ e.Cancel = true;
+ }
}
}
- else if(Status == LauncherStatus.Verifying || Status == LauncherStatus.Unpacking || Status == LauncherStatus.CleaningUp || Status == LauncherStatus.Uninstalling || Status == LauncherStatus.Working)
+ else if(Status == LauncherStatus.Preloading)
+ {
+ if(download != null)
+ {
+ download.Pause();
+ }
+ }
+ else if(Status == LauncherStatus.Verifying || Status == LauncherStatus.Unpacking || Status == LauncherStatus.CleaningUp || Status == LauncherStatus.Uninstalling || Status == LauncherStatus.Working || Status == LauncherStatus.PreloadVerifying)
{
e.Cancel = true;
}
@@ -3652,42 +3956,42 @@ private void OnGameExit()
private string CheckForExistingGameDirectory(string path)
{
- var pathVariants = new List(new string[]
+ if(string.IsNullOrEmpty(path))
+ return string.Empty;
+
+ var path_variants = new List(new string[]
{
- path.Replace(@"Honkai Impact 3rd\Honkai Impact 3rd", @"Honkai Impact 3rd\Games"),
- path.Replace(@"Honkai Impact 3\Honkai Impact 3", @"Honkai Impact 3\Games"),
- path.Replace(@"Honkai Impact 3rd\Games\Honkai Impact 3rd", @"Honkai Impact 3rd\Games"),
- path.Replace(@"Honkai Impact 3\Games\Honkai Impact 3", @"Honkai Impact 3\Games"),
- path.Replace(@"\BH3_Data\Honkai Impact 3rd", string.Empty),
- path.Replace(@"\BH3_Data\Honkai Impact 3", string.Empty),
+
+ path.Replace(@"\BH3_Data", string.Empty),
Path.Combine(path, "Games"),
Path.Combine(path, "Honkai Impact 3rd"),
Path.Combine(path, "Honkai Impact 3"),
Path.Combine(path, "Honkai Impact 3rd", "Games"),
- Path.Combine(path, "Honkai Impact 3", "Games")
+ Path.Combine(path, "Honkai Impact 3", "Games"),
+ Path.Combine(path, "Honkai Impact 3rd glb", "Games"),
+ Path.Combine(path, "Honkai Impact 3rd sea", "Games")
});
if(path.Length >= 16)
{
- pathVariants.Add(path.Substring(0, path.Length - 16));
+ path_variants.Add(path.Substring(0, path.Length - 16));
}
if(path.Length >= 18)
{
- pathVariants.Add(path.Substring(0, path.Length - 18));
+ path_variants.Add(path.Substring(0, path.Length - 18));
}
- if(File.Exists(Path.Combine(path, GameExeName)))
- {
- return path;
- }
- else
+ foreach(var variant in path_variants)
{
- foreach(var variant in pathVariants)
+ if(string.IsNullOrEmpty(variant))
+ continue;
+
+ Log($"checking {Path.Combine(variant, GameExeName)}");
+ if(File.Exists(Path.Combine(variant, GameExeName)))
{
- if(File.Exists(Path.Combine(variant, GameExeName)))
- return variant;
+ return variant;
}
- return string.Empty;
}
+ return string.Empty;
}
private int CheckForExistingGameClientServer()
@@ -3855,7 +4159,7 @@ public void Log(string msg, bool newline = true, int type = 0)
catch
{
DisableLogging = true;
- Log($"WARNING: Unable to write to log file", true, 2);
+ Log("WARNING: Unable to write to log file", true, 2);
}
}
}
@@ -3881,7 +4185,6 @@ public void DeleteFile(string path, bool ignorereadonly = false)
public struct Version
{
- internal static Version zero = new Version(0, 0, 0, 0);
private int major, minor, date, hotfix;
internal Version(int _major, int _minor, int _date, int _hotfix)
@@ -3910,23 +4213,26 @@ internal Version(string _version)
hotfix = int.Parse(_versionStrings[3]);
}
- internal bool IsDifferentThan(Version _otherVersion)
+ internal bool IsNewerThan(Version _otherVersion)
{
- if(major != _otherVersion.major)
- {
- return true;
- }
- else if(minor != _otherVersion.minor)
- {
- return true;
- }
- else if(date != _otherVersion.date)
- {
- return true;
- }
- else if(hotfix != _otherVersion.hotfix)
+ if(major >= _otherVersion.major && minor >= _otherVersion.minor && date >= _otherVersion.date)
{
- return true;
+ if(major > _otherVersion.major)
+ {
+ return true;
+ }
+ else if(minor > _otherVersion.minor)
+ {
+ return true;
+ }
+ else if(date > _otherVersion.date)
+ {
+ return true;
+ }
+ else if(hotfix > _otherVersion.hotfix)
+ {
+ return true;
+ }
}
return false;
}
@@ -3939,60 +4245,49 @@ public override string ToString()
public struct GameVersion
{
- internal static GameVersion zero = new GameVersion(0, 0, 0, string.Empty);
private int major, minor, patch;
- private string build;
- internal GameVersion(int _major, int _minor, int _patch, string _build)
+ internal GameVersion(int _major, int _minor, int _patch)
{
major = _major;
minor = _minor;
patch = _patch;
- build = _build;
}
internal GameVersion(string _version)
{
string[] _versionStrings = _version.Split('.', '_');
- if(_versionStrings.Length != 4)
+ if(_versionStrings.Length < 3 || _versionStrings.Length > 4)
{
major = 0;
minor = 0;
patch = 0;
- build = "xxxxxxxxxx";
return;
}
major = int.Parse(_versionStrings[0]);
minor = int.Parse(_versionStrings[1]);
patch = int.Parse(_versionStrings[2]);
- build = _versionStrings[3];
}
- internal bool IsDifferentThan(GameVersion _otherVersion)
+ internal bool IsNewerThan(GameVersion _otherVersion)
{
- if(major != _otherVersion.major)
- {
- return true;
- }
- else if(minor != _otherVersion.minor)
- {
- return true;
- }
- else if(patch != _otherVersion.patch)
+ int old_ver = int.Parse(string.Format("{0}{1}{2}", _otherVersion.major, _otherVersion.minor, _otherVersion.patch));
+ int new_ver = int.Parse(string.Format("{0}{1}{2}", major, minor, patch));
+
+ if(new_ver > old_ver)
{
return true;
}
- else if(build != _otherVersion.build)
+ else
{
- return true;
+ return false;
}
- return false;
}
public override string ToString()
{
- return $"{major}.{minor}.{patch}_{build}";
+ return $"{major}.{minor}.{patch}";
}
}
}
diff --git a/TextStrings_de.cs b/TextStrings_de.cs
index 89cf6fa..5301a9c 100644
--- a/TextStrings_de.cs
+++ b/TextStrings_de.cs
@@ -14,6 +14,7 @@ private void TextStrings_German()
textStrings["button_download"] = "Herunterladen";
textStrings["button_downloading"] = "Lädt herunter";
textStrings["button_running"] = "Läuft";
+ textStrings["button_launch"] = "Start";
textStrings["button_options"] = "Optionen";
textStrings["button_resume"] = "Fortsetzen";
textStrings["button_confirm"] = "Bestätigen";
@@ -21,6 +22,16 @@ private void TextStrings_German()
textStrings["button_github"] = "GitHub-Repository öffnen";
textStrings["button_generate"] = "Generiere";
textStrings["label_log"] = "Log anzeigen";
+ textStrings["label_preload"] = "Vorzeitiges Herunterladen des Spiels";
+ textStrings["label_get_now"] = "Jetzt herunterladen";
+ textStrings["label_verifying"] = "Überprüfung läuft";
+ textStrings["label_paused"] = "Angehalten";
+ textStrings["label_done"] = "Abgeschlossen";
+ textStrings["label_retry"] = "Erneut versuchen";
+ textStrings["label_downloaded_1"] = "Heruntergeladen {0}%";
+ textStrings["label_downloaded_2"] = "Daten Herunterladen:";
+ textStrings["label_eta"] = "Geschätzte verbleibende Zeit:";
+ textStrings["label_speed"] = "Download-Geschwindigkeit:";
textStrings["contextmenu_repair"] = "Repariere Spieldateien";
textStrings["contextmenu_move"] = "Verschiebe Spieldateien";
textStrings["contextmenu_uninstall"] = "Spiel deinstallieren";
@@ -175,6 +186,7 @@ private void TextStrings_German()
textStrings["msgbox_language_msg"] = "Die Sprache wird zu {0} geändert und der Launcher neu gestartet.\nFortfahren?";
textStrings["msgbox_conn_bp_error_msg"] = "Es konnte keine Verbindung zum Bp Network hergestellt werden:";
textStrings["msgbox_conn_mihoyo_error_msg"] = "Es konnte keine Verbindung zum miHoYo Server hergestellt werden:";
+ textStrings["msgbox_preload_msg"] = "Während des vorzeitigen Herunterladens kann das Spiel gestartet werden. Willst du jetzt herunterladen?";
}
}
}
\ No newline at end of file
diff --git a/TextStrings_en.cs b/TextStrings_en.cs
index e0b5a94..4993fd7 100644
--- a/TextStrings_en.cs
+++ b/TextStrings_en.cs
@@ -27,7 +27,7 @@ private void TextStrings_English()
textStrings.Add("button_running", "Running");
textStrings.Add("button_update", "Update");
textStrings.Add("button_pause", "Pause");
- textStrings.Add("button_launch", "Start");
+ textStrings.Add("button_launch", "Launch");
textStrings.Add("button_options", "Options");
textStrings.Add("button_resume", "Resume");
textStrings.Add("button_ok", "OK");
@@ -38,6 +38,16 @@ private void TextStrings_English()
textStrings.Add("label_server", "Server");
textStrings.Add("label_mirror", "Mirror");
textStrings.Add("label_log", "Show log");
+ textStrings.Add("label_preload", "Game Pre-Installation");
+ textStrings.Add("label_get_now", "Get Now");
+ textStrings.Add("label_verifying", "Verifying");
+ textStrings.Add("label_paused", "Paused");
+ textStrings.Add("label_done", "Done");
+ textStrings.Add("label_retry", "Retry");
+ textStrings.Add("label_downloaded_1", "Downloaded {0}%");
+ textStrings.Add("label_downloaded_2", "Download resources:");
+ textStrings.Add("label_eta", "Time remaining:");
+ textStrings.Add("label_speed", "Download speed:");
textStrings.Add("contextmenu_downloadcache", "Download cache");
textStrings.Add("contextmenu_repair", "Repair game files");
textStrings.Add("contextmenu_move", "Move game files");
@@ -196,6 +206,7 @@ private void TextStrings_English()
textStrings.Add("msgbox_language_msg", "Language is going to be changed to {0} and launcher will be restarted.\nContinue?");
textStrings.Add("msgbox_conn_bp_error_msg", "Cannot connect to Bp Network:");
textStrings.Add("msgbox_conn_mihoyo_error_msg", "Cannot connect to miHoYo servers:");
+ textStrings.Add("msgbox_preload_msg", "You can still enter the game when pre-installing. Are you sure you want to download?");
}
}
}
\ No newline at end of file
diff --git a/TextStrings_es.cs b/TextStrings_es.cs
index 60f3b15..03e0177 100644
--- a/TextStrings_es.cs
+++ b/TextStrings_es.cs
@@ -27,6 +27,16 @@ private void TextStrings_Spanish()
textStrings["label_server"] = "Servidor";
textStrings["label_mirror"] = "Espejo";
textStrings["label_log"] = "Mostrar log";
+ textStrings["label_preload"] = "Predescarga del juego";
+ textStrings["label_get_now"] = "Obtener ahora";
+ textStrings["label_verifying"] = "Examinando";
+ textStrings["label_paused"] = "En pausa";
+ textStrings["label_done"] = "Completada";
+ textStrings["label_retry"] = "Reintentar";
+ textStrings["label_downloaded_1"] = "Descargado {0}%";
+ textStrings["label_downloaded_2"] = "Descarga de recursos:";
+ textStrings["label_eta"] = "Tiempo restante:";
+ textStrings["label_speed"] = "Velocidad de descarga:";
textStrings["contextmenu_downloadcache"] = "Descargar cache";
textStrings["contextmenu_repair"] = "Reparar los archivos del juego";
textStrings["contextmenu_move"] = "Mover los archivos del juego";
@@ -181,6 +191,7 @@ private void TextStrings_Spanish()
textStrings["msgbox_language_msg"] = "El idioma se cambiará a {0} y el launcher se reiniciará.\n¿Continuar?";
textStrings["msgbox_conn_bp_error_msg"] = "No se puede conectar a Bp Network:";
textStrings["msgbox_conn_mihoyo_error_msg"] = "No se puede conectar a los servidores miHoYo:";
+ textStrings["msgbox_preload_msg"] = "Podrás seguir jugando durante la predescarga. ¿Deseas continuar?";
}
}
}
\ No newline at end of file
diff --git a/TextStrings_pt.cs b/TextStrings_pt.cs
index 589bcf6..726afee 100644
--- a/TextStrings_pt.cs
+++ b/TextStrings_pt.cs
@@ -28,6 +28,16 @@ private void TextStrings_Portuguese()
textStrings["label_server"] = "Servidor";
textStrings["label_mirror"] = "Espelho";
textStrings["label_log"] = "Mostrar log";
+ textStrings["label_preload"] = "Pré-download do jogo";
+ textStrings["label_get_now"] = "Obter já";
+ textStrings["label_verifying"] = "Examinando";
+ textStrings["label_paused"] = "Em pausa";
+ textStrings["label_done"] = "Concluído";
+ textStrings["label_retry"] = "Tentar de novo";
+ textStrings["label_downloaded_1"] = "Baixado {0}%";
+ textStrings["label_downloaded_2"] = "Baixando recursos:";
+ textStrings["label_eta"] = "Tempo estimado:";
+ textStrings["label_speed"] = "Velocidade de baixada:";
textStrings["contextmenu_downloadcache"] = "Baixar cache";
textStrings["contextmenu_repair"] = "Reparar arquivos do jogo";
textStrings["contextmenu_move"] = "Mover arquivos do jogo";
@@ -86,7 +96,7 @@ private void TextStrings_Portuguese()
textStrings["resolutioninputbox_label_width"] = "Largura";
textStrings["resolutioninputbox_label_height"] = "Altura";
textStrings["resolutioninputbox_label_fullscreen"] = "Tela cheia";
- textStrings["changelogbox_1_msg"] = "Better Honkai Impact 3rd Launcher acaba de se tornar ainda melhor. Aqui está o que aconteceu:";
+ textStrings["changelogbox_1_msg"] = "Better Honkai Impact 3rd Launcher acaba de ficar ainda melhor. Aqui está o que mudou:";
textStrings["changelogbox_2_msg"] = "Carregando o changelog...";
textStrings["changelogbox_3_msg"] = "Não foi possível carregar o changelog.";
textStrings["aboutbox_msg"] = "Bem, é muito mais avançado, não é? :^)\nEste projeto foi feito com a esperança de que muitos capitães tivessem uma melhor experiência com o jogo.\nEle não é afiliado à miHoYo e é totalmente código-aberto.\nQualquer comentário será muito bem vindo.\nAgradecimentos especiais à esses contribuidores do GitHub:\nSinsOfSeven - Contribuição de resolução personalizada\nProxy-E23 - Tradução da idioma espanhola\nSpookyKisuy - Tradução da idioma portuguêsa\nbulawin1, Vrontis - Tradução da idioma alemã\nKorewaLidesu - Tradução da idioma vietnamita\nSm1leAway - Tradução da idioma sérvia\nVoRTeXStarz - Tradução da idioma tailandesa";
@@ -184,6 +194,7 @@ private void TextStrings_Portuguese()
textStrings["msgbox_language_msg"] = "O idioma será alterado para {0} e o launcher será reiniciado.\nContinuar?";
textStrings["msgbox_conn_bp_error_msg"] = "Não foi possível conectar-se ao Bp Network:";
textStrings["msgbox_conn_mihoyo_error_msg"] = "Não foi possível conectar-se aos servidores miHoYo:";
+ textStrings["msgbox_preload_msg"] = "É possível entrar no jogo durante o pré-download dos recursos. Deseja mesmo fazer o pré-download?";
}
}
}
\ No newline at end of file
diff --git a/TextStrings_ru.cs b/TextStrings_ru.cs
index 8fa9c85..00bae3e 100644
--- a/TextStrings_ru.cs
+++ b/TextStrings_ru.cs
@@ -31,6 +31,16 @@ private void TextStrings_Russian()
textStrings["label_server"] = "Сервер";
textStrings["label_mirror"] = "Зеркало";
textStrings["label_log"] = "Показать лог";
+ textStrings["label_preload"] = "Предзагрузить игру";
+ textStrings["label_get_now"] = "Получить";
+ textStrings["label_verifying"] = "Проверка";
+ textStrings["label_paused"] = "Приостановлено";
+ textStrings["label_done"] = "Завершено";
+ textStrings["label_retry"] = "Попробовать снова";
+ textStrings["label_downloaded_1"] = "Загружено {0}%";
+ textStrings["label_downloaded_2"] = "Загрузка ресурсов:";
+ textStrings["label_eta"] = "Осталось времени:";
+ textStrings["label_speed"] = "Скорость загрузки:";
textStrings["contextmenu_downloadcache"] = "Загрузить кеш";
textStrings["contextmenu_repair"] = "Починить игровые файлы";
textStrings["contextmenu_move"] = "Переместить игровые файлы";
@@ -189,6 +199,7 @@ private void TextStrings_Russian()
textStrings["msgbox_language_msg"] = "Язык изменится на {0} и лаунчер будет перезапущен.\nПродолжить?";
textStrings["msgbox_conn_bp_error_msg"] = "Не удаётся подключиться к Bp Network:";
textStrings["msgbox_conn_mihoyo_error_msg"] = "Не удаётся подключиться к серверам miHoYo:";
+ textStrings["msgbox_preload_msg"] = "Вы можете зайти в игру во время предзагрузки. Вы уверены, что хотите загрузить игру?";
}
}
}
\ No newline at end of file
diff --git a/TextStrings_sr.cs b/TextStrings_sr.cs
index 3949341..bbfaa9c 100644
--- a/TextStrings_sr.cs
+++ b/TextStrings_sr.cs
@@ -26,6 +26,7 @@ private void TextStrings_Serbian()
textStrings["button_github"] = "Idi na GitHub repozitorijum";
textStrings["button_generate"] = "Generiši";
textStrings["label_log"] = "Pokaži zapis";
+ textStrings["label_preload"] = "Učitaj unapred igru";
textStrings["contextmenu_downloadcache"] = "Preuzmi keš";
textStrings["contextmenu_repair"] = "Popravi fajlove igre";
textStrings["contextmenu_move"] = "Premesti fajlove igre";
diff --git a/TextStrings_th.cs b/TextStrings_th.cs
index 3cae9d3..01cd33f 100644
--- a/TextStrings_th.cs
+++ b/TextStrings_th.cs
@@ -29,6 +29,16 @@ private void TextStrings_Thai()
textStrings["label_server"] = "เซิร์ฟเวอร์";
textStrings["label_mirror"] = "ไฟล์สำรอง";
textStrings["label_log"] = "แสดงการบันทึก";
+ textStrings["label_preload"] = "ดาวน์โหลดเกมล่วงหน้า";
+ textStrings["label_get_now"] = "ดาวน์โหลดทันที";
+ textStrings["label_verifying"] = "กำลังตรวจสอบ";
+ textStrings["label_paused"] = "หยุดชั่วคราว";
+ textStrings["label_done"] = "เสร็จสิ้น";
+ textStrings["label_retry"] = "ลองใหม่";
+ textStrings["label_downloaded_1"] = "ดาวน์โหลด {0}%";
+ textStrings["label_downloaded_2"] = "ดาวน์โหลดทรัพยากร:";
+ textStrings["label_eta"] = "เวลาที่เหลือโดยประมาณ:";
+ textStrings["label_speed"] = "ความเร็วดาวน์โหลด:";
textStrings["contextmenu_downloadcache"] = "ดาวน์โหลดไฟล์แคช";
textStrings["contextmenu_repair"] = "ซ่อมไฟล์เกม";
textStrings["contextmenu_move"] = "ย้ายไฟล์เกม";
@@ -187,6 +197,7 @@ private void TextStrings_Thai()
textStrings["msgbox_language_msg"] = "ภาษาที่ใช้กำลังจะเปลี่ยนเป็น{0}และตัวโปรแกรมกำลังจะถูกรีสตาร์ท\nดำเนินการต่อ?";
textStrings["msgbox_conn_bp_error_msg"] = "ไม่สามารถเชื่อมต่อกับเครือข่าย Bp:";
textStrings["msgbox_conn_mihoyo_error_msg"] = "ไม่สามารถเชื่อมต่อกับเซิร์ฟเวอร์ miHoYo:";
+ textStrings["msgbox_preload_msg"] = "ระหว่างทำการดาวน์โหลดล่วงหน้า สามารถเข้าเกมไปพร้อมกันได้ ต้องการดาวน์โหลดหรือไม่?";
}
}
}
\ No newline at end of file
diff --git a/TextStrings_vi.cs b/TextStrings_vi.cs
index f6c9bf4..fbcfd3c 100644
--- a/TextStrings_vi.cs
+++ b/TextStrings_vi.cs
@@ -27,6 +27,16 @@ private void TextStrings_Vietnamese()
textStrings["button_generate"] = "Tạo";
textStrings["label_server"] = "Máy chủ";
textStrings["label_log"] = "Hiện log";
+ textStrings["label_preload"] = "Tải trước trò chơi";
+ textStrings["label_get_now"] = "Tải ngay";
+ textStrings["label_verifying"] = "Đang xác nhận";
+ textStrings["label_paused"] = "Đã tạm dừng";
+ textStrings["label_done"] = "Đã hoàn thành";
+ textStrings["label_retry"] = "Thử Lại";
+ textStrings["label_downloaded_1"] = "Đã tải {0}%";
+ textStrings["label_downloaded_2"] = "Tải tài nguyên:";
+ textStrings["label_eta"] = "Thời gian dự kiến:";
+ textStrings["label_speed"] = "Tốc độ tải:";
textStrings["contextmenu_downloadcache"] = "Tải cache";
textStrings["contextmenu_repair"] = "Sửa chữa tệp trò chơi";
textStrings["contextmenu_move"] = "Di chuyển tệp trò chơi";
@@ -182,6 +192,7 @@ private void TextStrings_Vietnamese()
textStrings["msgbox_language_msg"] = "Ngôn ngữ sẽ chuyển sang {0} và trình khởi chạy sẽ được khởi động lại.\nTiếp tục?";
textStrings["msgbox_conn_bp_error_msg"] = "Không thể kết nối với Bp Network:";
textStrings["msgbox_conn_mihoyo_error_msg"] = "Không thể kết nối với máy chủ miHoYo:";
+ textStrings["msgbox_preload_msg"] = "Khi tải trước vẫn có thể vào trò chơi. Xác nhận tải xuống?";
}
}
}
\ No newline at end of file
diff --git a/Utility.cs b/Utility.cs
index b667bf4..cc67e0f 100644
--- a/Utility.cs
+++ b/Utility.cs
@@ -10,6 +10,9 @@
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Media;
+using System.Windows.Shapes;
using ProgressItem = System.Collections.Generic.KeyValuePair;
namespace BetterHI3Launcher
@@ -369,6 +372,110 @@ protected override WebRequest GetWebRequest(Uri address)
}
}
+ // https://stackoverflow.com/a/23047288/7570821
+ public class Arc : Shape
+ {
+ public double StartAngle
+ {
+ get { return (double)GetValue(StartAngleProperty); }
+ set { SetValue(StartAngleProperty, value); }
+ }
+
+ // Using a DependencyProperty as the backing store for StartAngle. This enables animation, styling, binding, etc...
+ public static readonly DependencyProperty StartAngleProperty =
+ DependencyProperty.Register("StartAngle", typeof(double), typeof(Arc), new UIPropertyMetadata(0.0, new PropertyChangedCallback(UpdateArc)));
+
+ public double EndAngle
+ {
+ get { return (double)GetValue(EndAngleProperty); }
+ set { SetValue(EndAngleProperty, value); }
+ }
+
+ // Using a DependencyProperty as the backing store for EndAngle. This enables animation, styling, binding, etc...
+ public static readonly DependencyProperty EndAngleProperty =
+ DependencyProperty.Register("EndAngle", typeof(double), typeof(Arc), new UIPropertyMetadata(90.0, new PropertyChangedCallback(UpdateArc)));
+
+ //This controls whether or not the progress bar goes clockwise or counterclockwise
+ public SweepDirection Direction
+ {
+ get { return (SweepDirection)GetValue(DirectionProperty); }
+ set { SetValue(DirectionProperty, value); }
+ }
+
+ public static readonly DependencyProperty DirectionProperty =
+ DependencyProperty.Register("Direction", typeof(SweepDirection), typeof(Arc),
+ new UIPropertyMetadata(SweepDirection.Clockwise));
+
+ //rotate the start/endpoint of the arc a certain number of degree in the direction
+ //ie. if you wanted it to be at 12:00 that would be 270 Clockwise or 90 counterclockwise
+ public double OriginRotationDegrees
+ {
+ get { return (double)GetValue(OriginRotationDegreesProperty); }
+ set { SetValue(OriginRotationDegreesProperty, value); }
+ }
+
+ public static readonly DependencyProperty OriginRotationDegreesProperty =
+ DependencyProperty.Register("OriginRotationDegrees", typeof(double), typeof(Arc),
+ new UIPropertyMetadata(270.0, new PropertyChangedCallback(UpdateArc)));
+
+ protected static void UpdateArc(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ Arc arc = d as Arc;
+ arc.InvalidateVisual();
+ }
+
+ protected override Geometry DefiningGeometry
+ {
+ get { return GetArcGeometry(); }
+ }
+
+ protected override void OnRender(System.Windows.Media.DrawingContext drawingContext)
+ {
+ drawingContext.DrawGeometry(null, new Pen(Stroke, StrokeThickness), GetArcGeometry());
+ }
+
+ private Geometry GetArcGeometry()
+ {
+ Point startPoint = PointAtAngle(Math.Min(StartAngle, EndAngle), Direction);
+ Point endPoint = PointAtAngle(Math.Max(StartAngle, EndAngle), Direction);
+
+ Size arcSize = new Size(Math.Max(0, (RenderSize.Width - StrokeThickness) / 2),
+ Math.Max(0, (RenderSize.Height - StrokeThickness) / 2));
+ bool isLargeArc = Math.Abs(EndAngle - StartAngle) > 180;
+
+ StreamGeometry geom = new StreamGeometry();
+ using(StreamGeometryContext context = geom.Open())
+ {
+ context.BeginFigure(startPoint, false, false);
+ context.ArcTo(endPoint, arcSize, 0, isLargeArc, Direction, true, false);
+ }
+ geom.Transform = new TranslateTransform(StrokeThickness / 2, StrokeThickness / 2);
+ return geom;
+ }
+
+ private Point PointAtAngle(double angle, SweepDirection sweep)
+ {
+ double translatedAngle = angle + OriginRotationDegrees;
+ double radAngle = translatedAngle * (Math.PI / 180);
+ double xr = (RenderSize.Width - StrokeThickness) / 2;
+ double yr = (RenderSize.Height - StrokeThickness) / 2;
+
+ double x = xr + xr * Math.Cos(radAngle);
+ double y = yr * Math.Sin(radAngle);
+
+ if(sweep == SweepDirection.Counterclockwise)
+ {
+ y = yr - y;
+ }
+ else
+ {
+ y = yr + y;
+ }
+
+ return new Point(x, y);
+ }
+ }
+
// https://github.com/scottrippey/Progression/blob/master/Progression/Extras/ETACalculator.cs
public interface IETACalculator
{
@@ -517,7 +624,22 @@ public bool ETAIsAvailable
}
}
- #if DEBUG
+ public class ProgressToAngleConverter : System.Windows.Data.IMultiValueConverter
+ {
+ public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+ {
+ double progress = (double)values[0];
+ System.Windows.Controls.ProgressBar bar = values[1] as System.Windows.Controls.ProgressBar;
+ return 359.999 * (progress / (bar.Maximum - bar.Minimum));
+ }
+
+ public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+#if DEBUG
// https://stackoverflow.com/a/48864902/7570821
static class WinConsole
{