Compare commits

..
Author SHA1 Message Date
RMBGAME cc8dbeb3f0 🚧 Misc 2024-11-28 16:45:52 +08:00
Aigio Liu e96fcd5f1b 🐛 Settings Reset 2024-11-28 15:54:53 +08:00
Aigio Liu d5c87efea9 🚑 macos build 2024-11-28 15:13:54 +08:00
Aigio Liu 8044cee366 🐛 macos build 2024-11-28 14:44:36 +08:00
Aigio Liu 2bbbf14ea6 🐛 BasicPlatformSwitcher(DeleteRegistryKey) 2024-11-27 23:35:54 +08:00
Aigio Liu 2737f9ae01 🐛 BasicPlatformSwitcher(SetRegistryKey) 2024-11-27 23:05:24 +08:00
Aigio Liu 078d4623f9 ⬆️ .NET 9.0 2024-11-27 20:02:12 +08:00
RMBGAME 593c170ee5 🐛 fix ClickAd OpenBrowserCommand 2024-11-27 17:38:17 +08:00
Aigio Liu a0279bf8f1 🔥 Remove ProxyMode.DNSIntercept with REMOVE_DNS_INTERCEPT" 2024-11-27 17:27:29 +08:00
Aigio Liu dcda15a33c 🐛 Fix 未使用 IsAuth 参数 2024-11-27 17:05:22 +08:00
Aigio Liu 39ef48dbec ⬆️ .NET 9.0 2024-11-27 16:40:05 +08:00
k1mlka c3d9c4525f 🐛 修复证书过期后加速失效的问题 (#3553)
* 🐛 修复证书过期后加速失效的问题

* 🐛 修复证书过期跨天情况下的加速error情景

* 🎨 CertService 使用证书默认到期时间
2024-11-26 13:58:25 +08:00
RMBGAME 039eb60c4b 🚧 NewUrl 2024-11-25 18:01:45 +08:00
RMBGAME 0a6aae5c97 🚧 改进需要登录的提示 2024-11-25 17:38:20 +08:00
RMBGAME 08ffcfc50d Merge pull request #3544 from BeyondDimension/feature/info_icon
✨ 网络测试页面延迟后增加info图标
2024-11-25 17:25:32 +08:00
RMBGAME c93db63297 🚧 Misc 2024-11-25 17:24:26 +08:00
RMBGAME 36339154dc 🚧 文本调整 2024-11-25 17:06:06 +08:00
Aigio Liu 1648d65c47 🎨 BD_AppCenter.Start 2024-11-25 12:29:05 +08:00
Aigio Liu 815e426ecc 🎨 BD.AppCenter 2024-11-25 10:18:50 +08:00
Aigio Liu f37454fe9b ⬆️ Avalonia v11.1.5 2024-11-24 20:24:13 +08:00
Aigio Liu b79debc968 🎨 Tracepoint 2024-11-24 20:21:28 +08:00
Aigio Liu c2bb1ea80a ➕ AppCenter 2024-11-24 20:20:33 +08:00
Aigio Liu 1e9d647de8 🐛 ipc 2024-11-23 18:31:55 +08:00
Aigio Liu 774e75848a 🐛 pkg ref 2024-11-22 15:57:58 +08:00
Aigio Liu ebbb2d90ba ➕ TracepointHelper 2024-11-22 15:21:47 +08:00
k1mlka 77b43918f1 💄 去除StringNotEmptyToVisibilityConverter 2024-11-22 10:20:36 +08:00
RMBGAME e505e91931 🐛 fix #3519 #3530
增加战网账号切换支持国服国际服切换(建议重新保存一次账号)
修复国服国际服战网邮箱相同时无法同时保存账号问题
修复了一个账号切换的炸弹,可能会让GOG切换变好(未测试)
2024-11-22 00:57:29 +08:00
k1mlka c9118b5abe ✨ ASF 对低版本操作系统提供下载 2024-11-21 11:39:16 +08:00
BuknSS 9843c01904 Revert "✨ AdvertisementDTO 增加带 IsAuth 的版本"
This reverts commit e5abea1474.
2024-11-20 14:34:22 +08:00
k1mlka 4986266268 ✨ ASF 默认允许打开额外菜单下的文档链接 2024-11-20 14:33:19 +08:00
ff m e629bffde8 ↑ 升级 SDK 子模块 2024-11-20 14:28:44 +08:00
ff m 6cf351bac5 🐛 修复判断打开广告地址带登录信息错误判断 2024-11-20 14:25:37 +08:00
RMBGAME e32c0bbf97 🚧 Misc 2024-11-20 14:09:11 +08:00
BuknSS e5abea1474 ✨ AdvertisementDTO 增加带 IsAuth 的版本 2024-11-19 19:34:18 +08:00
k1mlka 3ae002db91 ✨ 网络测试页面延迟后增加info图标 2024-11-19 15:54:13 +08:00
Aigio L 063ca17403 🐛 AvaloniaToastServiceImpl.Show 2024-11-18 15:37:28 +08:00
ff m 4573a9b494 🐛 优化安装脚本 2024-10-21 17:32:54 +08:00
Aigio Liu 8f29d7b8ea 🔖 3.0.0-rc.12 2024-10-11 16:40:52 +08:00
RMBGAME 7156d90967 🐛 Windows 关机事件遗漏 2024-10-11 16:33:56 +08:00
RMBGAME ec726e8c48 💄 成就 受保护 文本调整 2024-10-10 15:55:08 +08:00
RMBGAME 488403a86b 🐛 修复 新版 Steam 客户端 编辑游戏功能保存不生效问题 2024-10-10 15:50:59 +08:00
Aigio Liu 59474d68cd Revert "🔥 Remove ProxyMode.DNSIntercept with REMOVE_DNS_INTERCEPT"
This reverts commit 7f7fde20bd.
2024-10-09 21:14:50 +08:00
RMBGAME 5ab308bb9b 🐛 修复 ASF 下载通知问题 2024-10-09 19:31:42 +08:00
RMBGAME bf3d6ad778 🐛 修复挂卡和令牌确认交易中可能出现系统代理更改时网络请求出错的问题 2024-10-09 18:33:02 +08:00
RMBGAME 59356f210e Merge pull request #3499 from BeyondDimension/feature/network_test_domain_validation
✨ 网络测试页面域名检测输入检查
2024-10-09 18:31:46 +08:00
k1mlka 42df02f718 🐛 网络测试页面清理 2024-10-09 15:22:33 +08:00
k1mlka 8728126421 Merge branch 'develop' into feature/network_test_domain_validation 2024-10-09 15:03:30 +08:00
RMBGAME e0c36a9545 Merge pull request #3495 from BeyondDimension/refactor_NetworkCheck
💄 网络测试子页面重构
2024-10-09 14:19:00 +08:00
k1mlka 9a2bd1a6cc 🐛 移除多余代码 2024-10-08 11:40:51 +08:00
k1mlka 499edb402c 💄 网络测试子页面ViewModel重构
💄 网络测试子页面NAT检查部分逻辑重构

💄 网络测试子页面ViewModel重构

💄 网络测试子页面NAT检查部分逻辑重构

💄代码Clean,没有引用到的名称空间与枚举类型

💄 网络测试子页面NAT检查部分逻辑重构

💄 网络测试子页面ViewModel重构

💄 网络测试子页面NAT检查部分逻辑重构

💄代码Clean,没有引用到的名称空间与枚举类型
2024-10-08 11:33:37 +08:00
k1mlka 14216ab98f ✨ 网络测试页面域名检测输入检查 2024-09-29 17:26:58 +08:00
john.jiang 95c10dacd4 🎨 ASF 插件 Release 版进程残留问题修复,启动优化,打开文件夹提示优化 2024-09-27 15:30:51 +08:00
134 changed files with 906 additions and 3054 deletions
+3
View File
@@ -37,3 +37,6 @@
[submodule "ref/Facepunch.Steamworks"]
path = ref/Facepunch.Steamworks
url = https://github.com/BeyondDimension/Facepunch.Steamworks.git
[submodule "ref/appcenter-sdk-dotnet"]
path = ref/appcenter-sdk-dotnet
url = https://github.com/BeyondDimension/appcenter-sdk-dotnet.git
+49 -33
View File
@@ -214,10 +214,14 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Facepunch.Steamworks.Posix"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Steam++", "src\BD.WTTS.Client.AppHost.Bridge\Steam++.csproj", "{26D8AA24-2ACE-4167-BC2B-117B9BB76AA4}"
EndProject
Project("{C7167F0D-BC9F-4E6E-AFE1-012C56B48DB5}") = "BD.WTTS.Client.AppHost.Bridge.Package", "src\BD.WTTS.Client.AppHost.Bridge.Package\BD.WTTS.Client.AppHost.Bridge.Package.wapproj", "{27795C79-2994-4514-8656-BA34FCEE8901}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ArchiSteamFarm", "ref\ArchiSteamFarm\ArchiSteamFarm\ArchiSteamFarm.csproj", "{8C34FCD5-8C7F-4B10-A970-7DEA8A61F56B}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AppCenter", "AppCenter", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BD.AppCenter.Any", "ref\appcenter-sdk-dotnet\SDK\AppCenter\BD.AppCenter.Any\BD.AppCenter.Any.csproj", "{BD7E0AF0-FABE-3C94-DE36-CF365BF7323D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BD.AppCenter.Analytics.Any", "ref\appcenter-sdk-dotnet\SDK\AppCenterAnalytics\BD.AppCenter.Analytics.Any\BD.AppCenter.Analytics.Any.csproj", "{9611DBE7-EDF0-9EB0-EE93-B158981BE48F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -1232,36 +1236,6 @@ Global
{26D8AA24-2ACE-4167-BC2B-117B9BB76AA4}.Release|x64.Build.0 = Release|Any CPU
{26D8AA24-2ACE-4167-BC2B-117B9BB76AA4}.Release|x86.ActiveCfg = Release|Any CPU
{26D8AA24-2ACE-4167-BC2B-117B9BB76AA4}.Release|x86.Build.0 = Release|Any CPU
{27795C79-2994-4514-8656-BA34FCEE8901}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{27795C79-2994-4514-8656-BA34FCEE8901}.Debug|Any CPU.Build.0 = Debug|Any CPU
{27795C79-2994-4514-8656-BA34FCEE8901}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{27795C79-2994-4514-8656-BA34FCEE8901}.Debug|ARM.ActiveCfg = Debug|ARM
{27795C79-2994-4514-8656-BA34FCEE8901}.Debug|ARM.Build.0 = Debug|ARM
{27795C79-2994-4514-8656-BA34FCEE8901}.Debug|ARM.Deploy.0 = Debug|ARM
{27795C79-2994-4514-8656-BA34FCEE8901}.Debug|ARM64.ActiveCfg = Debug|ARM64
{27795C79-2994-4514-8656-BA34FCEE8901}.Debug|ARM64.Build.0 = Debug|ARM64
{27795C79-2994-4514-8656-BA34FCEE8901}.Debug|ARM64.Deploy.0 = Debug|ARM64
{27795C79-2994-4514-8656-BA34FCEE8901}.Debug|x64.ActiveCfg = Debug|x64
{27795C79-2994-4514-8656-BA34FCEE8901}.Debug|x64.Build.0 = Debug|x64
{27795C79-2994-4514-8656-BA34FCEE8901}.Debug|x64.Deploy.0 = Debug|x64
{27795C79-2994-4514-8656-BA34FCEE8901}.Debug|x86.ActiveCfg = Debug|x86
{27795C79-2994-4514-8656-BA34FCEE8901}.Debug|x86.Build.0 = Debug|x86
{27795C79-2994-4514-8656-BA34FCEE8901}.Debug|x86.Deploy.0 = Debug|x86
{27795C79-2994-4514-8656-BA34FCEE8901}.Release|Any CPU.ActiveCfg = Release|Any CPU
{27795C79-2994-4514-8656-BA34FCEE8901}.Release|Any CPU.Build.0 = Release|Any CPU
{27795C79-2994-4514-8656-BA34FCEE8901}.Release|Any CPU.Deploy.0 = Release|Any CPU
{27795C79-2994-4514-8656-BA34FCEE8901}.Release|ARM.ActiveCfg = Release|ARM
{27795C79-2994-4514-8656-BA34FCEE8901}.Release|ARM.Build.0 = Release|ARM
{27795C79-2994-4514-8656-BA34FCEE8901}.Release|ARM.Deploy.0 = Release|ARM
{27795C79-2994-4514-8656-BA34FCEE8901}.Release|ARM64.ActiveCfg = Release|ARM64
{27795C79-2994-4514-8656-BA34FCEE8901}.Release|ARM64.Build.0 = Release|ARM64
{27795C79-2994-4514-8656-BA34FCEE8901}.Release|ARM64.Deploy.0 = Release|ARM64
{27795C79-2994-4514-8656-BA34FCEE8901}.Release|x64.ActiveCfg = Release|x64
{27795C79-2994-4514-8656-BA34FCEE8901}.Release|x64.Build.0 = Release|x64
{27795C79-2994-4514-8656-BA34FCEE8901}.Release|x64.Deploy.0 = Release|x64
{27795C79-2994-4514-8656-BA34FCEE8901}.Release|x86.ActiveCfg = Release|x86
{27795C79-2994-4514-8656-BA34FCEE8901}.Release|x86.Build.0 = Release|x86
{27795C79-2994-4514-8656-BA34FCEE8901}.Release|x86.Deploy.0 = Release|x86
{8C34FCD5-8C7F-4B10-A970-7DEA8A61F56B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8C34FCD5-8C7F-4B10-A970-7DEA8A61F56B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8C34FCD5-8C7F-4B10-A970-7DEA8A61F56B}.Debug|ARM.ActiveCfg = Debug|Any CPU
@@ -1282,6 +1256,46 @@ Global
{8C34FCD5-8C7F-4B10-A970-7DEA8A61F56B}.Release|x64.Build.0 = Release|Any CPU
{8C34FCD5-8C7F-4B10-A970-7DEA8A61F56B}.Release|x86.ActiveCfg = Release|Any CPU
{8C34FCD5-8C7F-4B10-A970-7DEA8A61F56B}.Release|x86.Build.0 = Release|Any CPU
{BD7E0AF0-FABE-3C94-DE36-CF365BF7323D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BD7E0AF0-FABE-3C94-DE36-CF365BF7323D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BD7E0AF0-FABE-3C94-DE36-CF365BF7323D}.Debug|ARM.ActiveCfg = Debug|Any CPU
{BD7E0AF0-FABE-3C94-DE36-CF365BF7323D}.Debug|ARM.Build.0 = Debug|Any CPU
{BD7E0AF0-FABE-3C94-DE36-CF365BF7323D}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{BD7E0AF0-FABE-3C94-DE36-CF365BF7323D}.Debug|ARM64.Build.0 = Debug|Any CPU
{BD7E0AF0-FABE-3C94-DE36-CF365BF7323D}.Debug|x64.ActiveCfg = Debug|Any CPU
{BD7E0AF0-FABE-3C94-DE36-CF365BF7323D}.Debug|x64.Build.0 = Debug|Any CPU
{BD7E0AF0-FABE-3C94-DE36-CF365BF7323D}.Debug|x86.ActiveCfg = Debug|Any CPU
{BD7E0AF0-FABE-3C94-DE36-CF365BF7323D}.Debug|x86.Build.0 = Debug|Any CPU
{BD7E0AF0-FABE-3C94-DE36-CF365BF7323D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BD7E0AF0-FABE-3C94-DE36-CF365BF7323D}.Release|Any CPU.Build.0 = Release|Any CPU
{BD7E0AF0-FABE-3C94-DE36-CF365BF7323D}.Release|ARM.ActiveCfg = Release|Any CPU
{BD7E0AF0-FABE-3C94-DE36-CF365BF7323D}.Release|ARM.Build.0 = Release|Any CPU
{BD7E0AF0-FABE-3C94-DE36-CF365BF7323D}.Release|ARM64.ActiveCfg = Release|Any CPU
{BD7E0AF0-FABE-3C94-DE36-CF365BF7323D}.Release|ARM64.Build.0 = Release|Any CPU
{BD7E0AF0-FABE-3C94-DE36-CF365BF7323D}.Release|x64.ActiveCfg = Release|Any CPU
{BD7E0AF0-FABE-3C94-DE36-CF365BF7323D}.Release|x64.Build.0 = Release|Any CPU
{BD7E0AF0-FABE-3C94-DE36-CF365BF7323D}.Release|x86.ActiveCfg = Release|Any CPU
{BD7E0AF0-FABE-3C94-DE36-CF365BF7323D}.Release|x86.Build.0 = Release|Any CPU
{9611DBE7-EDF0-9EB0-EE93-B158981BE48F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9611DBE7-EDF0-9EB0-EE93-B158981BE48F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9611DBE7-EDF0-9EB0-EE93-B158981BE48F}.Debug|ARM.ActiveCfg = Debug|Any CPU
{9611DBE7-EDF0-9EB0-EE93-B158981BE48F}.Debug|ARM.Build.0 = Debug|Any CPU
{9611DBE7-EDF0-9EB0-EE93-B158981BE48F}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{9611DBE7-EDF0-9EB0-EE93-B158981BE48F}.Debug|ARM64.Build.0 = Debug|Any CPU
{9611DBE7-EDF0-9EB0-EE93-B158981BE48F}.Debug|x64.ActiveCfg = Debug|Any CPU
{9611DBE7-EDF0-9EB0-EE93-B158981BE48F}.Debug|x64.Build.0 = Debug|Any CPU
{9611DBE7-EDF0-9EB0-EE93-B158981BE48F}.Debug|x86.ActiveCfg = Debug|Any CPU
{9611DBE7-EDF0-9EB0-EE93-B158981BE48F}.Debug|x86.Build.0 = Debug|Any CPU
{9611DBE7-EDF0-9EB0-EE93-B158981BE48F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9611DBE7-EDF0-9EB0-EE93-B158981BE48F}.Release|Any CPU.Build.0 = Release|Any CPU
{9611DBE7-EDF0-9EB0-EE93-B158981BE48F}.Release|ARM.ActiveCfg = Release|Any CPU
{9611DBE7-EDF0-9EB0-EE93-B158981BE48F}.Release|ARM.Build.0 = Release|Any CPU
{9611DBE7-EDF0-9EB0-EE93-B158981BE48F}.Release|ARM64.ActiveCfg = Release|Any CPU
{9611DBE7-EDF0-9EB0-EE93-B158981BE48F}.Release|ARM64.Build.0 = Release|Any CPU
{9611DBE7-EDF0-9EB0-EE93-B158981BE48F}.Release|x64.ActiveCfg = Release|Any CPU
{9611DBE7-EDF0-9EB0-EE93-B158981BE48F}.Release|x64.Build.0 = Release|Any CPU
{9611DBE7-EDF0-9EB0-EE93-B158981BE48F}.Release|x86.ActiveCfg = Release|Any CPU
{9611DBE7-EDF0-9EB0-EE93-B158981BE48F}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -1347,8 +1361,10 @@ Global
{638745C0-B699-4009-9764-05434C511403} = {99D97BD4-3F51-48BC-8BD2-647F6D268BB0}
{35676E23-8E54-4785-A75B-98EB0650596B} = {99D97BD4-3F51-48BC-8BD2-647F6D268BB0}
{26D8AA24-2ACE-4167-BC2B-117B9BB76AA4} = {5541B406-4A9A-4AC8-AA77-CE14E133DB80}
{27795C79-2994-4514-8656-BA34FCEE8901} = {5541B406-4A9A-4AC8-AA77-CE14E133DB80}
{8C34FCD5-8C7F-4B10-A970-7DEA8A61F56B} = {99D97BD4-3F51-48BC-8BD2-647F6D268BB0}
{02EA681E-C7D8-13C7-8484-4AC65E1B71E8} = {90E88965-DB90-4B49-94F5-6D2965491988}
{BD7E0AF0-FABE-3C94-DE36-CF365BF7323D} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
{9611DBE7-EDF0-9EB0-EE93-B158981BE48F} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {567F588F-E95C-4286-8B30-DB3B2200221C}
+63 -9
View File
@@ -3,6 +3,12 @@
default_base_path="$HOME/WattToolkit"
base_path="$default_base_path"
# 检查是否以root身份执行
if [ "$EUID" -eq 0 ]; then
echo "此脚本不能以root身份执行。"
exit 1
fi
# 循环直到用户输入有效路径或直接回车
while true; do
# 使用 zenity 提示用户选择安装路径或使用默认路径
@@ -41,7 +47,45 @@ base_url="https://api.steampp.net"
architecture=1
app_name="Watt Toolkit"
PROCESS_NAMES=("$exec_name" "$app_name")
export LC_ALL=en_US.UTF-8
Check_LC_Code() {
# 检查当前 LANG 环境变量
current_lang="${LC_ALL:-$LANG}"
echo "当前语言环境: $current_lang"
# 检查是否为 C 或 C.UTF-8
if [ "$current_lang" = "C" ] || [ "$current_lang" = "C.UTF-8" ]; then
echo "当前语言环境是 C 或 C.UTF-8,需要修改。"
# 列出系统支持的语言环境
supported_locales=$(locale -a)
if [ -z "$supported_locales" ]; then
echo "未能获取到支持的语言环境列表。请检查系统配置。"
return 1
fi
# 遍历支持的语言环境列表,找到第一个不是 C 或 C.UTF-8 的项
first_non_c_locale=""
for locale in $supported_locales; do
if [ "$locale" != "C" ] && [ "$locale" != "C.UTF-8" ]; then
first_non_c_locale="$locale"
break
fi
done
# 检查是否找到了非 C/C.UTF-8 的语言环境
if [ -n "$first_non_c_locale" ]; then
echo "修改语言环境为支持列表中的第一个非 C/C.UTF-8 项:$first_non_c_locale"
export LC_ALL="$first_non_c_locale"
echo "语言环境已修改为 $first_non_c_locale。"
else
echo "未能找到非 C/C.UTF-8 的语言环境。请检查系统配置。"
return 1
fi
else
echo "当前语言环境不是 C 或 C.UTF-8,无需修改。"
fi
}
Check_LC_Code
Install_certutil() {
# 判断发行版类型
if command -v certutil &>/dev/null; then
@@ -360,34 +404,44 @@ Kill_Process
Decompression
# xdg-icon-resource install "$base_path/Icons/Watt-Toolkit.png" --size 128 Watt-Toolkit
InitDesktop() {
# 检查XDG_DESKTOP_DIR环境变量,如果未设置则使用默认值
XDG_DESKTOP_DIR="${XDG_DESKTOP_DIR:-$HOME/Desktop}"
while true; do
# 使用 zenity 提示用户选择安装路径或使用默认路径
choice=$(zenity --list --radiolist --title="请选择要添加到的位置" --column="选择" --column="路径" TRUE "$HOME/.local/share/applications/" FALSE "$HOME/Desktop")
choice=$(zenity --list --radiolist --title="请选择要添加到的位置" \
--column="选择" --column="路径" \
TRUE "$XDG_DESKTOP_DIR" \
FALSE "$HOME/.local/share/applications/")
# 检查用户输入
if [ "$choice" == "$HOME/.local/share/applications/" ]; then
target_dir="$HOME/.local/share/applications/"
break
elif [ "$choice" == "$HOME/Desktop" ]; then
target_dir="$HOME/Desktop/"
elif [ "$choice" == "$XDG_DESKTOP_DIR" ]; then
target_dir="$XDG_DESKTOP_DIR"
break
else
echo "无效选项,请输入 1 或 2。"
# 无效选项时给出提示,并继续循环
zenity --info --text="无效选项,请重新选择。"
fi
done
#添加桌面文件
# 添加桌面文件
rm -rf "$target_dir/Watt Toolkit.desktop" 2>/dev/null
echo "#!/usr/bin/env xdg-open
cat <<EOT > "$target_dir/Watt Toolkit.desktop"
[Desktop Entry]
Name=Watt Toolkit
Exec=$base_path/$exec_name.sh
Icon=$base_path/Icons/Watt-Toolkit.png
Terminal=false
Type=Application
StartupNotify=false" >"$target_dir/Watt Toolkit.desktop"
StartupNotify=false
EOT
chmod +x "$target_dir/Watt Toolkit.desktop"
}
InitDesktop
# update-desktop-database ~/.local/share/applications
#运行程序
-43
View File
@@ -1,43 +0,0 @@
# Steam++ v3.X Program File Structure for Windows
- dotnet 共享运行时,删除后将使用已安装的运行时,此目参考 ```C:\Program Files\dotnet```,可自行升级行库小版本号,二进制兼容
- host
- fxr
- x.y.z
- hostfxr.dll
- shared
- Microsoft.AspNetCore.App
- x.y.z
- Microsoft.NETCore.App
- x.y.z
- native
- win-x64
- 7z.dll
- av_libglesv2.dll
- e_sqlite3.dll
- libHarfBuzzSharp.dll
- libSkiaSharp.dll
- WebView2Loader.dll
- WinDivert.dll
- WinDivert64.sys
- assemblies 主模块程序集
- modules 可选模块
- ~~Update 自更新模块,删除该文件夹后禁用更新~~
- Steam++.Update.exe 更新程序,CDN 分发更包,下载与解压在主程序中,此进程仅退出主程执行覆盖操作
- Accelerator 网络加速
- Steam++.Accelerator.exe 控制台子服务进,使用匿名管道与主进程通信,无参数或指定某参数(待定)启动时可读取配置文件启动加速,可全独立运行,ASP.NET Core Web API 项目,支持 Docker
- Steam++.Plugins.Accelerator.dll 插件程集
- AccountSwitch 账号切换
- Steam++.Plugins.AccountSwitch.dll
- ~~ArchiSteamFarm~~
- Steam++.ArchiSteamFarm.exe
- Steam++.Plugins.ArchiSteamFarm.dll
- GameList 库存游戏
- Steam++.Plugins.GameList.dll
- LocalAuth 本地令牌
- Steam++.Plugins.LocalAuth.dll
- GameTools 游戏工具
- Steam++.Plugins.GameTools.dll
- Steam++.exe (主启动程序).NET Framework 二进制主程序
- Steam++.exe.config 使用该配置文件以允许在 .NET Framework 3.5 ~ 4.8.1 中任意版本中兼容运行(从 Windows 7 ~ 11 中所有系统自带运行时)
- ~~Steam++.Uninstall.exe 卸载程序(WinForms?AOT?)~~
+1 -1
View File
@@ -21,7 +21,7 @@ public static partial class AssemblyInfo
/// <summary>
/// RC 版本号,范围 0~9,只增不减
/// </summary>
const string ver_for_rc = "11";
const string ver_for_rc = "12";
public const string FileVersion = $"{Version2}.{ver_for_rc}1{ver_for_preview}.0";
Binary file not shown.

Before

Width:  |  Height:  |  Size: 190 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 218 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 231 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 279 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 444 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 666 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 666 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 484 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 787 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

@@ -1,83 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Package
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
xmlns:desktop2="http://schemas.microsoft.com/appx/manifest/desktop/windows10/2"
IgnorableNamespaces="uap rescap desktop desktop2">
<Identity
Name="4651ED44255E.47979655102CE"
Publisher="CN=A90E406B-B2D3-4A23-B061-0FA1D65C4F66"
Version="3.0.207.0" />
<Properties>
<DisplayName>Watt Toolkit</DisplayName>
<PublisherDisplayName>软妹币玩家</PublisherDisplayName>
<Logo>Images\StoreLogo.png</Logo>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" />
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" />
</Dependencies>
<Resources>
<Resource Language="x-generate"/>
</Resources>
<Applications>
<Application Id="App"
Executable="$targetnametoken$.exe"
EntryPoint="$targetentrypoint$">
<uap:VisualElements
DisplayName="Watt Toolkit"
Description="「Watt Toolkit」是一个开源跨平台的多功能游戏工具箱,此工具的大部分功能都是需要您下载安装 Steam 才能使用。"
BackgroundColor="transparent"
Square150x150Logo="Images\Square150x150Logo.png"
Square44x44Logo="Images\Square44x44Logo.png">
<uap:DefaultTile Wide310x150Logo="Images\Wide310x150Logo.png" Square71x71Logo="Images\SmallTile.png" Square310x310Logo="Images\LargeTile.png" ShortName="Steam++">
<uap:ShowNameOnTiles>
<uap:ShowOn Tile="square150x150Logo"/>
<uap:ShowOn Tile="wide310x150Logo"/>
<uap:ShowOn Tile="square310x310Logo"/>
</uap:ShowNameOnTiles>
</uap:DefaultTile >
<uap:SplashScreen Image="Images\SplashScreen.png" />
<uap:InitialRotationPreference>
<uap:Rotation Preference="landscape"/>
</uap:InitialRotationPreference>
<uap:LockScreen BadgeLogo="Images\BadgeLogo.png" Notification="badgeAndTileText"/>
</uap:VisualElements>
<Extensions>
<desktop:Extension Category="windows.fullTrustProcess" Executable="Steam++\Steam++.exe" />
<desktop:Extension Category="windows.startupTask" Executable="Steam++\Steam++.exe" EntryPoint="Windows.FullTrustApplication">
<desktop:StartupTask TaskId="BootAutoStartTask" Enabled="true" DisplayName="Steam++ System Boot Run" />
</desktop:Extension>
<uap:Extension Category="windows.protocol">
<uap:Protocol Name="spp">
<uap:Logo>Images\Square44x44Logo.png</uap:Logo>
<uap:DisplayName>Steam++ URI Scheme</uap:DisplayName>
</uap:Protocol>
</uap:Extension>
</Extensions>
</Application>
</Applications>
<Extensions>
<desktop2:Extension Category="windows.firewallRules">
<desktop2:FirewallRules Executable="Steam++\modules\Accelerator\Steam++.Accelerator.exe">
<desktop2:Rule Direction="in" IPProtocol="TCP" Profile="all"/>
<desktop2:Rule Direction="in" IPProtocol="UDP" Profile="all"/>
</desktop2:FirewallRules>
</desktop2:Extension>
</Extensions>
<Capabilities>
<Capability Name="internetClient" />
<rescap:Capability Name="runFullTrust" />
<rescap:Capability Name="allowElevation" />
</Capabilities>
</Package>
+1 -1
View File
@@ -10,6 +10,6 @@
<legacyCorruptedStateExceptionsPolicy enabled="true"/>
</runtime>
<appSettings>
<add key="d" value="8.0.0"/>
<add key="d" value="9.0.0"/>
</appSettings>
</configuration>
+3 -3
View File
@@ -16,7 +16,7 @@ static unsafe partial class Program
{
static Program()
{
dotnet_version_major = "8";
dotnet_version_major = "9";
dotnet_version_minor = "0";
dotnet_version_build = "0";
dotnet_version = $"{dotnet_version_major}.{dotnet_version_minor}.{dotnet_version_build}";
@@ -426,8 +426,8 @@ static unsafe partial class Program
if (!File.Exists(config_path) || !File.Exists(dotnetlib_path))
{
#if DEBUG
config_path = string.Join(Path.DirectorySeparatorChar.ToString(), new[] { ProjectUtils.ProjPath, "src", "BD.WTTS.Client.Avalonia.App", "bin", "Debug", $"net{dotnet_version_major}.{dotnet_version_minor}-windows10.0.19041.0", $"{dotnet_dll_name}.runtimeconfig.json" });
dotnetlib_path = string.Join(Path.DirectorySeparatorChar.ToString(), new[] { ProjectUtils.ProjPath, "src", "BD.WTTS.Client.Avalonia.App", "bin", "Debug", $"net{dotnet_version_major}.{dotnet_version_minor}-windows10.0.19041.0", $"{dotnet_dll_name}.dll" });
config_path = string.Join(Path.DirectorySeparatorChar.ToString(), new[] { ProjectUtils.ProjPath, "src", "BD.WTTS.Client.Avalonia.App", "bin", "Debug", $"net{dotnet_version_major}.{dotnet_version_minor}-windows10.0.19041", $"{dotnet_dll_name}.runtimeconfig.json" });
dotnetlib_path = string.Join(Path.DirectorySeparatorChar.ToString(), new[] { ProjectUtils.ProjPath, "src", "BD.WTTS.Client.Avalonia.App", "bin", "Debug", $"net{dotnet_version_major}.{dotnet_version_minor}-windows10.0.19041", $"{dotnet_dll_name}.dll" });
#else
ShowErrMessageBox($"Loading assembly failed \"{dotnetlib_path}\"");
return (int)ExitCode.EntryPointFileNotFound;
@@ -95,31 +95,37 @@
<ProjectReference Include="..\BD.WTTS.Client\BD.WTTS.Client.csproj" />
</ItemGroup>
<ItemGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows' AND Exists('$(NugetPackageRoot)\system.drawing.common\$(Version_System_Drawing_Common)\lib\net8.0\System.Drawing.Common.dll')">
<!-- Windows Only -->
<!-- 修复:存在 Microsoft.WindowsDesktop.App 依赖时不会将 System.Drawing.Common.dll 复制到输出目录-->
<None Include="$(NugetPackageRoot)\system.drawing.common\$(Version_System_Drawing_Common)\lib\net8.0\System.Drawing.Common.dll">
<!--<ItemGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows' AND Exists('$(NugetPackageRoot)\system.drawing.common\$(Version_System_Drawing_Common)\lib\net9.0\System.Drawing.Common.dll')">
--><!-- Windows Only --><!--
--><!-- 修复:存在 Microsoft.WindowsDesktop.App 依赖时不会将 System.Drawing.Common.dll 复制到输出目录--><!--
<None Include="$(NugetPackageRoot)\system.drawing.common\$(Version_System_Drawing_Common)\lib\net9.0\System.Drawing.Common.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<Reference Include="System.Drawing.Common">
<HintPath>$(NugetPackageRoot)\system.drawing.common\$(Version_System_Drawing_Common)\lib\net8.0\System.Drawing.Common.dll</HintPath>
<HintPath>$(NugetPackageRoot)\system.drawing.common\$(Version_System_Drawing_Common)\lib\net9.0\System.Drawing.Common.dll</HintPath>
</Reference>
<None Include="$(NugetPackageRoot)\microsoft.win32.systemevents\9.0.0\runtimes\win\lib\net9.0\Microsoft.Win32.SystemEvents.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<Reference Include="Microsoft.Win32.SystemEvents">
<HintPath>$(NugetPackageRoot)\microsoft.win32.systemevents\9.0.0\runtimes\win\lib\net9.0\Microsoft.Win32.SystemEvents.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows' AND Exists('$(NugetPackageRoot)\splat.drawing\$(Version_Splat_Drawing)\lib\net7.0\Splat.Drawing.dll')">
<!-- Windows Only -->
<!-- 修复:Splat.Drawing 包存在 WPF 的依赖项 -->
--><!-- Windows Only --><!--
--><!-- 修复:Splat.Drawing 包存在 WPF 的依赖项 --><!--
<PackageReference Include="Splat.Drawing">
<ExcludeAssets>all</ExcludeAssets>
</PackageReference>
<Reference Include="Splat.Drawing">
<HintPath>$(NugetPackageRoot)\splat.drawing\$(Version_Splat_Drawing)\lib\net7.0\Splat.Drawing.dll</HintPath>
</Reference>
<!-- 修复:System.Reactive 包存在 System.Windows.Forms 的依赖项 -->
--><!-- 修复:System.Reactive 包存在 System.Windows.Forms 的依赖项 --><!--
<Reference Include="System.Reactive">
<HintPath>$(NugetPackageRoot)\system.reactive\$(Version_System_Reactive)\lib\net6.0\System.Reactive.dll</HintPath>
</Reference>
</ItemGroup>
</ItemGroup>-->
<Import Project="..\TFM_NETX_WITH_DESKTOP.props" />
@@ -8,8 +8,6 @@
<string>3.0.0</string>
<key>CFBundleVersion</key>
<string>3.0.0.0</string>
<key>LSMinimumSystemVersion</key>
<string>10.15</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
@@ -54,8 +54,11 @@ sealed class AvaloniaToastServiceImpl : IToastService
}
}
var notificationType = GetNotificationType(icon);
NotificationManager.Show(text, notificationType: notificationType);
if (NotificationManager != null)
{
var notificationType = GetNotificationType(icon);
NotificationManager.Show(text, notificationType: notificationType);
}
}
/// <inheritdoc cref="Show(string, int?)"/>
+9 -3
View File
@@ -76,7 +76,7 @@ public sealed partial class App : Application
Log.Error(nameof(Steamworks), ex, "Steamworks.SteamClient Init");
}
}
#endif
#endif
}
catch (Exception ex)
{
@@ -111,6 +111,12 @@ public sealed partial class App : Application
{
Task2.InBackground(() => appWindow.SplashScreen?.RunTasks(CancellationToken.None));
}
IPlatformService.Instance.SetSystemSessionEnding(() =>
{
Log.Info("System Shutdown", "Application SafeExit...");
Shutdown();
});
}
else if (ApplicationLifetime is ISingleViewApplicationLifetime singleView)
{
@@ -246,8 +252,8 @@ public sealed partial class App : Application
try
{
Uri uri = new(urlString);
if (uri.Host.EndsWith("steampp.net", StringComparison.OrdinalIgnoreCase) ||
uri.Host.EndsWith("mossimo.net", StringComparison.OrdinalIgnoreCase))
if (uri.Host.EndsWith(Constants.Urls.OfficialWebsiteHost, StringComparison.OrdinalIgnoreCase) &&
uri.Query.EndsWith(Constants.Urls.Komaasharu_IsAuthQuery, StringComparison.OrdinalIgnoreCase))
{
await UserService.Current.OpenAuthUrl(urlString);
return;
@@ -7,7 +7,7 @@
<RootNamespace>BD.WTTS</RootNamespace>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<SelfContained>false</SelfContained>
<DefineConstants>APP_REVERSE_PROXY;NONE_UI;REMOVE_DNS_INTERCEPT;$(DefineConstants)</DefineConstants>
<DefineConstants>APP_REVERSE_PROXY;NONE_UI;$(DefineConstants)</DefineConstants>
<ApplicationManifest>Properties\app.manifest</ApplicationManifest>
</PropertyGroup>
@@ -129,7 +129,7 @@ sealed partial class CertificateManagerImpl : ICertificateManager
bool SharedCreateRootCertificate()
{
RootCertificate ??= LoadRootCertificate();
RootCertificate = LoadRootCertificate();
if (RootCertificate != null)
{
@@ -83,7 +83,7 @@ sealed class CertService
entry.SetAbsoluteExpiration(notAfter);
var subjectName = new X500DistinguishedName($"CN={domain}");
using var serverCert = CertGenerator.CreateEndCertificate(caCert, subjectName, GetDomains(), notBefore, notAfter);
using var serverCert = CertGenerator.CreateEndCertificate(caCert, subjectName, GetDomains());
var serverCertPfx = serverCert.Export(X509ContentType.Pfx);
// 将生成的证书导出后重新创建一个
return new X509Certificate2(serverCertPfx);
@@ -84,7 +84,7 @@ sealed partial class HttpReverseProxyMiddleware
!reverseProxyConfig.Service.OnlyEnableProxyScript)
{
// 部分运营商将奇怪的域名解析到 127.0.0.1 再此排除这些不支持的代理域名
var ip = await reverseProxyConfig.DnsAnalysis.AnalysisDomainIpAsync(context.Request.Host.Value, IDnsAnalysisService.DNS_Dnspods).FirstOrDefaultAsync();
var ip = await reverseProxyConfig.DnsAnalysis.AnalysisDomainIpAsync(context.Request.Host.Value!, IDnsAnalysisService.DNS_Dnspods).FirstOrDefaultAsync();
if (ip == null || IPAddress.IsLoopback(ip))
{
context.Response.StatusCode = StatusCodes.Status500InternalServerError;
@@ -47,9 +47,40 @@ sealed partial class YarpReverseProxyServiceImpl : ReverseProxyServiceImpl, IRev
ICertificateManager.Constants.CheckRootCertificate(
platformService,
CertificateManager);
X509Certificate2? cer = CertificateManager.RootCertificatePackable;
if (cer is not null && DateTime.Now <= cer.NotAfter && cer.NotAfter <= DateTime.Now.AddMonths(1))
{
var interval = cer.NotAfter - DateTime.Now;
_certificateTimer = new System.Timers.Timer(interval)
{
AutoReset = false,
};
_certificateTimer.Elapsed += async (_, _) =>
{
ICertificateManager.Constants.CheckRootCertificate(
platformService,
CertificateManager);
await StopProxyAsync();
await StartProxyImpl();
};
_certificateTimer.Start();
}
}
}
private System.Timers.Timer? _certificateTimer;
private void StopCertificateTimer()
{
_certificateTimer?.Stop();
_certificateTimer?.Dispose();
_certificateTimer = null;
}
protected override Task<StartProxyResult> StartProxyImpl() => Task.FromResult(StartProxyCore());
StartProxyResult StartProxyCore()
@@ -153,6 +184,7 @@ sealed partial class YarpReverseProxyServiceImpl : ReverseProxyServiceImpl, IRev
public async Task StopProxyAsync()
{
StopCertificateTimer();
Scripts = null;
if (app == null) return;
await app.StopAsync();
@@ -196,6 +196,11 @@ public interface ICertificateManager
// 生成证书
certificateManager.GenerateCertificate();
packable = GetRootCertificatePackable();
certificate2 = packable;
if (certificate2 == null)
return StartProxyResultCode.GetX509Certificate2Fail;
// 安装证书
ICertificateManager.Constants.TrustRootCertificate(
GetCerFilePath, platformService, certificate2);
@@ -3,7 +3,7 @@
<PropertyGroup>
<RootNamespace>BD.WTTS</RootNamespace>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DefineConstants>WTTS_PLUGIN;WTTS_PLUGIN_ACCELERATOR;REMOVE_DNS_INTERCEPT;$(DefineConstants)</DefineConstants>
<DefineConstants>WTTS_PLUGIN;WTTS_PLUGIN_ACCELERATOR;$(DefineConstants)</DefineConstants>
<!--<EnableDynamicLoading>true</EnableDynamicLoading>-->
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
</PropertyGroup>
@@ -2,6 +2,7 @@
using Avalonia.Platform.Storage;
using Avalonia.Threading;
using BD.Common.Models;
using BD.WTTS.Helpers;
using BD.WTTS.UI.Views.Controls;
using BD.WTTS.UI.Views.Pages;
using FluentAvalonia.UI.Controls;
@@ -52,7 +53,7 @@ public sealed partial class GameAcceleratorService
[Reactive]
public DateTime? VipEndTime { get; set; }
const string VipEndTimeStringDef = "新用户免费试用 2 天";
const string VipEndTimeStringDef = "新用户免费试用";
[Reactive]
public string? VipEndTimeString { get; set; } = VipEndTimeStringDef;
@@ -353,9 +354,16 @@ public sealed partial class GameAcceleratorService
if (UserService.Current.User?.WattOpenId == null)
{
Toast.Show(ToastIcon.Warning, "需要登录账号才能使用游戏加速功能!");
UserService.Current.ShowWindow();
app.IsAccelerating = false;
return;
}
TracepointHelper.TrackEvent(nameof(GameAccelerator), new Dictionary<string, string> {
{ "GameId", app.Id.ToString() },
{ "GameName", app.Name ?? string.Empty },
});
var xunYouIsInstall = await Ioc.Get<IAcceleratorService>().XY_IsInstall();
if (xunYouIsInstall.HandleUI(out var isInstall))
{
@@ -604,6 +612,7 @@ public sealed partial class GameAcceleratorService
Toast.Show(ToastIcon.Info, "已安装Watt加速器");
return;
}
TracepointHelper.TrackEvent("DownloadInstallAccelerator");
var td = new TaskDialog
{
Title = "下载插件",
@@ -1,4 +1,6 @@
// ReSharper disable once CheckNamespace
using BD.WTTS.Helpers;
namespace BD.WTTS.Services;
partial class ProxyService
@@ -36,10 +38,15 @@ partial class ProxyService
Toast.Show(ToastIcon.Warning, Strings.CommunityFix_AccEmpty);
}
TracepointHelper.TrackEvent("StartProxy", new Dictionary<string, string> {
{ "ProxyType", ProxySettings.ProxyMode.Value.ToString() },
{ "ProxyScriptStatus", ProxySettings.IsEnableScript.Value.ToString() },
});
IReadOnlyCollection<ScriptIPCDTO>? scripts = default;
bool isEnableScript = ProxySettings.IsEnableScript.Value;
bool isOnlyWorkSteamBrowser = ProxySettings.IsOnlyWorkSteamBrowser.Value;
ushort proxyPort = ProxySettings.SystemProxyPortId.Value;
ushort proxyPort = ProxySettings.SystemProxyPortId.Value == 0 ? ProxySettings.SystemProxyPortId.Default : ProxySettings.SystemProxyPortId.Value;
string? proxyIp = ProxySettings.SystemProxyIp.Value;
proxyMode = defaultProxyMode;
bool isProxyGOG = ProxySettings.IsProxyGOG.Value;
@@ -1,5 +1,6 @@
// ReSharper disable once CheckNamespace
using Avalonia.Data;
using BD.WTTS.Helpers;
using Google.Protobuf.WellKnownTypes;
using Org.BouncyCastle.Bcpg.OpenPgp;
using System.Linq;
@@ -28,7 +28,7 @@ public static partial class ProxySettings
yield return EProxyMode.System;
}
#else
return Array.Empty<EProxyMode>();
return Array.Empty<EProxyMode>();
#endif
}
@@ -1,19 +1,17 @@
using AppResources = BD.WTTS.Client.Resources.Strings;
using BD.WTTS.UI.Views.Pages;
using STUN.StunResult;
using STUN.Enums;
using AppResources = BD.WTTS.Client.Resources.Strings;
namespace BD.WTTS.UI.ViewModels;
public sealed partial class AcceleratorPageViewModel
{
public NetworkCheckControlViewModel NetworkCheckControlViewModel { get; } = new();
DateTime _initializeTime;
readonly IHostsFileService? hostsFileService;
readonly IPlatformService platformService = IPlatformService.Instance;
readonly IReverseProxyService reverseProxyService = IReverseProxyService.Constants.Instance;
readonly ICertificateManager certificateManager = ICertificateManager.Constants.Instance;
readonly INetworkTestService networkTestService = INetworkTestService.Instance;
public AcceleratorPageViewModel()
{
@@ -71,82 +69,6 @@ public sealed partial class AcceleratorPageViewModel
GameAcceleratorService.Current.LoadGames();
});
SelectedSTUNAddress = STUNAddress[0];
NATCheckCommand = ReactiveCommand.CreateFromTask(async () =>
{
var natCheckResult = await networkTestService.TestStunClient3489Async(testServerHostName: SelectedSTUNAddress) ?? new ClassicStunResult { NatType = NatType.Unknown };
var (netSucc, _) = await networkTestService.TestOpenUrlAsync("https://www.baidu.com");
var natStatus = natCheckResult.NatType switch
{
NatType.OpenInternet or NatType.FullCone => NatTypeSimple.Open,
NatType.RestrictedCone or NatType.PortRestrictedCone or NatType.SymmetricUdpFirewall => NatTypeSimple.Moderate,
NatType.Symmetric or NatType.UdpBlocked => NatTypeSimple.Strict,
NatType.Unknown or NatType.UnsupportedServer or _ => NatTypeSimple.Unknown,
};
PublicEndPoint = natCheckResult.PublicEndPoint?.Address.ToString() ?? "Unknown";
LocalEndPoint = natCheckResult.LocalEndPoint?.Address.ToString() ?? "Unknown";
return (natStatus, netSucc);
});
NATCheckCommand
.IsExecuting
.ToPropertyEx(this, x => x.IsNATChecking);
DNSCheckCommand = ReactiveCommand.CreateFromTask(async () =>
{
var testDomain = DomainPendingTest == string.Empty ? "store.steampowered.com" : DomainPendingTest;
try
{
long delayMs;
IPAddress[] address;
if (ProxySettings.UseDoh)
{
var configDoh = ProxySettings.CustomDohAddres2.Value ?? ProxySettingsWindowViewModel.DohAddress.FirstOrDefault() ?? string.Empty;
(delayMs, address) = await networkTestService.TestDNSOverHttpsAsync(testDomain, configDoh);
}
else
{
var configDns = ProxySettings.ProxyMasterDns.Value ?? string.Empty;
(delayMs, address) = await networkTestService.TestDNSAsync(testDomain, configDns, 53);
}
if (address.Length == 0)
throw new Exception("Parsing failed. Return empty ip address.");
DNSTestDelay = delayMs + "ms ";
DNSTestResult = string.Empty + address.FirstOrDefault();
}
catch (Exception ex)
{
Log.Error(nameof(AcceleratorPageViewModel), ex.ToString());
DNSTestDelay = string.Empty;
DNSTestResult = "error";
}
});
DNSCheckCommand
.IsExecuting
.ToPropertyEx(this, x => x.IsDNSChecking);
IPv6CheckCommand = ReactiveCommand.CreateFromTask(async () =>
{
var result = await IMicroServiceClient.Instance.Accelerate.GetMyIP(ipV6: true);
if (result.IsSuccess)
{
IsSupportIPv6 = true;
IPv6Address = result.Content ?? string.Empty;
}
else
{
IsSupportIPv6 = false;
IPv6Address = string.Empty;
}
});
IPv6CheckCommand
.IsExecuting
.ToPropertyEx(this, x => x.IsIPv6Checking);
ProxySettingsCommand = ReactiveCommand.Create(() =>
{
var vm = new ProxySettingsWindowViewModel();
@@ -4,66 +4,11 @@ namespace BD.WTTS.UI.ViewModels;
public sealed partial class AcceleratorPageViewModel : TabItemViewModel
{
public enum NatTypeSimple
{
Unknown,
Open,
Moderate,
Strict,
}
public override string Name => Strings.Welcome;
[Reactive]
public string SelectedSTUNAddress { get; set; }
public string[] STUNAddress { get; } =
[
"stun.syncthing.net",
"stun.hot-chilli.net",
"stun.fitauto.ru",
"stun.miwifi.com",
];
[ObservableAsProperty]
public bool IsNATChecking { get; }
[ObservableAsProperty]
public bool IsDNSChecking { get; }
[ObservableAsProperty]
public bool IsIPv6Checking { get; }
[Reactive]
public string DomainPendingTest { get; set; } = string.Empty;
[Reactive]
public ReadOnlyCollection<ProxyDomainGroupViewModel>? EnableProxyDomainGroupVMs { get; set; }
[Reactive]
public string LocalEndPoint { get; set; } = string.Empty;
[Reactive]
public string PublicEndPoint { get; set; } = string.Empty;
[Reactive]
public string DNSTestDelay { get; set; } = string.Empty;
[Reactive]
public string DNSTestResult { get; set; } = string.Empty;
[Reactive]
public string IPv6Address { get; set; } = string.Empty;
[Reactive]
public bool IsSupportIPv6 { get; set; }
public ReactiveCommand<Unit, (NatTypeSimple Nat, bool PingSuccess)> NATCheckCommand { get; }
public ReactiveCommand<Unit, Unit> DNSCheckCommand { get; }
public ReactiveCommand<Unit, Unit> IPv6CheckCommand { get; }
public ICommand StartProxyCommand { get; }
public ICommand RefreshCommand { get; }
@@ -1,3 +1,5 @@
using BD.WTTS.Helpers;
namespace BD.WTTS.UI.ViewModels;
public sealed class GameInfoPageViewModel : WindowViewModel
@@ -38,6 +40,13 @@ public sealed class GameInfoPageViewModel : WindowViewModel
return;
}
TracepointHelper.TrackEvent(nameof(ImmediatelyAccelerate), new Dictionary<string, string> {
{ "GameId", XunYouGame.Id.ToString() },
{ "GameName", XunYouGame.Name ?? string.Empty },
{ "SelectedArea", XunYouGame?.SelectedArea?.Name ?? string.Empty },
{ "SelectedServer", XunYouGame?.SelectedServer?.Name ?? string.Empty },
});
Close?.Invoke(true);
}
}
@@ -0,0 +1,202 @@
using STUN.Enums;
using STUN.StunResult;
using System.Reactive;
namespace BD.WTTS.UI.ViewModels;
public partial class NetworkCheckControlViewModel : ViewModelBase
{
[GeneratedRegex(DomainValidationAttribute.RegPattern)]
private static partial Regex DomainRegExp();
public class DomainValidationAttribute : RegularExpressionAttribute
{
public const string RegPattern = @"^[^/]+\.[^/]{2,}$";
public override string FormatErrorMessage(string name) => "请填入不带分隔符 \"/\" 的域名";
public DomainValidationAttribute() : base(RegPattern)
{
}
}
private readonly INetworkTestService _networkTestService = INetworkTestService.Instance;
public record NATFetchResult(string PublicEndPoint, string LocalEndPoint, string NATLevel, string NATTypeTip, bool PingResult);
public string DefaultTestDomain { get; } = "store.steampowered.com";
[Reactive]
public string SelectedSTUNAddress { get; set; }
public string[] STUNAddress { get; } =
[
"stun.syncthing.net",
"stun.hot-chilli.net",
"stun.fitauto.ru",
"stun.miwifi.com",
];
[ObservableAsProperty]
public string NATLevel { get; } = string.Empty;
[ObservableAsProperty]
public string NATTypeTip { get; } = string.Empty;
[ObservableAsProperty]
public string LocalEndPoint { get; } = string.Empty;
[ObservableAsProperty]
public string PublicEndPoint { get; } = string.Empty;
[ObservableAsProperty]
public bool PingOkVisible { get; }
[ObservableAsProperty]
public bool PingErrorVisible { get; }
[ObservableAsProperty]
public bool IsNATChecking { get; }
[ObservableAsProperty]
public bool IsDNSChecking { get; }
[ObservableAsProperty]
public bool IsIPv6Checking { get; }
[DomainValidation]
[Reactive]
public string DomainPendingTest { get; set; } = string.Empty;
[Reactive]
public string DNSTestDelay { get; set; } = string.Empty;
[Reactive]
public string DNSTestResult { get; set; } = string.Empty;
[Reactive]
public string IPv6Address { get; set; } = string.Empty;
[Reactive]
public bool IsSupportIPv6 { get; set; }
public ReactiveCommand<Unit, NATFetchResult> NATCheckCommand { get; }
public ReactiveCommand<Unit, Unit> DNSCheckCommand { get; }
public ReactiveCommand<Unit, Unit> IPv6CheckCommand { get; }
public NetworkCheckControlViewModel()
{
SelectedSTUNAddress = STUNAddress[0];
NATCheckCommand = ReactiveCommand.CreateFromTask(async () =>
{
var natCheckResult = await _networkTestService.TestStunClient3489Async(testServerHostName: SelectedSTUNAddress) ?? new ClassicStunResult { NatType = NatType.Unknown };
var (netSucc, _) = await _networkTestService.TestOpenUrlAsync("https://www.baidu.com");
var publicEndPoint = natCheckResult.PublicEndPoint?.Address.ToString() ?? "Unknown";
var localEndPoint = natCheckResult.LocalEndPoint?.Address.ToString() ?? "Unknown";
var (natLevel, natTypeTip) = natCheckResult.NatType switch
{
// Open
NatType.OpenInternet or NatType.FullCone => ("开放 NAT", "您可与在其网络上具有任意 NAT 类型的用户玩多人游戏和发起多人游戏。"),
// Moderate
NatType.RestrictedCone or NatType.PortRestrictedCone or NatType.SymmetricUdpFirewall => ("中等 NAT", "您可与一些用户玩多人游戏;但是,并且通常你将不会被选为比赛的主持人。"),
// Strict
NatType.Symmetric or NatType.UdpBlocked => ("严格 NAT", "您只能与具有开放 NAT 类型的用户玩多人游戏。您不能被选为比赛的主持人。"),
// Unknown
NatType.Unknown or NatType.UnsupportedServer or _ => ("不可用 NAT", "如果 NAT 不可用,您将无法使用群聊天或连接到某些 Xbox 游戏的多人游戏。"),
};
return new NATFetchResult(publicEndPoint, localEndPoint, natLevel, natTypeTip, netSucc);
});
NATCheckCommand
.IsExecuting
.ToPropertyEx(this, x => x.IsNATChecking);
NATCheckCommand
.Select(x => x.PublicEndPoint)
.ToPropertyEx(this, x => x.PublicEndPoint);
NATCheckCommand
.Select(x => x.LocalEndPoint)
.ToPropertyEx(this, x => x.LocalEndPoint);
NATCheckCommand
.Select(x => x.NATLevel)
.Merge(Observable.Return("未知"))
.ToPropertyEx(this, x => x.NATLevel);
NATCheckCommand
.Select(x => x.NATTypeTip)
.Merge(Observable.Return("未知类型"))
.ToPropertyEx(this, x => x.NATTypeTip);
var hidePingResultStream = NATCheckCommand
.IsExecuting
.Where(x => x == true)
.Select(x => false);
NATCheckCommand
.Select(x => x.PingResult == true)
.Merge(hidePingResultStream)
.ToPropertyEx(this, x => x.PingOkVisible);
NATCheckCommand
.Select(x => x.PingResult == false)
.Merge(hidePingResultStream)
.ToPropertyEx(this, x => x.PingErrorVisible);
var canDNSCheck = this.WhenAnyValue(x => x.DomainPendingTest)
.Select(domain => domain == string.Empty || DomainRegExp().IsMatch(domain));
DNSCheckCommand = ReactiveCommand.CreateFromTask(async () =>
{
var testDomain = DomainPendingTest == string.Empty ? DefaultTestDomain : DomainPendingTest;
try
{
long delayMs;
IPAddress[] address;
if (ProxySettings.UseDoh)
{
var configDoh = ProxySettings.CustomDohAddres2.Value ?? ProxySettingsWindowViewModel.DohAddress.FirstOrDefault() ?? string.Empty;
(delayMs, address) = await _networkTestService.TestDNSOverHttpsAsync(testDomain, configDoh);
}
else
{
var configDns = ProxySettings.ProxyMasterDns.Value ?? string.Empty;
(delayMs, address) = await _networkTestService.TestDNSAsync(testDomain, configDns, 53);
}
if (address.Length == 0)
throw new Exception("Parsing failed. Return empty ip address.");
DNSTestDelay = delayMs + "ms ";
DNSTestResult = string.Empty + address.FirstOrDefault();
}
catch (Exception ex)
{
Log.Error(nameof(AcceleratorPageViewModel), ex.ToString());
DNSTestDelay = string.Empty;
DNSTestResult = "error";
}
}, canDNSCheck);
DNSCheckCommand
.IsExecuting
.ToPropertyEx(this, x => x.IsDNSChecking);
IPv6CheckCommand = ReactiveCommand.CreateFromTask(async () =>
{
var result = await IMicroServiceClient.Instance.Accelerate.GetMyIP(ipV6: true);
if (result.IsSuccess)
{
IsSupportIPv6 = true;
IPv6Address = result.Content ?? string.Empty;
}
else
{
IsSupportIPv6 = false;
IPv6Address = string.Empty;
}
});
IPv6CheckCommand
.IsExecuting
.ToPropertyEx(this, x => x.IsIPv6Checking);
IPv6CheckCommand.Execute().Subscribe();
}
}
@@ -70,6 +70,7 @@ public partial class ScriptPageViewModel : TabItemViewModel
if (UserService.Current.IsAuthenticated == false)
{
Toast.Show(ToastIcon.Error, "脚本商店需要登录账号才可访问");
UserService.Current.ShowWindow();
return;
}
var model = new ScriptStorePageViewModel();
@@ -3,25 +3,32 @@
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:i="using:Avalonia.Xaml.Interactivity"
xmlns:ia="using:Avalonia.Xaml.Interactions.Core"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ms="https://steampp.net/settings"
xmlns:spp="https://steampp.net/ui"
xmlns:ui="using:FluentAvalonia.UI.Controls"
MinWidth="380"
d:DesignHeight="450"
d:DesignWidth="800"
mc:Ignorable="d">
<StackPanel Spacing="15">
<TextBlock FontSize="21" TextAlignment="Center">
<TextBlock
HorizontalAlignment="Center"
FontSize="21"
TextAlignment="Center">
<Run Text="下载 Watt加速器" />
<LineBreak />
<Run Text="拒绝游戏延迟,提高稳定性" />
</TextBlock>
<ui:SettingsExpander
x:Name="PathSelect"
Description="{Binding Source={x:Static ms:GameAcceleratorSettings.WattAcceleratorDirPath}, Path=Value}"
Header="安装路径"
IsClickEnabled="True">
IsClickEnabled="True"
IsVisible="False">
<ui:SettingsExpander.IconSource>
<ui:FontIconSource FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="&#xE188;" />
</ui:SettingsExpander.IconSource>
@@ -32,13 +39,28 @@
<!--<TextBlock Text="需要下载 Watt 加速器插件才可使用,确定要下载吗?" />-->
<Button
Margin="0,15"
Padding="20,10"
HorizontalAlignment="Center"
Classes="TransparentAccent"
Click="OKButton_Click"
Content="立即下载"
FontSize="14" />
<Panel>
<Button
Margin="0,15"
Padding="20,10"
HorizontalAlignment="Center"
Classes="TransparentAccent"
Click="OKButton_Click"
Content="立即下载"
FontSize="14" />
<Button
Margin="10,0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Click="CustomInstallButton_Click"
Theme="{StaticResource TransparentButton}">
<StackPanel Orientation="Horizontal" Spacing="5">
<TextBlock Text="自定义安装" />
<ui:FontIcon Glyph="&#xE70D;" IsVisible="{Binding !#PathSelect.IsVisible}" />
<ui:FontIcon Glyph="&#xE70E;" IsVisible="{Binding #PathSelect.IsVisible}" />
</StackPanel>
</Button>
</Panel>
</StackPanel>
</UserControl>
@@ -1,6 +1,7 @@
using Avalonia.Controls;
using Avalonia.Platform.Storage;
using Avalonia.ReactiveUI;
using BD.WTTS.Helpers;
namespace BD.WTTS.UI.Views.Controls;
@@ -9,6 +10,8 @@ public partial class AcceleratorPathAskBox : ReactiveUserControl<MessageBoxWindo
public AcceleratorPathAskBox()
{
InitializeComponent();
TracepointHelper.TrackEvent("AcceleratorPathAskBoxShow");
}
private async void SelectWattAcceleratorInstallPath(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
@@ -36,4 +39,9 @@ public partial class AcceleratorPathAskBox : ReactiveUserControl<MessageBoxWindo
{
this.ViewModel?.Close?.Invoke(true);
}
private void CustomInstallButton_Click(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
{
PathSelect.IsVisible = !PathSelect.IsVisible;
}
}
@@ -71,14 +71,24 @@
Text="Beta" />
</Border>
</StackPanel>
<TextBlock
<StackPanel
Orientation="Horizontal"
Margin="0,0,4,0"
HorizontalAlignment="Right"
DockPanel.Dock="Right"
Foreground="{Binding DelayColor}"
Text="{Binding DelayMillseconds}"
ToolTip.ShowDelay="0"
ToolTip.Tip="此数值代表测试网页打开访问所需时间,请以实际浏览器访问网页状况为准" />
DockPanel.Dock="Right">
<TextBlock x:Name="DelayValue"
Foreground="{Binding DelayColor}" VerticalAlignment="Center"
Text="{Binding DelayMillseconds}" />
<ui:FontIcon
Margin="3,0"
FontSize="20"
Glyph="&#xE946;"
ToolTip.ShowDelay="0"
ToolTip.Tip="此数值代表测试网页打开访问所需时间,请以实际浏览器访问网页状况为准"
IsVisible="{Binding Text, ElementName=DelayValue, Converter={x:Static StringConverters.IsNotNullOrEmpty}}">
</ui:FontIcon>
</StackPanel>
</DockPanel>
</TreeDataTemplate>
</TreeView.ItemTemplate>
@@ -11,7 +11,7 @@
xmlns:ui="using:FluentAvalonia.UI.Controls"
d:DesignHeight="450"
d:DesignWidth="800"
x:DataType="spp:AcceleratorPageViewModel"
x:DataType="spp:NetworkCheckControlViewModel"
mc:Ignorable="d">
<ScrollViewer
Padding="0,0,10,0"
@@ -42,7 +42,6 @@
x:Name="NATCheckButton"
Width="100"
Margin="0,0,0,4"
x:FieldModifier="public"
Command="{Binding NATCheckCommand}"
Content="检测"
IsEnabled="True" />
@@ -63,14 +62,14 @@
x:Name="NATTextBlock"
VerticalAlignment="Center"
Foreground="Gray"
Text="未知" />
Text="{Binding NATLevel}" />
<ui:FontIcon
Margin="3,0"
FontSize="20"
Glyph="&#xE946;"
ToolTip.ShowDelay="0">
<ToolTip.Tip>
<TextBlock x:Name="NATTypeTip" Text="未知类型" />
<TextBlock x:Name="NATTypeTip" Text="{Binding NATTypeTip}" />
</ToolTip.Tip>
</ui:FontIcon>
</DockPanel>
@@ -126,13 +125,13 @@
<ui:FontIcon
x:Name="PingOK"
HorizontalAlignment="Right"
x:FieldModifier="public"
FontFamily="{StaticResource SymbolThemeFontFamily}"
FontSize="26"
Foreground="Green"
Glyph="&#xe73d;" />
Glyph="&#xe73d;"
IsVisible="{Binding PingOkVisible}" />
<Grid x:Name="PingError" x:FieldModifier="public">
<Grid x:Name="PingError" IsVisible="{Binding PingErrorVisible}">
<ui:FontIcon
Margin="3"
HorizontalAlignment="Right"
@@ -213,7 +212,50 @@
<TextBox
Width="220"
Text="{Binding DomainPendingTest, Mode=TwoWay}"
Watermark="store.steampowered.com" />
Watermark="{Binding DefaultTestDomain}">
<TextBox.Styles>
<Style Selector="DataValidationErrors">
<Setter Property="Template">
<ControlTemplate>
<DockPanel LastChildFill="True">
<ContentControl
Content="{Binding (DataValidationErrors.Errors)}"
ContentTemplate="{TemplateBinding ErrorTemplate}"
DataContext="{TemplateBinding Owner}"
DockPanel.Dock="Right"
IsVisible="{Binding (DataValidationErrors.HasErrors)}" />
<ContentPresenter
Name="PART_ContentPresenter"
Padding="{TemplateBinding Padding}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
CornerRadius="{TemplateBinding CornerRadius}" />
</DockPanel>
</ControlTemplate>
</Setter>
<Setter Property="ErrorTemplate">
<DataTemplate x:DataType="{x:Type x:Object}">
<Canvas
Width="14"
Height="14"
Margin="4,0,1,0"
Background="Transparent">
<ToolTip.Tip>
<ItemsControl ItemsSource="{Binding}" />
</ToolTip.Tip>
<Path
Data="M14,7 A7,7 0 0,0 0,7 M0,7 A7,7 0 1,0 14,7 M7,3l0,5 M7,9l0,2"
Stroke="Red"
StrokeThickness="2" />
</Canvas>
</DataTemplate>
</Setter>
</Style>
</TextBox.Styles>
</TextBox>
</ui:SettingsExpanderItem.Footer>
</ui:SettingsExpanderItem>
@@ -1,7 +1,4 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Org.BouncyCastle.Asn1.Utilities;
namespace BD.WTTS.UI.Views.Pages;
@@ -648,7 +648,7 @@
</Panel>
<!-- 网络检测 -->
<spp:NetworkCheck x:Name="NetworkCheckControl" />
<spp:NetworkCheck DataContext="{Binding NetworkCheckControlViewModel}" />
<TabItem Content="dummy_tab_for_transisit_animation" />
</Carousel>
@@ -73,31 +73,6 @@ public partial class AcceleratorPage2 : PageBase<AcceleratorPageViewModel>
GameAccTab.IsVisible = false;
AcceleratorTabs.SelectedIndex = 0;
}
NetworkCheckControl.PingOK.IsVisible = false;
NetworkCheckControl.PingError.IsVisible = false;
NetworkCheckControl.NATCheckButton.Click += (_, _) => NetworkCheckControl.PingError.IsVisible = NetworkCheckControl.PingOK.IsVisible = false;
ViewModel!.NATCheckCommand
.Subscribe(result =>
{
(NetworkCheckControl.NATTextBlock.Text, NetworkCheckControl.NATTypeTip.Text) = result.Nat switch
{
AcceleratorPageViewModel.NatTypeSimple.Open => ("开放 NAT", "您可与在其网络上具有任意 NAT 类型的用户玩多人游戏和发起多人游戏。"),
AcceleratorPageViewModel.NatTypeSimple.Moderate => ("中等 NAT", "您可与一些用户玩多人游戏;但是,并且通常你将不会被选为比赛的主持人。"),
AcceleratorPageViewModel.NatTypeSimple.Strict => ("严格 NAT", "您只能与具有开放 NAT 类型的用户玩多人游戏。您不能被选为比赛的主持人。"),
_ => ("不可用 NAT", "如果 NAT 不可用,您将无法使用群聊天或连接到某些 Xbox 游戏的多人游戏。"),
};
if (result.PingSuccess)
{
NetworkCheckControl.PingOK.IsVisible = true;
}
else
{
NetworkCheckControl.PingError.IsVisible = true;
}
}).DisposeWith(disposables);
ViewModel.IPv6CheckCommand.Execute().Subscribe();
});
SearchGameBox.DropDownClosed += SearchGameBox_DropDownClosed;
@@ -113,4 +113,22 @@ public sealed class Plugin : PluginBase<Plugin>, IPlugin
{
yield return GetConfiguration<ASFSettings_>(directoryExists);
}
public override async ValueTask OnExit()
{
if (ArchiSteamFarmServiceImpl.ASFProcessId.HasValue)
{
try
{
var process = Process.GetProcessById(ArchiSteamFarmServiceImpl.ASFProcessId.Value);
process.Kill();
process.Dispose();
}
catch (ArgumentException)
{
// 进程已经退出
}
}
await base.OnExit();
}
}
@@ -27,6 +27,8 @@ public partial class ArchiSteamFarmServiceImpl : ReactiveObject, IArchiSteamFarm
{
}
public static int? ASFProcessId { get; private set; }
public Process? ASFProcess { get; set; }
public event Action<string>? OnConsoleWirteLine;
@@ -89,26 +91,48 @@ public partial class ArchiSteamFarmServiceImpl : ReactiveObject, IArchiSteamFarm
{
var isStartSuccess = false;
var ipcUrl = string.Empty;
try
if (ASFProcess != null || string.IsNullOrEmpty(SharedInfo.ASFExecuteFilePath))
{
if (ASFProcess != null || string.IsNullOrEmpty(SharedInfo.ASFExecuteFilePath))
{
Toast.Show(ToastIcon.Error, BDStrings.ASF_SelectASFExePath);
return (isStartSuccess, ipcUrl);
}
Toast.Show(ToastIcon.Error, BDStrings.ASF_SelectASFExePath);
return (isStartSuccess, ipcUrl);
}
if (ASFSettings.CheckArchiSteamFarmExe && !await CheckFileConsistence()) // 检查文件是否被篡改
{
Toast.Show(ToastIcon.Error, BDStrings.ASF_ExecuteFileUnsafe);
return (isStartSuccess, ipcUrl);
}
if (ASFSettings.CheckArchiSteamFarmExe && !await CheckFileConsistence()) // 检查文件是否被篡改
{
Toast.Show(ToastIcon.Error, BDStrings.ASF_ExecuteFileUnsafe);
return (isStartSuccess, ipcUrl);
}
ipcUrl = GetIPCUrl();
webApiService.SetIPCUrl(ipcUrl); // 设置 IPC 接口地址
ipcUrl = GetIPCUrl();
webApiService.SetIPCUrl(ipcUrl); // 设置 IPC 接口地址
KillASFProcess(); // 杀死未关闭的 ASF 进程
KillASFProcess(); // 杀死未关闭的 ASF 进程
var options = new ProcessStartInfo(SharedInfo.ASFExecuteFilePath);
ASFProcess = StartAsync(SharedInfo.ASFExecuteFilePath);
ASFProcessId = ASFProcess?.Id;
ASFService.Current.ConsoleLogText = string.Empty;
Task2.InBackground(ReadOutPutData, true);
AppDomain.CurrentDomain.ProcessExit += ExitHandler;
AppDomain.CurrentDomain.UnhandledException += ExitHandler;
ASFProcess!.ErrorDataReceived += new DataReceivedEventHandler(ExitHandler);
ASFProcess.BeginErrorReadLine();
using var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(60));
while (
!(isStartSuccess = SocketHelper.IsUsePort(CurrentIPCPortValue)) &&
!cancellationTokenSource.IsCancellationRequested)
{
await Task.Delay(1000);
continue;
}
return (isStartSuccess, ipcUrl);
Process? StartAsync(string fileName)
{
var options = new ProcessStartInfo(fileName);
options.CreateNoWindow = true;
options.UseShellExecute = false;
options.RedirectStandardOutput = true;
@@ -120,26 +144,8 @@ public partial class ArchiSteamFarmServiceImpl : ReactiveObject, IArchiSteamFarm
options.ArgumentList.Add("--CRYPTKEY");
options.ArgumentList.Add(EncryptionKey);
}
ASFProcess = Process.Start(options);
ASFService.Current.ConsoleLogText = string.Empty;
Task2.InBackground(ReadOutPutData, true);
AppDomain.CurrentDomain.ProcessExit += ExitHandler;
AppDomain.CurrentDomain.UnhandledException += ExitHandler;
ASFProcess!.ErrorDataReceived += new DataReceivedEventHandler(ExitHandler);
ASFProcess.BeginErrorReadLine();
while (!SocketHelper.IsUsePort(CurrentIPCPortValue))
{
Thread.Sleep(1000);
continue;
}
isStartSuccess = true;
return Process.Start(options);
}
catch (Exception)
{
}
return (isStartSuccess, ipcUrl);
}
private void KillASFProcess()
@@ -156,8 +156,20 @@ public sealed class ASFService : ReactiveObject
public void OpenFolder(string tag)
{
if (!Enum.TryParse<EPathFolder>(tag, true, out var folderASFPath)) return;
var folderASFPathValue = folderASFPath.GetFolderPath();
if (string.IsNullOrEmpty(ASFSettings.ArchiSteamFarmExePath.Value))
{
Toast.Show(ToastIcon.Error, BDStrings.ASF_SetExePathFirst);
return;
}
string folderASFPathValue = string.Empty;
if (!Enum.TryParse<EPathFolder>(tag, true, out var folderASFPath) ||
!Path.Exists(folderASFPathValue = folderASFPath.GetFolderPath()))
{
Toast.Show(ToastIcon.Error, BDStrings.ASF_SelectASFExePath);
return;
}
IPlatformService.Instance.OpenFolder(folderASFPathValue);
}
@@ -168,6 +180,17 @@ public sealed class ASFService : ReactiveObject
ActionItem.Repo => "https://github.com/JustArchiNET/ArchiSteamFarm",
ActionItem.Wiki => "https://github.com/JustArchiNET/ArchiSteamFarm/wiki/Home-zh-CN",
ActionItem.ConfigGenerator => "https://justarchinet.github.io/ASF-WebConfigGenerator",
_ => string.Empty,
};
if (url != string.Empty)
{
await Browser2.OpenAsync(url, BrowserLaunchMode.External);
return;
}
url = tag switch
{
ActionItem.WebConfig => IPCUrl + "/asf-config",
ActionItem.WebAddBot => IPCUrl + "/bot/new",
_ => IPCUrl,
@@ -1,3 +1,5 @@
using FluentAvalonia.UI.Controls;
namespace BD.WTTS.UI.ViewModels;
public partial class ArchiSteamFarmExePathSettingsPageViewModel : ViewModelBase
@@ -9,11 +11,51 @@ public partial class ArchiSteamFarmExePathSettingsPageViewModel : ViewModelBase
public ArchiSteamFarmExePathSettingsPageViewModel()
{
SelectProgramPath = ReactiveCommand.Create(ASFService.Current.SelectASFProgramLocationAsync);
DownloadASF = ReactiveCommand.Create(() =>
DownloadASF = ReactiveCommand.Create(async () =>
{
var progress = INotificationService.Instance.NotifyDownload(() => "开始下载 ASF ", NotificationType.NewVersion);
ASFService.Current.DownloadASFAsync(progress: progress);
Toast.Show(ToastIcon.Info, "等待后台下载文件", ToastLength.Short);
if (INotificationService.Instance.IsSupportNotifyDownload)
{
var progress = INotificationService.Instance.NotifyDownload(() => "开始下载 ASF ", NotificationType.NewVersion);
ASFService.Current.DownloadASFAsync(progress: progress);
Toast.Show(ToastIcon.Info, "等待后台下载文件", ToastLength.Short);
}
else
{
var (downloadDialog, progress) = CreateDownloadDialog();
ASFService.Current.DownloadASFAsync(progress: progress);
_ = await downloadDialog.ShowAsync(true);
}
});
}
}
private static (TaskDialog DownloadDialog, IProgress<float> Progress) CreateDownloadDialog()
{
var downloadDialog = new TaskDialog
{
Title = "下载插件",
ShowProgressBar = true,
IconSource = new SymbolIconSource { Symbol = Symbol.Download },
SubHeader = "开始下载 ASF",
Content = "正在初始化,请稍候",
XamlRoot = AvaloniaWindowManagerImpl.GetWindowTopLevel(),
// DownloadASFAsync() 无法取消后再次开启下载
//Buttons = [new TaskDialogButton("取消", TaskDialogStandardResult.Cancel)],
};
downloadDialog.Opened += (_, _) => { downloadDialog.SetProgressBarState(0, TaskDialogProgressState.Normal); };
var progress = new Progress<float>();
progress.ProgressChanged += (_, value) =>
{
// Value here report 1-100
downloadDialog.Content = $"正在下载 {value}%";
downloadDialog.SetProgressBarState(value, TaskDialogProgressState.Normal);
if (value >= 100)
{
downloadDialog.Hide();
}
};
return (downloadDialog, progress);
}
}

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