From d0d6f7c891f69c19086ff3a8b614462de6524af0 Mon Sep 17 00:00:00 2001 From: mkmark Date: Mon, 12 Aug 2024 02:32:37 +0800 Subject: [PATCH] feat: custom core version --- .github/workflows/build-qv2ray-cmake.yml | 3 - CMakeLists.txt | 8 -- src/base/Qv2rayBase.hpp | 4 +- src/base/models/QvSettingsObject.hpp | 17 +++- src/core/kernel/V2RayKernelInteractions.cpp | 88 ++++++++++++------- src/core/kernel/V2RayKernelInteractions.hpp | 4 +- src/core/settings/SettingsBackend.cpp | 1 + .../widgets/windows/w_PreferencesWindow.cpp | 58 ++++++------ .../widgets/windows/w_PreferencesWindow.hpp | 3 +- src/ui/widgets/windows/w_PreferencesWindow.ui | 62 ++++++++++--- translations/en_US.ts | 4 + 11 files changed, 163 insertions(+), 89 deletions(-) diff --git a/.github/workflows/build-qv2ray-cmake.yml b/.github/workflows/build-qv2ray-cmake.yml index 997c858b5..063113f0c 100644 --- a/.github/workflows/build-qv2ray-cmake.yml +++ b/.github/workflows/build-qv2ray-cmake.yml @@ -123,7 +123,6 @@ jobs: -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} \ -DCMAKE_OSX_DEPLOYMENT_TARGET=10.13 \ -DDS_STORE_SCRIPT=ON \ - -DQV2RAY_USE_V5_CORE=ON \ -DQV2RAY_DEFAULT_VASSETS_PATH=/usr/local/opt/v2ray/share/v2ray \ -DQV2RAY_DEFAULT_VCORE_PATH=/usr/local/opt/v2ray/bin/v2ray cmake --build . --parallel $(sysctl -n hw.logicalcpu) @@ -141,7 +140,6 @@ jobs: cd build cmake .. -GNinja \ -DCMAKE_INSTALL_PREFIX=./deployment \ - -DQV2RAY_USE_V5_CORE=ON \ -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} cmake --build . --parallel $(nproc) cmake --install . @@ -155,7 +153,6 @@ jobs: cd build cmake .. -GNinja \ -DCMAKE_INSTALL_PREFIX=./AppDir/usr \ - -DQV2RAY_USE_V5_CORE=ON \ -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} \ -DQV2RAY_TRANSLATION_PATH=QApplication::applicationDirPath\(\)+"/../share/qv2ray/lang" cmake --build . --parallel $(nproc) diff --git a/CMakeLists.txt b/CMakeLists.txt index 27c605e18..f329d591d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -130,9 +130,6 @@ option(QV2RAY_HAS_SINGLEAPPLICATION "Build With SingleApplication" ON) set(QV2RAY_UI_TYPE "QWidget" CACHE STRING "Qv2ray GUI Component") QVLOG(QV2RAY_UI_TYPE) -option(QV2RAY_USE_V5_CORE "Use V5 Core" ON) -QVLOG(QV2RAY_USE_V5_CORE) - option(QV2RAY_QT6 "Use Qt6" OFF) if(QV2RAY_UI_TYPE STREQUAL "QWidget") @@ -334,11 +331,6 @@ target_include_directories(qv2ray_baselib PUBLIC ${Protobuf_INCLUDE_DIRS} ) -if(QV2RAY_USE_V5_CORE) - message("-- Use V2Ray Core V5") - target_compile_definitions(qv2ray_baselib PUBLIC QV2RAY_USE_V5_CORE) -endif() - # ================================================================================== # Qv2ray Builtin Plugins # ================================================================================== diff --git a/src/base/Qv2rayBase.hpp b/src/base/Qv2rayBase.hpp index d369e10ca..ba9a1b178 100644 --- a/src/base/Qv2rayBase.hpp +++ b/src/base/Qv2rayBase.hpp @@ -63,9 +63,7 @@ using namespace Qv2ray::base::objects::transfer; #if !defined(QV2RAY_DEFAULT_VCORE_PATH) && !defined(QV2RAY_DEFAULT_VASSETS_PATH) #define QV2RAY_DEFAULT_VASSETS_PATH (QV2RAY_CONFIG_DIR + "vcore/") #define QV2RAY_DEFAULT_VCORE_PATH (QV2RAY_CONFIG_DIR + "vcore/v2ray" QV2RAY_EXECUTABLE_SUFFIX) -#if !defined(QV2RAY_USE_V5_CORE) -#define QV2RAY_DEFAULT_VCTL_PATH (QV2RAY_CONFIG_DIR + "vcore/v2ctl" QV2RAY_EXECUTABLE_SUFFIX) -#endif +// #define QV2RAY_DEFAULT_VCTL_PATH (QV2RAY_CONFIG_DIR + "vcore/v2ctl" QV2RAY_EXECUTABLE_SUFFIX) #elif defined(QV2RAY_DEFAULT_VCORE_PATH) && defined(QV2RAY_DEFAULT_VASSETS_PATH) // ---- Using user-specified VCore and VAssets path #else diff --git a/src/base/models/QvSettingsObject.hpp b/src/base/models/QvSettingsObject.hpp index e04fdfc8f..777a8a806 100644 --- a/src/base/models/QvSettingsObject.hpp +++ b/src/base/models/QvSettingsObject.hpp @@ -14,7 +14,7 @@ namespace Qv2ray::base::config int R = 150, G = 150, B = 150; float width = 1.5f; Qt::PenStyle style = Qt::SolidLine; - QvGraphPenConfig(){}; + QvGraphPenConfig() {}; QvGraphPenConfig(int R, int G, int B, float w, Qt::PenStyle s) { this->R = R; @@ -64,8 +64,9 @@ namespace Qv2ray::base::config bool exitByCloseEvent = false; JSONSTRUCT_COMPARE(Qv2rayConfig_UI, theme, language, quietMode, graphConfig, useDarkTheme, useDarkTrayIcon, useGlyphTrayIcon, maximumLogLines, maxJumpListCount, recentConnections, useOldShareLinkFormat, startMinimized, exitByCloseEvent) - JSONSTRUCT_REGISTER(Qv2rayConfig_UI, F(theme, language, quietMode, graphConfig, useDarkTheme, useDarkTrayIcon, useGlyphTrayIcon, - maximumLogLines, maxJumpListCount, recentConnections, useOldShareLinkFormat, startMinimized, exitByCloseEvent)) + JSONSTRUCT_REGISTER(Qv2rayConfig_UI, + F(theme, language, quietMode, graphConfig, useDarkTheme, useDarkTrayIcon, useGlyphTrayIcon, maximumLogLines, + maxJumpListCount, recentConnections, useOldShareLinkFormat, startMinimized, exitByCloseEvent)) }; struct Qv2rayConfig_Plugin @@ -77,6 +78,12 @@ namespace Qv2ray::base::config JSONSTRUCT_REGISTER(Qv2rayConfig_Plugin, F(pluginStates, v2rayIntegration, portAllocationStart)) }; + enum CoreVersion + { + COREVERSION_V2RAY_V5, + COREVERSION_V2RAY_V4 + }; + struct Qv2rayConfig_Kernel { bool enableAPI = true; @@ -89,6 +96,8 @@ namespace Qv2ray::base::config QString v2CorePath_win; QString v2AssetsPath_win; + CoreVersion coreVersion = (CoreVersion) 0; + #ifdef Q_OS_LINUX #define _VARNAME_VCOREPATH_ v2CorePath_linux #define _VARNAME_VASSETSPATH_ v2AssetsPath_linux @@ -113,11 +122,13 @@ namespace Qv2ray::base::config #undef _VARNAME_VASSETSPATH_ JSONSTRUCT_COMPARE(Qv2rayConfig_Kernel, enableAPI, statsPort, // + coreVersion, // v2CorePath_linux, v2AssetsPath_linux, // v2CorePath_macx, v2AssetsPath_macx, // v2CorePath_win, v2AssetsPath_win) JSONSTRUCT_REGISTER(Qv2rayConfig_Kernel, // F(enableAPI, statsPort), // + F(coreVersion), // F(v2CorePath_linux, v2AssetsPath_linux), // F(v2CorePath_macx, v2AssetsPath_macx), // F(v2CorePath_win, v2AssetsPath_win)) diff --git a/src/core/kernel/V2RayKernelInteractions.cpp b/src/core/kernel/V2RayKernelInteractions.cpp index e4f8d89a7..6aa3fc3a5 100644 --- a/src/core/kernel/V2RayKernelInteractions.cpp +++ b/src/core/kernel/V2RayKernelInteractions.cpp @@ -9,18 +9,11 @@ #define QV2RAY_GENERATED_FILE_PATH (QV2RAY_GENERATED_DIR + "config.gen.json") #define QV_MODULE_NAME "V2RayInteraction" -#ifdef QV2RAY_USE_V5_CORE -#define V2RAY_CORE_VERSION_ARGV "version" -#define V2RAY_CORE_CONFIG_ARGV "run", "-config" -#else -#define V2RAY_CORE_VERSION_ARGV "--version" -#define V2RAY_CORE_CONFIG_ARGV "--config" -#endif - namespace Qv2ray::core::kernel { #if QV2RAY_FEATURE(kernel_check_permission) - std::pair> V2RayKernelInstance::CheckAndSetCoreExecutableState(const QString &vCorePath) + std::pair> V2RayKernelInstance::CheckAndSetCoreExecutableState(const Qv2ray::base::config::CoreVersion vCoreVersion, + const QString &vCorePath) { #ifdef Q_OS_UNIX // For Linux/macOS users: if they cannot execute the core, @@ -59,7 +52,8 @@ namespace Qv2ray::core::kernel } #endif - std::pair> V2RayKernelInstance::ValidateKernel(const QString &corePath, const QString &assetsPath) + std::pair> V2RayKernelInstance::ValidateKernel(const Qv2ray::base::config::CoreVersion coreVersion, + const QString &corePath, const QString &assetsPath) { QFile coreFile(corePath); @@ -114,7 +108,7 @@ namespace Qv2ray::core::kernel #if QV2RAY_FEATURE(kernel_check_permission) // Check executable permissions. - const auto [isExecutableOk, strExecutableErr] = CheckAndSetCoreExecutableState(corePath); + const auto [isExecutableOk, strExecutableErr] = CheckAndSetCoreExecutableState(coreVersion, corePath); if (!isExecutableOk) return { false, strExecutableErr.value_or("") }; #endif @@ -140,10 +134,23 @@ namespace Qv2ray::core::kernel // reason... proc.setProcessChannelMode(QProcess::MergedChannels); proc.setProgram(corePath); - proc.setNativeArguments(V2RAY_CORE_VERSION_ARGV); + switch (coreVersion) + { + case Qv2ray::base::config::COREVERSION_V2RAY_V5: proc.setNativeArguments("version"); break; + case Qv2ray::base::config::COREVERSION_V2RAY_V4: proc.setNativeArguments("--version"); break; + + default: break; + } + proc.start(); #else - proc.start(corePath, { V2RAY_CORE_VERSION_ARGV }); + switch (coreVersion) + { + case Qv2ray::base::config::COREVERSION_V2RAY_V5: proc.start(corePath, { "version" }); break; + case Qv2ray::base::config::COREVERSION_V2RAY_V4: proc.start(corePath, { "--version" }); break; + + default: break; + } #endif proc.waitForStarted(); proc.waitForFinished(); @@ -165,7 +172,8 @@ namespace Qv2ray::core::kernel { const auto kernelPath = GlobalConfig.kernelConfig.KernelPath(); const auto assetsPath = GlobalConfig.kernelConfig.AssetsPath(); - if (const auto &[result, msg] = ValidateKernel(kernelPath, assetsPath); result) + const auto coreVersion = GlobalConfig.kernelConfig.coreVersion; + if (const auto &[result, msg] = ValidateKernel(coreVersion, kernelPath, assetsPath); result) { DEBUG("V2Ray version: " + *msg); // Append assets location env. @@ -176,11 +184,17 @@ namespace Qv2ray::core::kernel QProcess process; process.setProcessEnvironment(env); DEBUG("Starting V2Ray core with test options"); -#ifdef QV2RAY_USE_V5_CORE - process.start(kernelPath, { "test", "-c", path }, QIODevice::ReadWrite | QIODevice::Text); -#else - process.start(kernelPath, { "-test", "-config", path }, QIODevice::ReadWrite | QIODevice::Text); -#endif + switch (coreVersion) + { + case Qv2ray::base::config::COREVERSION_V2RAY_V5: + process.start(kernelPath, { "test", "-c", path }, QIODevice::ReadWrite | QIODevice::Text); + break; + case Qv2ray::base::config::COREVERSION_V2RAY_V4: + process.start(kernelPath, { "-test", "-config", path }, QIODevice::ReadWrite | QIODevice::Text); + break; + + default: break; + } process.waitForFinished(); if (process.exitCode() != 0) @@ -204,17 +218,19 @@ namespace Qv2ray::core::kernel vProcess = new QProcess(); connect(vProcess, &QProcess::readyReadStandardOutput, this, [&]() { emit OnProcessOutputReadyRead(vProcess->readAllStandardOutput().trimmed()); }); - connect(vProcess, &QProcess::stateChanged, [&](QProcess::ProcessState state) { - DEBUG("V2Ray kernel process status changed: " + QVariant::fromValue(state).toString()); - - // If V2Ray crashed AFTER we start it. - if (kernelStarted && state == QProcess::NotRunning) - { - LOG("V2Ray kernel crashed."); - StopConnection(); - emit OnProcessErrored("V2Ray kernel crashed."); - } - }); + connect(vProcess, &QProcess::stateChanged, + [&](QProcess::ProcessState state) + { + DEBUG("V2Ray kernel process status changed: " + QVariant::fromValue(state).toString()); + + // If V2Ray crashed AFTER we start it. + if (kernelStarted && state == QProcess::NotRunning) + { + LOG("V2Ray kernel crashed."); + StopConnection(); + emit OnProcessErrored("V2Ray kernel crashed."); + } + }); apiWorker = new APIWorker(); qRegisterMetaType(); qRegisterMetaType>(); @@ -244,7 +260,17 @@ namespace Qv2ray::core::kernel env.insert("v2ray.location.asset", GlobalConfig.kernelConfig.AssetsPath()); env.insert("XRAY_LOCATION_ASSET", GlobalConfig.kernelConfig.AssetsPath()); vProcess->setProcessEnvironment(env); - vProcess->start(GlobalConfig.kernelConfig.KernelPath(), { V2RAY_CORE_CONFIG_ARGV, filePath }, QIODevice::ReadWrite | QIODevice::Text); + switch (GlobalConfig.kernelConfig.coreVersion) + { + case Qv2ray::base::config::COREVERSION_V2RAY_V5: + vProcess->start(GlobalConfig.kernelConfig.KernelPath(), { "run", "-config", filePath }, QIODevice::ReadWrite | QIODevice::Text); + break; + case Qv2ray::base::config::COREVERSION_V2RAY_V4: + vProcess->start(GlobalConfig.kernelConfig.KernelPath(), { "--config", filePath }, QIODevice::ReadWrite | QIODevice::Text); + break; + + default: break; + } vProcess->waitForStarted(); kernelStarted = true; diff --git a/src/core/kernel/V2RayKernelInteractions.hpp b/src/core/kernel/V2RayKernelInteractions.hpp index 513d199b5..61991e735 100644 --- a/src/core/kernel/V2RayKernelInteractions.hpp +++ b/src/core/kernel/V2RayKernelInteractions.hpp @@ -22,9 +22,9 @@ namespace Qv2ray::core::kernel } // static std::optional ValidateConfig(const QString &path); - static std::pair> ValidateKernel(const QString &vCorePath, const QString &vAssetsPath); + static std::pair> ValidateKernel(const Qv2ray::base::config::CoreVersion coreVersion, const QString &vCorePath, const QString &vAssetsPath); #if QV2RAY_FEATURE(kernel_check_permission) - static std::pair> CheckAndSetCoreExecutableState(const QString &vCorePath); + static std::pair> CheckAndSetCoreExecutableState(const Qv2ray::base::config::CoreVersion coreVersion, const QString &vCorePath); #endif signals: diff --git a/src/core/settings/SettingsBackend.cpp b/src/core/settings/SettingsBackend.cpp index 8e60cf70f..f3c79f6bb 100644 --- a/src/core/settings/SettingsBackend.cpp +++ b/src/core/settings/SettingsBackend.cpp @@ -214,6 +214,7 @@ namespace Qv2ray::core::config GlobalConfig.kernelConfig.KernelPath(QV2RAY_DEFAULT_VCORE_PATH); GlobalConfig.kernelConfig.AssetsPath(QV2RAY_DEFAULT_VASSETS_PATH); + GlobalConfig.kernelConfig.coreVersion = Qv2ray::base::config::COREVERSION_V2RAY_V5; GlobalConfig.logLevel = 3; GlobalConfig.uiConfig.language = QLocale::system().name(); GlobalConfig.defaultRouteConfig.dnsConfig.servers.append({ "1.1.1.1" }); diff --git a/src/ui/widgets/windows/w_PreferencesWindow.cpp b/src/ui/widgets/windows/w_PreferencesWindow.cpp index 1ad6d57f4..4eec822e5 100644 --- a/src/ui/widgets/windows/w_PreferencesWindow.cpp +++ b/src/ui/widgets/windows/w_PreferencesWindow.cpp @@ -93,6 +93,7 @@ PreferencesWindow::PreferencesWindow(QWidget *parent) : QvDialog("PreferenceWind glyphTrayCB->setChecked(CurrentConfig.uiConfig.useGlyphTrayIcon); languageComboBox->setCurrentText(CurrentConfig.uiConfig.language); logLevelComboBox->setCurrentIndex(CurrentConfig.logLevel); + coreVersionComboBox->setCurrentIndex(CurrentConfig.kernelConfig.coreVersion); quietModeCB->setChecked(CurrentConfig.uiConfig.quietMode); useOldShareLinkFormatCB->setChecked(CurrentConfig.uiConfig.useOldShareLinkFormat); startMinimizedCB->setChecked(CurrentConfig.uiConfig.startMinimized); @@ -317,7 +318,7 @@ QvMessageBusSlotImpl(PreferencesWindow) } } -PreferencesWindow::~PreferencesWindow(){}; +PreferencesWindow::~PreferencesWindow() {}; std::optional PreferencesWindow::checkTProxySettings() const { @@ -463,6 +464,12 @@ void PreferencesWindow::on_logLevelComboBox_currentIndexChanged(int index) CurrentConfig.logLevel = index; } +void PreferencesWindow::on_coreVersionComboBox_currentIndexChanged(int index) +{ + NEEDRESTART + CurrentConfig.kernelConfig.coreVersion = (Qv2ray::base::config::CoreVersion) index; +} + void PreferencesWindow::on_vCoreAssetsPathTxt_textEdited(const QString &arg1) { NEEDRESTART @@ -752,6 +759,7 @@ void PreferencesWindow::on_fpPortSB_valueChanged(int arg1) void PreferencesWindow::on_checkVCoreSettings_clicked() { + auto vcoreVersion = (Qv2ray::base::config::CoreVersion) coreVersionComboBox->currentIndex(); auto vcorePath = vCorePathTxt->text(); auto vAssetsPath = vCoreAssetsPathTxt->text(); @@ -764,7 +772,6 @@ void PreferencesWindow::on_checkVCoreSettings_clicked() "If your V2Ray core filename happened to be 'qv2ray'-something, you are totally free to ignore this warning."); QvMessageBoxWarn(this, tr("Watch Out!"), content); } -#if !defined(QV2RAY_USE_V5_CORE) else if (vCorePathSmallCased.endsWith("v2ctl") || vCorePathSmallCased.endsWith("v2ctl.exe")) { const auto content = tr("You may be about to set V2Ray core incorrectly to V2Ray Control executable, which is absolutely not correct.\r\n" @@ -772,10 +779,9 @@ void PreferencesWindow::on_checkVCoreSettings_clicked() "If you insist to proceed, we're not providing with any support."); QvMessageBoxWarn(this, tr("Watch Out!"), content); } -#endif #endif - if (const auto &&[result, msg] = V2RayKernelInstance::ValidateKernel(vcorePath, vAssetsPath); !result) + if (const auto &&[result, msg] = V2RayKernelInstance::ValidateKernel(vcoreVersion, vcorePath, vAssetsPath); !result) { QvMessageBoxWarn(this, tr("V2Ray Core Settings"), *msg); } @@ -1131,27 +1137,29 @@ void PreferencesWindow::on_pushButton_clicked() return; auto client = new ntp::NtpClient(this); - connect(client, &ntp::NtpClient::replyReceived, [&](const QHostAddress &, quint16, const ntp::NtpReply &reply) { - const int offsetSecTotal = reply.localClockOffset() / 1000; - if (offsetSecTotal >= 90 || offsetSecTotal <= -90) - { - const auto inaccurateWarning = tr("Your time offset is %1 seconds, which is too high.") + NEWLINE + // - tr("Please synchronize your system to use the VMess protocol."); - QvMessageBoxWarn(this, tr("Time Inaccurate"), inaccurateWarning.arg(offsetSecTotal)); - } - else if (offsetSecTotal > 15 || offsetSecTotal < -15) - { - const auto smallErrorWarning = tr("Your time offset is %1 seconds, which is a little high.") + NEWLINE + // - tr("VMess protocol may still work, but we suggest you synchronize your clock."); - QvMessageBoxInfo(this, tr("Time Somewhat Inaccurate"), smallErrorWarning.arg(offsetSecTotal)); - } - else - { - const auto accurateInfo = tr("Your time offset is %1 seconds, which looks good.") + NEWLINE + // - tr("VMess protocol may not suffer from time inaccuracy."); - QvMessageBoxInfo(this, tr("Time Accurate"), accurateInfo.arg(offsetSecTotal)); - } - }); + connect(client, &ntp::NtpClient::replyReceived, + [&](const QHostAddress &, quint16, const ntp::NtpReply &reply) + { + const int offsetSecTotal = reply.localClockOffset() / 1000; + if (offsetSecTotal >= 90 || offsetSecTotal <= -90) + { + const auto inaccurateWarning = tr("Your time offset is %1 seconds, which is too high.") + NEWLINE + // + tr("Please synchronize your system to use the VMess protocol."); + QvMessageBoxWarn(this, tr("Time Inaccurate"), inaccurateWarning.arg(offsetSecTotal)); + } + else if (offsetSecTotal > 15 || offsetSecTotal < -15) + { + const auto smallErrorWarning = tr("Your time offset is %1 seconds, which is a little high.") + NEWLINE + // + tr("VMess protocol may still work, but we suggest you synchronize your clock."); + QvMessageBoxInfo(this, tr("Time Somewhat Inaccurate"), smallErrorWarning.arg(offsetSecTotal)); + } + else + { + const auto accurateInfo = tr("Your time offset is %1 seconds, which looks good.") + NEWLINE + // + tr("VMess protocol may not suffer from time inaccuracy."); + QvMessageBoxInfo(this, tr("Time Accurate"), accurateInfo.arg(offsetSecTotal)); + } + }); const auto hostInfo = QHostInfo::fromName(ntpServer); if (hostInfo.error() == QHostInfo::NoError) diff --git a/src/ui/widgets/windows/w_PreferencesWindow.hpp b/src/ui/widgets/windows/w_PreferencesWindow.hpp index 356f80748..2423507dc 100644 --- a/src/ui/widgets/windows/w_PreferencesWindow.hpp +++ b/src/ui/widgets/windows/w_PreferencesWindow.hpp @@ -39,7 +39,7 @@ class PreferencesWindow } private: - void updateColorScheme() override{}; + void updateColorScheme() override {}; QvMessageBusSlotDecl override; private slots: @@ -48,6 +48,7 @@ class PreferencesWindow void on_socksAuthCB_stateChanged(int arg1); void on_languageComboBox_currentTextChanged(const QString &arg1); void on_logLevelComboBox_currentIndexChanged(int index); + void on_coreVersionComboBox_currentIndexChanged(int index); void on_vCoreAssetsPathTxt_textEdited(const QString &arg1); void on_listenIPTxt_textEdited(const QString &arg1); void on_socksPortLE_valueChanged(int arg1); diff --git a/src/ui/widgets/windows/w_PreferencesWindow.ui b/src/ui/widgets/windows/w_PreferencesWindow.ui index 396f28fb2..5cf1eb09e 100644 --- a/src/ui/widgets/windows/w_PreferencesWindow.ui +++ b/src/ui/widgets/windows/w_PreferencesWindow.ui @@ -752,6 +752,42 @@ Qv2ray will give a more accurate latency value if Enabled, but makes it easy to + + + Core Version + + + Qt::PlainText + + + + + + + + 0 + 0 + + + + + 150 + 0 + + + + + 5 + + + + + 4 + + + + + V2Ray Core Executable Path @@ -761,7 +797,7 @@ Qv2ray will give a more accurate latency value if Enabled, but makes it easy to - + @@ -779,7 +815,7 @@ Qv2ray will give a more accurate latency value if Enabled, but makes it easy to - + V2Ray Assets Directory @@ -789,7 +825,7 @@ Qv2ray will give a more accurate latency value if Enabled, but makes it easy to - + @@ -803,21 +839,21 @@ Qv2ray will give a more accurate latency value if Enabled, but makes it easy to - + Check V2Ray Core Settings - + Check System Date and Time from the Internet - + V2Ray API Subsystem @@ -827,14 +863,14 @@ Qv2ray will give a more accurate latency value if Enabled, but makes it easy to - + Enabled - + V2Ray API Port @@ -844,7 +880,7 @@ Qv2ray will give a more accurate latency value if Enabled, but makes it easy to - + @@ -863,14 +899,14 @@ Qv2ray will give a more accurate latency value if Enabled, but makes it easy to - + Outbound Statistics (V2Ray Core v4.26+) - + Currently: @@ -883,14 +919,14 @@ Qv2ray will give a more accurate latency value if Enabled, but makes it easy to - + Include Direct Connection - + Enabled diff --git a/translations/en_US.ts b/translations/en_US.ts index 10524c3f3..148ed234b 100644 --- a/translations/en_US.ts +++ b/translations/en_US.ts @@ -1402,6 +1402,10 @@ For example, for updating subscriptions. Log Level + + Core Version + + none