diff --git a/vrcosc-magicchatbox/Classes/DataAndSecurity/DataController.cs b/vrcosc-magicchatbox/Classes/DataAndSecurity/DataController.cs index f9cdf857..89411789 100644 --- a/vrcosc-magicchatbox/Classes/DataAndSecurity/DataController.cs +++ b/vrcosc-magicchatbox/Classes/DataAndSecurity/DataController.cs @@ -393,6 +393,7 @@ public static void LoadComponentStats() { "ChatAddSmallDelayTIME", (typeof(double), "Chat") }, { "ChattingUpdateRate", (typeof(double), "Chat") }, { "RealTimeChatEdit", (typeof(bool), "Chat") }, + { "HideOpenAITools", (typeof(bool), "Chat") }, { "SeperateWithENTERS", (typeof(bool), "Custom") }, @@ -1054,7 +1055,11 @@ public static List ReadTkTkTTSVoices() { try { - string json = File.ReadAllText(@"Json\voices.json"); + string currentrunningAppdir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + + + string voicesFilePath = Path.Combine(currentrunningAppdir, "Json", "voices.json"); + string json = File.ReadAllText(voicesFilePath); List ConfirmList = JsonConvert.DeserializeObject>(json); if (string.IsNullOrEmpty(ViewModel.Instance.RecentTikTokTTSVoice) || ConfirmList.Count == 0) @@ -1064,10 +1069,7 @@ public static List ReadTkTkTTSVoices() if (!string.IsNullOrEmpty(ViewModel.Instance.RecentTikTokTTSVoice) || ConfirmList.Count == 0) { Voice selectedVoice = ConfirmList.FirstOrDefault(v => v.ApiName == ViewModel.Instance.RecentTikTokTTSVoice); - if (selectedVoice == null) - { - } - else + if (selectedVoice != null) { ViewModel.Instance.SelectedTikTokTTSVoice = selectedVoice; } diff --git a/vrcosc-magicchatbox/Classes/Modules/ComponentStatsModule.cs b/vrcosc-magicchatbox/Classes/Modules/ComponentStatsModule.cs index 1b54eb80..8d854891 100644 --- a/vrcosc-magicchatbox/Classes/Modules/ComponentStatsModule.cs +++ b/vrcosc-magicchatbox/Classes/Modules/ComponentStatsModule.cs @@ -6,6 +6,7 @@ using System.Globalization; using System.IO; using System.Linq; +using System.Management; using System.Threading.Tasks; using System.Windows; using vrcosc_magicchatbox.Classes.DataAndSecurity; @@ -20,6 +21,7 @@ public class ComponentStatsModule private readonly List _componentStats = new List(); private static string FileName = null; public bool started = false; + private string _ramDDRVersion = "Unknown"; public void StartModule() { @@ -27,7 +29,81 @@ public void StartModule() ViewModel.Instance.IsVRRunning || ViewModel.Instance.IntgrComponentStats && ViewModel.Instance.IntgrComponentStats_DESKTOP && !ViewModel.Instance.IsVRRunning) + { LoadComponentStats(); + FetchAndStoreDDRVersion(); + } + + } + + private void FetchAndStoreDDRVersion() + { + _ramDDRVersion = GetDDRVersion(); + var ramItem = _componentStats.FirstOrDefault(stat => stat.ComponentType == StatsComponentType.RAM); + if (ramItem != null) + { + ramItem.DDRVersion = _ramDDRVersion; + } + } + + public string GetDDRVersion() + { + try + { + HashSet ddrVersions = new HashSet(); + + ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT SMBIOSMemoryType FROM Win32_PhysicalMemory"); + foreach (ManagementObject queryObj in searcher.Get()) + { + ushort smbiosMemoryType = Convert.ToUInt16(queryObj["SMBIOSMemoryType"]); + string ddrVersion = GetDDRVersionFromSMBIOSMemoryType(smbiosMemoryType); + if (!string.IsNullOrEmpty(ddrVersion)) + { + ddrVersions.Add(ddrVersion); + } + } + + if (ddrVersions.Count > 0) + { + // Return the unique DDR versions, joined by a slash if multiple + return string.Join("'", ddrVersions); + } + } + catch (Exception ex) + { + Logging.WriteException(ex, MSGBox: false); + } + + // Return null if DDR version cannot be determined + return null; + } + + private string GetDDRVersionFromSMBIOSMemoryType(ushort smbiosMemoryType) + { + // Map the SMBIOSMemoryType to DDR version numbers 0-5 + switch (smbiosMemoryType) + { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + return "ᴰᴰᴿ"; + case 20: + return "ᴰᴰᴿ¹"; + case 21: + return "ᴰᴰᴿ²"; + case 24: + return "ᴰᴰᴿ³"; + case 26: + return "ᴰᴰᴿ⁴"; + case 34: + return "ᴰᴰᴿ⁵"; + // Include other cases as needed + default: + return null; + } } public IReadOnlyList GetAllStats() @@ -346,6 +422,21 @@ public void SetShowGPUTemperature(bool state) } } + public bool GetShowRamDDRVersion() + { + var item = _componentStats.FirstOrDefault(stat => stat.ComponentType == StatsComponentType.RAM); + return item?.ShowDDRVersion ?? false; + } + + public void SetShowRamDDRVersion(bool state) + { + var item = _componentStats.FirstOrDefault(stat => stat.ComponentType == StatsComponentType.RAM); + if (item != null) + { + item.ShowDDRVersion = state; + } + } + public bool GetShowGPUHotspotTemperature() { var item = _componentStats.FirstOrDefault(stat => stat.ComponentType == StatsComponentType.GPU); @@ -499,7 +590,6 @@ public void SetStatMaxValueShown(StatsComponentType type, bool state) StatsComponentType.GPU, StatsComponentType.VRAM, StatsComponentType.RAM, - //StatsComponentType.FPS }; public string GenerateStatsDescription() @@ -551,6 +641,11 @@ public string GenerateStatsDescription() } } + if (stat.ComponentType == StatsComponentType.RAM && stat.ShowDDRVersion && !string.IsNullOrWhiteSpace(stat.DDRVersion)) + { + componentDescription += $" ⁽{stat.DDRVersion}⁾"; + } + // Combine the additionalInfo parts with a single space string additionalInfo = string.Join(" ", additionalInfoParts).Trim(); @@ -1100,6 +1195,8 @@ private static string FetchStat( } } + + private static string FetchHotspotTemperatureStat(IHardware hardware, ComponentStatsItem item) { foreach (var sensor in hardware.Sensors) diff --git a/vrcosc-magicchatbox/Classes/Modules/NetworkStatisticsModule.cs b/vrcosc-magicchatbox/Classes/Modules/NetworkStatisticsModule.cs index 7750c27c..0749f2d5 100644 --- a/vrcosc-magicchatbox/Classes/Modules/NetworkStatisticsModule.cs +++ b/vrcosc-magicchatbox/Classes/Modules/NetworkStatisticsModule.cs @@ -1,11 +1,13 @@ using System; using System.Collections.Generic; using System.ComponentModel; -using System.Diagnostics; +using System.Linq; using System.Net.NetworkInformation; using System.Runtime.CompilerServices; +using System.Threading; using System.Threading.Tasks; -using System.Timers; +using System.Windows; +using System.Windows.Threading; using vrcosc_magicchatbox.Classes.DataAndSecurity; using vrcosc_magicchatbox.DataAndSecurity; using vrcosc_magicchatbox.ViewModels; @@ -15,8 +17,31 @@ namespace vrcosc_magicchatbox.Classes.Modules public class NetworkStatisticsModule : INotifyPropertyChanged, IDisposable { private Timer _updateTimer; + private NetworkInterface _activeNetworkInterface; + private bool _isMonitoring; + private long _previousBytesReceived; + private long _previousBytesSent; + private readonly Dispatcher _dispatcher; + private readonly object _initLock = new object(); + private bool _isInitializing; + public bool IsInitialized { get; private set; } - public double interval { get; set; } = 1000; + private double _interval = 1000; + public double Interval + { + get => _interval; + set + { + if (value <= 0) + throw new ArgumentOutOfRangeException(nameof(Interval), "Interval must be greater than zero."); + _interval = value; + if (_isMonitoring) + { + _updateTimer.Change(TimeSpan.Zero, TimeSpan.FromMilliseconds(_interval)); + } + } + } + private double _currentDownloadSpeedMbps; private double _currentUploadSpeedMbps; private double _maxDownloadSpeedMbps; @@ -24,42 +49,47 @@ public class NetworkStatisticsModule : INotifyPropertyChanged, IDisposable private double _networkUtilization; private double _totalDownloadedMB; private double _totalUploadedMB; - public int ErrorCount = 0; + public event PropertyChangedEventHandler PropertyChanged; + + // New property to control max speed source + public bool UseInterfaceMaxSpeed { get; set; } = false; + + // CancellationTokenSource for asynchronous initialization + private CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); + + public NetworkStatisticsModule(double interval = 1000) + { + Interval = interval; + _dispatcher = Application.Current.Dispatcher; + ViewModel.Instance.PropertyChanged += PropertyChangedHandler; + + InitializeNetworkStatsAsync().ConfigureAwait(false); + } - public void PropertyChangedHandler(object sender, PropertyChangedEventArgs e) + private void PropertyChangedHandler(object sender, PropertyChangedEventArgs e) { if (IsRelevantPropertyChange(e.PropertyName)) { if (ShouldStartMonitoring()) { - if (!IsInitialized) - { - InitializeNetworkStatsAsync(); - IsInitialized = true; - } - StartModule(); + InitializeNetworkStatsAsync().ConfigureAwait(false); } else { - if (!IsInitialized) - { - InitializeNetworkStatsAsync(); - IsInitialized = true; - } StopModule(); } } } - - public bool ShouldStartMonitoring() + private bool ShouldStartMonitoring() { - return ViewModel.Instance.IntgrNetworkStatistics && ViewModel.Instance.IsVRRunning && ViewModel.Instance.IntgrNetworkStatistics_VR || - ViewModel.Instance.IntgrNetworkStatistics && !ViewModel.Instance.IsVRRunning && ViewModel.Instance.IntgrNetworkStatistics_DESKTOP; + return ViewModel.Instance.IntgrNetworkStatistics && + ((ViewModel.Instance.IsVRRunning && ViewModel.Instance.IntgrNetworkStatistics_VR) || + (!ViewModel.Instance.IsVRRunning && ViewModel.Instance.IntgrNetworkStatistics_DESKTOP)); } - public bool IsRelevantPropertyChange(string propertyName) + private bool IsRelevantPropertyChange(string propertyName) { return propertyName == nameof(ViewModel.Instance.IntgrNetworkStatistics) || propertyName == nameof(ViewModel.Instance.IsVRRunning) || @@ -67,267 +97,281 @@ public bool IsRelevantPropertyChange(string propertyName) propertyName == nameof(ViewModel.Instance.IntgrNetworkStatistics_DESKTOP); } - private PerformanceCounter downloadCounter; - private PerformanceCounter uploadCounter; - private DateTime previousUpdateTime; - - public double TotalDownloadedMB - { - get { return _totalDownloadedMB; } - set { SetProperty(ref _totalDownloadedMB, value); } - } - - public double TotalUploadedMB - { - get { return _totalUploadedMB; } - set { SetProperty(ref _totalUploadedMB, value); } - } - - public double CurrentDownloadSpeedMbps + /// + /// Asynchronously initializes network statistics. + /// Ensures that initialization is thread-safe and does not block the UI thread. + /// + private async Task InitializeNetworkStatsAsync() { - get { return _currentDownloadSpeedMbps; } - set { SetProperty(ref _currentDownloadSpeedMbps, value); } - } + if (_isInitializing) + return; - public double CurrentUploadSpeedMbps - { - get { return _currentUploadSpeedMbps; } - set { SetProperty(ref _currentUploadSpeedMbps, value); } - } + lock (_initLock) + { + if (_isInitializing) + return; + _isInitializing = true; + } - public double MaxDownloadSpeedMbps - { - get { return _maxDownloadSpeedMbps; } - set { SetProperty(ref _maxDownloadSpeedMbps, value); } - } + try + { + var networkInterface = await Task.Run(() => GetActiveNetworkInterfaceAsync(_cancellationTokenSource.Token)); + if (networkInterface != null) + { + _activeNetworkInterface = networkInterface; - public double MaxUploadSpeedMbps - { - get { return _maxUploadSpeedMbps; } - set { SetProperty(ref _maxUploadSpeedMbps, value); } - } + if (UseInterfaceMaxSpeed) + { + var speedInMbps = _activeNetworkInterface.Speed / 1e6; + MaxDownloadSpeedMbps = speedInMbps; + MaxUploadSpeedMbps = speedInMbps; + } + else + { + MaxDownloadSpeedMbps = 0; + MaxUploadSpeedMbps = 0; + } - public double NetworkUtilization - { - get { return _networkUtilization; } - set { SetProperty(ref _networkUtilization, value); } - } + var stats = GetTotalBytes(_activeNetworkInterface); + _previousBytesReceived = stats.BytesReceived; + _previousBytesSent = stats.BytesSent; - public event PropertyChangedEventHandler PropertyChanged; + IsInitialized = true; - public NetworkStatisticsModule(double interval) - { - this.interval = interval; - ViewModel.Instance.PropertyChanged += PropertyChangedHandler; - if (ShouldStartMonitoring()) - { - if(!IsInitialized) + if (!_isMonitoring) + { + StartModule(); + } + } + else { - InitializeNetworkStatsAsync(); - IsInitialized = true; + // Handle the case when no active network interface is found + Logging.WriteException(new Exception("No active network interface found"), MSGBox: false); + IsInitialized = false; } - StartModule(); } - - } - - public void StartModule() - { - if (_updateTimer != null && !_updateTimer.Enabled) + catch (OperationCanceledException) { - _updateTimer.Start(); + // Initialization was canceled; do nothing. + } + catch (Exception ex) + { + Logging.WriteException(ex, MSGBox: false); + IsInitialized = false; + } + finally + { + lock (_initLock) + { + _isInitializing = false; + } } } - public void StopModule() + /// + /// Asynchronously determines the active network interface. + /// Includes both IPv4 and IPv6 statistics. + /// + /// Cancellation token. + /// The selected active NetworkInterface or null if none found. + private NetworkInterface GetActiveNetworkInterfaceAsync(CancellationToken cancellationToken) { - if (_updateTimer != null && _updateTimer.Enabled) + var networkInterfaces = NetworkInterface.GetAllNetworkInterfaces() + .Where(ni => + ni.OperationalStatus == OperationalStatus.Up && + ni.NetworkInterfaceType != NetworkInterfaceType.Loopback && + ni.NetworkInterfaceType != NetworkInterfaceType.Tunnel && + ni.GetIPProperties().UnicastAddresses.Any()).ToList(); + + if (networkInterfaces.Count == 0) + return null; + + // If there's only one active network interface, return it directly + if (networkInterfaces.Count == 1) { - _updateTimer.Stop(); + return networkInterfaces.First(); } - } - public void ForceUpdate() - { - OnTimedEvent(null, null); - } + // Prioritize network interfaces based on type (e.g., Ethernet over Wireless) + var prioritizedInterfaces = networkInterfaces.OrderByDescending(ni => GetInterfacePriority(ni)).ToList(); - private async Task InitializeNetworkStatsAsync() - { - // Attempt to initialize performance counters with an active network interface - await Task.Run(() => + // Measure initial bytes sent/received for all interfaces + var interfaceStats = prioritizedInterfaces.Select(ni => new InterfaceStats { - if (!InitializePerformanceCounters()) + NetworkInterface = ni, + InitialBytesReceived = GetTotalBytes(ni).BytesReceived, + InitialBytesSent = GetTotalBytes(ni).BytesSent + }).ToList(); + + // Wait for a short interval asynchronously + Task.Delay(500, cancellationToken).Wait(cancellationToken); + + // Measure bytes sent/received after the interval + foreach (var stat in interfaceStats) { - // If initialization fails, subscribe to the NetworkAddressChanged event to retry when the network status changes - NetworkChange.NetworkAddressChanged += OnNetworkAddressChanged; + var currentStats = GetTotalBytes(stat.NetworkInterface); + stat.BytesReceivedDiff = currentStats.BytesReceived - stat.InitialBytesReceived; + stat.BytesSentDiff = currentStats.BytesSent - stat.InitialBytesSent; + stat.TotalBytesDiff = stat.BytesReceivedDiff + stat.BytesSentDiff; } - }); - // Initialize and start the update timer - _updateTimer = new Timer(interval) + // Select the network interface with the highest total bytes difference + var mostActiveInterface = interfaceStats + .OrderByDescending(s => s.TotalBytesDiff) + .FirstOrDefault(s => s.TotalBytesDiff > 0); + + return mostActiveInterface?.NetworkInterface ?? prioritizedInterfaces.FirstOrDefault(); + } + + /// + /// Assigns a priority to network interfaces based on their type. + /// Higher priority for Ethernet, then Wireless, then others. + /// + /// NetworkInterface. + /// Integer priority. + private int GetInterfacePriority(NetworkInterface ni) + { + return ni.NetworkInterfaceType switch { - AutoReset = true, - Enabled = false + NetworkInterfaceType.Ethernet => 3, + NetworkInterfaceType.Wireless80211 => 2, + _ => 1, }; - _updateTimer.Elapsed += OnTimedEvent; - - previousUpdateTime = DateTime.Now; } - private bool InitializePerformanceCounters() + /// + /// Retrieves total bytes sent and received, including both IPv4 and IPv6. + /// + /// NetworkInterface. + /// TotalBytes struct containing BytesReceived and BytesSent. + private TotalBytes GetTotalBytes(NetworkInterface ni) { - try + var ipv4Stats = ni.GetIPv4Statistics(); + var ipv6Stats = ni.GetIPStatistics(); + return new TotalBytes { - // Dispose of existing counters - downloadCounter?.Dispose(); - uploadCounter?.Dispose(); + BytesReceived = ipv4Stats.BytesReceived + ipv6Stats.BytesReceived, + BytesSent = ipv4Stats.BytesSent + ipv6Stats.BytesSent + }; + } - // Attempt to select an active network interface - NetworkInterface activeNetworkInterface = GetActiveNetworkInterface(); + private struct TotalBytes + { + public long BytesReceived; + public long BytesSent; + } - if (activeNetworkInterface != null) - { - // Get the correct instance name for the PerformanceCounter - string instanceName = GetInstanceNameForPerformanceCounter(activeNetworkInterface); - if (instanceName == null) - { - // Handle the case where no matching instance name is found - // For example, log this issue and use a default instance name or skip setting up counters - return false; - } + private class InterfaceStats + { + public NetworkInterface NetworkInterface { get; set; } + public long InitialBytesReceived { get; set; } + public long InitialBytesSent { get; set; } + public long BytesReceivedDiff { get; set; } + public long BytesSentDiff { get; set; } + public long TotalBytesDiff { get; set; } + } - // Initialize Performance Counters for the selected network interface - downloadCounter = new PerformanceCounter("Network Interface", "Bytes Received/sec", instanceName); - uploadCounter = new PerformanceCounter("Network Interface", "Bytes Sent/sec", instanceName); + public void StartModule() + { + if (_isMonitoring || !IsInitialized) + return; - // Update maximum speeds based on the active network interface - MaxDownloadSpeedMbps = activeNetworkInterface.Speed / 8e6; // Convert from bits to Megabytes - MaxUploadSpeedMbps = activeNetworkInterface.Speed / 8e6; // Convert from bits to Megabytes + _updateTimer = new Timer(OnTimedEvent, null, TimeSpan.Zero, TimeSpan.FromMilliseconds(Interval)); + _isMonitoring = true; + } - return true; // Initialization succeeded - } + public void StopModule() + { + if (!_isMonitoring) + return; - return false; // No active network interface was found - } - catch (Exception ex) - { - Logging.WriteException(ex, MSGBox: false); - ErrorCount++; - return false; - } - + _updateTimer?.Change(Timeout.Infinite, Timeout.Infinite); + _updateTimer?.Dispose(); + _updateTimer = null; + _isMonitoring = false; } - private string GetInstanceNameForPerformanceCounter(NetworkInterface networkInterface) + private void OnTimedEvent(object state) { try { - var category = new PerformanceCounterCategory("Network Interface"); - string[] instanceNames = category.GetInstanceNames(); - string normalizedInterfaceName = NormalizeInterfaceName(networkInterface.Description); + if (_activeNetworkInterface == null) + { + // Attempt to re-initialize if the active interface is null + InitializeNetworkStatsAsync().ConfigureAwait(false); + if (_activeNetworkInterface == null) + return; + } - foreach (string instanceName in instanceNames) + // Update UseInterfaceMaxSpeed based on ViewModel + if (UseInterfaceMaxSpeed != ViewModel.Instance.NetworkStats_UseInterfaceMaxSpeed) { - if (instanceName.Equals(normalizedInterfaceName, StringComparison.OrdinalIgnoreCase)) - { - return instanceName; - } + UseInterfaceMaxSpeed = ViewModel.Instance.NetworkStats_UseInterfaceMaxSpeed; + MaxDownloadSpeedMbps = 0; + MaxUploadSpeedMbps = 0; } - return null; - } - catch (InvalidOperationException ex) - { - // Log the exception for debugging purposes - Logging.WriteException(ex, MSGBox: false); - ErrorCount++; - // Notify user or take steps to repair or provide alternative - HandlePerformanceCounterError(); + var stats = GetTotalBytes(_activeNetworkInterface); - return null; - } - catch (Exception ex) - { - Logging.WriteException(ex, MSGBox: false); - ErrorCount++; - return null; - } - } + // Calculate the differences since the last check + var bytesReceivedDiff = stats.BytesReceived - _previousBytesReceived; + var bytesSentDiff = stats.BytesSent - _previousBytesSent; - private void HandlePerformanceCounterError() - { - Logging.WriteException(new Exception("Performance counter error"), MSGBox: false); - } + // Update previous values + _previousBytesReceived = stats.BytesReceived; + _previousBytesSent = stats.BytesSent; + // Calculate speeds in Mbps + var intervalInSeconds = Interval / 1000; + var downloadSpeed = (bytesReceivedDiff * 8) / 1e6 / intervalInSeconds; + var uploadSpeed = (bytesSentDiff * 8) / 1e6 / intervalInSeconds; - private string NormalizeInterfaceName(string interfaceName) - { - // Replace invalid characters based on the mappings provided by Microsoft documentation - return interfaceName - .Replace('(', '[') - .Replace(')', ']') - .Replace('#', '_') - .Replace('\\', '_') - .Replace('/', '_'); - // Add any other normalization rules if needed - } + // Update total downloaded and uploaded data in MB + var totalDownloaded = TotalDownloadedMB + (bytesReceivedDiff / 1e6); + var totalUploaded = TotalUploadedMB + (bytesSentDiff / 1e6); + // Update maximum observed speeds if not using interface max speed + if (!UseInterfaceMaxSpeed) + { + if (downloadSpeed > MaxDownloadSpeedMbps) + MaxDownloadSpeedMbps = downloadSpeed; - private NetworkInterface GetActiveNetworkInterface() - { - try - { - // Retrieve all network interfaces - NetworkInterface[] networkInterfaces = NetworkInterface.GetAllNetworkInterfaces(); + if (uploadSpeed > MaxUploadSpeedMbps) + MaxUploadSpeedMbps = uploadSpeed; + } + + // Determine the max speed to use for utilization calculation + var maxDownloadSpeed = UseInterfaceMaxSpeed + ? _activeNetworkInterface.Speed / 1e6 + : MaxDownloadSpeedMbps; + + var maxUploadSpeed = UseInterfaceMaxSpeed + ? _activeNetworkInterface.Speed / 1e6 + : MaxUploadSpeedMbps; + + // Update network utilization + var utilization = maxDownloadSpeed > 0 + ? Math.Min(100, (downloadSpeed / maxDownloadSpeed) * 100) + : 0; - // Select the first active network interface that is up and has an IPv4 address and is not a loopback or tunnel - foreach (var ni in networkInterfaces) + // Update properties on the UI thread + _dispatcher.BeginInvoke(new Action(() => { - if (ni.OperationalStatus == OperationalStatus.Up && - // more that 0 less that 10000 (10Gbps) - ni.Speed > 0 && ni.Speed < 10000000000 && - ni.NetworkInterfaceType != NetworkInterfaceType.Loopback && - ni.NetworkInterfaceType != NetworkInterfaceType.Tunnel && - ni.GetIPProperties().UnicastAddresses.Count > 0) // Check for an IPv4 address - { - return ni; - } - } - return null; // No active network interface found + CurrentDownloadSpeedMbps = downloadSpeed; + CurrentUploadSpeedMbps = uploadSpeed; + TotalDownloadedMB = totalDownloaded; + TotalUploadedMB = totalUploaded; + NetworkUtilization = utilization; + MaxDownloadSpeedMbps = maxDownloadSpeed; + MaxUploadSpeedMbps = maxUploadSpeed; + })); } catch (Exception ex) { - ErrorCount++; Logging.WriteException(ex, MSGBox: false); - return null; } - } - - private void ResetCurrentStatistics() - { - // Reset current network statistics - CurrentDownloadSpeedMbps = 0; - CurrentUploadSpeedMbps = 0; - NetworkUtilization = 0; - } - - private void OnNetworkAddressChanged(object sender, EventArgs e) - { - // When the network address changes, try to re-initialize the performance counters - if (InitializePerformanceCounters()) - { - // If the re-initialization is successful, reset the current statistics - ResetCurrentStatistics(); - } - else - { - // Log or handle the error if no active network interface is found after a network change - // This is application-specific and you should decide how to handle this case - } - } public string GenerateDescription() { const int maxLineWidth = 25; @@ -348,33 +392,29 @@ public string GenerateDescription() networkStatsDescriptions.Add($"{ConvertToSuperScriptIfNeeded("Max Down: ")} {FormatSpeed(MaxDownloadSpeedMbps)}"); if (ViewModel.Instance.NetworkStats_ShowMaxUp) - networkStatsDescriptions.Add($"{ConvertToSuperScriptIfNeeded("Max Up: ")}{FormatSpeed(MaxUploadSpeedMbps)}"); + networkStatsDescriptions.Add($"{ConvertToSuperScriptIfNeeded("Max Up: ")} {FormatSpeed(MaxUploadSpeedMbps)}"); if (ViewModel.Instance.NetworkStats_ShowTotalDown) - networkStatsDescriptions.Add($"{ConvertToSuperScriptIfNeeded("Total Down: ")}{FormatData(TotalDownloadedMB)}"); + networkStatsDescriptions.Add($"{ConvertToSuperScriptIfNeeded("Total Down: ")} {FormatData(TotalDownloadedMB)}"); if (ViewModel.Instance.NetworkStats_ShowTotalUp) - networkStatsDescriptions.Add($"{ConvertToSuperScriptIfNeeded("Total Up: ")}{FormatData(TotalUploadedMB)}"); + networkStatsDescriptions.Add($"{ConvertToSuperScriptIfNeeded("Total Up: ")} {FormatData(TotalUploadedMB)}"); if (ViewModel.Instance.NetworkStats_ShowNetworkUtilization) - networkStatsDescriptions.Add($"{ConvertToSuperScriptIfNeeded("Network utilization: ")}{NetworkUtilization:N2} %"); + networkStatsDescriptions.Add($"{ConvertToSuperScriptIfNeeded("Network Utilization: ")} {NetworkUtilization:N2} %"); - if(networkStatsDescriptions.Count == 0) + if (networkStatsDescriptions.Count == 0) { return ""; } foreach (var description in networkStatsDescriptions) { - // Skip any descriptions that are null or whitespace. if (string.IsNullOrWhiteSpace(description)) { continue; } - // If adding the next description would exceed the max line width, - // or if the description is the only item and should be displayed alone, - // add currentLine to lines and reset it. if (currentLine.Length + description.Length > maxLineWidth || (currentLine.Length == 0 && description.Length <= maxLineWidth)) { if (currentLine.Length > 0) @@ -383,8 +423,6 @@ public string GenerateDescription() currentLine = ""; } - // If the description is short enough and currentLine is empty, - // add it directly to lines instead of appending to currentLine. if (description.Length <= maxLineWidth) { lines.Add(description); @@ -392,30 +430,24 @@ public string GenerateDescription() } } - // If currentLine is not empty, append the separator before adding the new description. if (currentLine.Length > 0) { currentLine += separator; } - // Append the current description to currentLine. currentLine += description; } - // After processing all descriptions, if there's any content left in currentLine, - // add it to lines. if (currentLine.Length > 0) { lines.Add(currentLine.TrimEnd()); } return string.Join("\v", lines); - } private string FormatSpeed(double speedMbps) { - // Convert and format speed based on its magnitude if (speedMbps < 1) return $"{speedMbps * 1000:N2} {ConvertToSuperScriptIfNeeded("Kbps")}"; else if (speedMbps >= 1000) @@ -438,96 +470,89 @@ private string ConvertToSuperScriptIfNeeded(string unitstring) private string FormatData(double dataMB) { - // Convert and format data based on its magnitude if (dataMB < 1) return $"{dataMB * 1000:N2} {ConvertToSuperScriptIfNeeded("KB")}"; + else if (dataMB >= 1_000_000) + return $"{dataMB / 1e6:N2} {ConvertToSuperScriptIfNeeded("TB")}"; else if (dataMB >= 1000) - return dataMB >= 1000000 ? $"{dataMB / 1e6:N2} TB" : $"{dataMB / 1000:N2} {ConvertToSuperScriptIfNeeded("GB")}"; + return $"{dataMB / 1000:N2} {ConvertToSuperScriptIfNeeded("GB")}"; else return $"{dataMB:N2} {ConvertToSuperScriptIfNeeded("MB")}"; } - - private void OnTimedEvent(Object source, ElapsedEventArgs e) + // Implement property getters and setters with OnPropertyChanged notifications + public double CurrentDownloadSpeedMbps { - try - { - // Current time - DateTime currentTime = DateTime.Now; + get => _currentDownloadSpeedMbps; + set => SetProperty(ref _currentDownloadSpeedMbps, value); + } - // Calculate the number of seconds elapsed - double elapsedSeconds = (currentTime - previousUpdateTime).TotalSeconds; - previousUpdateTime = currentTime; + public double CurrentUploadSpeedMbps + { + get => _currentUploadSpeedMbps; + set => SetProperty(ref _currentUploadSpeedMbps, value); + } - // Fetch current network usage once - double currentDownloadBytes = downloadCounter.NextValue(); - double currentUploadBytes = uploadCounter.NextValue(); + public double MaxDownloadSpeedMbps + { + get => _maxDownloadSpeedMbps; + set => SetProperty(ref _maxDownloadSpeedMbps, value); + } - // Calculate speeds in Mbps - CurrentDownloadSpeedMbps = currentDownloadBytes / 1e6 * 8; - CurrentUploadSpeedMbps = currentUploadBytes / 1e6 * 8; + public double MaxUploadSpeedMbps + { + get => _maxUploadSpeedMbps; + set => SetProperty(ref _maxUploadSpeedMbps, value); + } - // Update total downloaded and uploaded data in MB - TotalDownloadedMB += currentDownloadBytes / 1e6 * elapsedSeconds; - TotalUploadedMB += currentUploadBytes / 1e6 * elapsedSeconds; + public double NetworkUtilization + { + get => _networkUtilization; + set => SetProperty(ref _networkUtilization, value); + } - // Update network utilization - NetworkUtilization = Math.Min(100, (CurrentDownloadSpeedMbps / MaxDownloadSpeedMbps) * 100); - } - catch (Exception ex) - { - Logging.WriteException(ex, MSGBox: false); - ErrorCount++; - if(ErrorCount > 3) - { - ViewModel.Instance.IntgrNetworkStatistics = false; - ErrorCount = 0; - } - } + public double TotalDownloadedMB + { + get => _totalDownloadedMB; + set => SetProperty(ref _totalDownloadedMB, value); } - protected void OnPropertyChanged(string propertyName) + public double TotalUploadedMB { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + get => _totalUploadedMB; + set => SetProperty(ref _totalUploadedMB, value); } protected bool SetProperty(ref T storage, T value, [CallerMemberName] string propertyName = null) { - try - { - if (EqualityComparer.Default.Equals(storage, value)) - { - return false; - } - storage = value; - OnPropertyChanged(propertyName); - return true; - } - catch (Exception ex) - { - // Log the exception - Logging.WriteException(ex); + if (EqualityComparer.Default.Equals(storage, value)) return false; - } + storage = value; + OnPropertyChanged(propertyName); + return true; } - - public void Dispose() + protected void OnPropertyChanged([CallerMemberName] string propertyName = null) { - try + if (!_dispatcher.CheckAccess()) { - _updateTimer?.Stop(); - _updateTimer?.Dispose(); - downloadCounter?.Dispose(); - uploadCounter?.Dispose(); - NetworkChange.NetworkAddressChanged -= OnNetworkAddressChanged; + _dispatcher.BeginInvoke(() => + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + }); } - catch (Exception ex) + else { - // Log the exception - Logging.WriteException(ex); + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } + public void Dispose() + { + StopModule(); + _cancellationTokenSource.Cancel(); + _cancellationTokenSource.Dispose(); + ViewModel.Instance.PropertyChanged -= PropertyChangedHandler; + } } } diff --git a/vrcosc-magicchatbox/MagicChatbox.csproj b/vrcosc-magicchatbox/MagicChatbox.csproj index 51d64970..3925950d 100644 --- a/vrcosc-magicchatbox/MagicChatbox.csproj +++ b/vrcosc-magicchatbox/MagicChatbox.csproj @@ -2,7 +2,7 @@ WinExe - 0.9.052 + 0.9.060 net8.0-windows10.0.22000.0 vrcosc_magicchatbox enable @@ -190,15 +190,16 @@ - + - + + diff --git a/vrcosc-magicchatbox/MainWindow.xaml b/vrcosc-magicchatbox/MainWindow.xaml index 5b24b8b1..facca2b8 100644 --- a/vrcosc-magicchatbox/MainWindow.xaml +++ b/vrcosc-magicchatbox/MainWindow.xaml @@ -3257,6 +3257,28 @@ + + + + + Hide OpenAI toolbar in chatting tab + + + + + @@ -3834,6 +3856,19 @@ IsChecked="{Binding RAM_ShowMaxValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Style="{DynamicResource SettingsCheckbox}" ToolTip="When checked, the VRAM usage label will display the model name of ur GPU." /> + - + + + Use network interface as the max speed + + - + @@ -6984,11 +7038,12 @@ Color="#FF7F759A" /> + RenderOptions.BitmapScalingMode="NearestNeighbor" + Visibility="{Binding HideOpenAITools, Converter={StaticResource InverseBoolToVisibilityConverter}}">