diff --git a/VRCOSC.Desktop/VRCOSC.Desktop.csproj b/VRCOSC.Desktop/VRCOSC.Desktop.csproj
index b126d80d..172b7c78 100644
--- a/VRCOSC.Desktop/VRCOSC.Desktop.csproj
+++ b/VRCOSC.Desktop/VRCOSC.Desktop.csproj
@@ -6,12 +6,12 @@
     <ApplicationIcon>game.ico</ApplicationIcon>
     <ApplicationManifest>app.manifest</ApplicationManifest>
     <Version>0.0.0</Version>
-    <FileVersion>2023.1220.0</FileVersion>
+    <FileVersion>2024.102.0</FileVersion>
     <Title>VRCOSC</Title>
     <Authors>VolcanicArts</Authors>
     <Company>VolcanicArts</Company>
     <Nullable>enable</Nullable>
-    <AssemblyVersion>2023.1220.0</AssemblyVersion>
+    <AssemblyVersion>2024.102.0</AssemblyVersion>
   </PropertyGroup>
   <ItemGroup Label="Project References">
     <ProjectReference Include="..\VRCOSC.Game\VRCOSC.Game.csproj" />
diff --git a/VRCOSC.Game/Modules/Bases/Heartrate/HeartrateModule.cs b/VRCOSC.Game/Modules/Bases/Heartrate/HeartrateModule.cs
index fe645fc7..910c207c 100644
--- a/VRCOSC.Game/Modules/Bases/Heartrate/HeartrateModule.cs
+++ b/VRCOSC.Game/Modules/Bases/Heartrate/HeartrateModule.cs
@@ -40,7 +40,8 @@ protected override void CreateAttributes()
 
         CreateVariable(HeartrateVariable.Heartrate, "Heartrate", "hr");
 
-        CreateState(HeartrateState.Default, "Default", $"Heartrate/v{GetVariableFormat(HeartrateVariable.Heartrate)} bpm");
+        CreateState(HeartrateState.Default, "Connected", $"Heartrate/v{GetVariableFormat(HeartrateVariable.Heartrate)} bpm");
+        CreateState(HeartrateState.Disconnected, "Disconnected", "Heartrate Disconnected");
     }
 
     protected override void OnModuleStart()
@@ -56,7 +57,7 @@ protected override void OnModuleStart()
         HeartrateProvider.OnLog += Log;
         HeartrateProvider.Initialise();
 
-        ChangeStateTo(HeartrateState.Default);
+        ChangeStateTo(HeartrateState.Disconnected);
     }
 
     private async void attemptReconnection()
@@ -111,6 +112,7 @@ private void updateCurrentHeartrate()
     private void updateParameters()
     {
         var isReceiving = HeartrateProvider?.IsReceiving ?? false;
+        ChangeStateTo(isReceiving ? HeartrateState.Default : HeartrateState.Disconnected);
 
         SendParameter(HeartrateParameter.Enabled, isReceiving);
 
@@ -166,7 +168,8 @@ private enum HeartrateParameter
 
     private enum HeartrateState
     {
-        Default
+        Default,
+        Disconnected
     }
 
     private enum HeartrateVariable
diff --git a/VRCOSC.Game/Providers/Hardware/Components.cs b/VRCOSC.Game/Providers/Hardware/Components.cs
index aec13f67..96db7828 100644
--- a/VRCOSC.Game/Providers/Hardware/Components.cs
+++ b/VRCOSC.Game/Providers/Hardware/Components.cs
@@ -3,7 +3,6 @@
 
 using System;
 using System.Collections.Generic;
-using System.Linq;
 using LibreHardwareMonitor.Hardware;
 
 namespace VRCOSC.Game.Providers.Hardware;
@@ -28,7 +27,7 @@ public abstract class HardwareComponent
 
     protected static bool GetIntValue(ISensor sensor, SensorInfo info, out int value)
     {
-        if (!GetFloatValue(sensor, info, out var floatValue))
+        if (GetFloatValue(sensor, info, out var floatValue))
         {
             value = (int)MathF.Round(floatValue);
             return true;
@@ -40,13 +39,17 @@ protected static bool GetIntValue(ISensor sensor, SensorInfo info, out int value
 
     protected static bool GetFloatValue(ISensor sensor, SensorInfo info, out float value)
     {
-        if (info.Pairs.Any(pair => sensor.SensorType == pair.Type && sensor.Name == pair.Name))
+        foreach (var pair in info.Pairs)
         {
-            value = sensor.Value ?? 0f;
+            var innerValue = sensor.Value.GetValueOrDefault(0f);
+
+            if (sensor.SensorType != pair.Type || sensor.Name != pair.Name || innerValue == 0f) continue;
+
+            value = innerValue;
             return true;
         }
 
-        value = 0;
+        value = 0f;
         return false;
     }
 
diff --git a/VRCOSC.Modules/HardwareStats/HardwareStatsModule.cs b/VRCOSC.Modules/HardwareStats/HardwareStatsModule.cs
index 025f3716..5ec04d5e 100644
--- a/VRCOSC.Modules/HardwareStats/HardwareStatsModule.cs
+++ b/VRCOSC.Modules/HardwareStats/HardwareStatsModule.cs
@@ -19,6 +19,7 @@ protected override void CreateAttributes()
     {
         CreateSetting(HardwareStatsSetting.SelectedCPU, "Selected CPU", "Enter the (0th based) index of the CPU you want to track", 0);
         CreateSetting(HardwareStatsSetting.SelectedGPU, "Selected GPU", "Enter the (0th based) index of the GPU you want to track", 0);
+        CreateSetting(HardwareStatsSetting.ChatBoxFormatting, "ChatBox Formatting", "How should numbers be formatted in the chatbox?", "0.0");
 
         CreateParameter<float>(HardwareStatsParameter.CpuUsage, ParameterMode.Write, "VRCOSC/Hardware/CPUUsage", "CPU Usage", "The CPU usage normalised");
         CreateParameter<int>(HardwareStatsParameter.CpuPower, ParameterMode.Write, "VRCOSC/Hardware/CPUPower", "CPU Power", "The power usage of your CPU in Watts");
@@ -110,20 +111,21 @@ private async void updateParameters()
         SendParameter(HardwareStatsParameter.VRamUsed, gpu.MemoryUsed / 1000f);
         SendParameter(HardwareStatsParameter.VRamTotal, gpu.MemoryTotal / 1000f);
 
-        SetVariableValue(HardwareStatsParameter.CpuUsage, cpu.Usage.ToString("0.00"));
+        var format = GetSetting<string>(HardwareStatsSetting.ChatBoxFormatting);
+        SetVariableValue(HardwareStatsParameter.CpuUsage, cpu.Usage.ToString(format));
         SetVariableValue(HardwareStatsParameter.CpuPower, cpu.Power.ToString());
         SetVariableValue(HardwareStatsParameter.CpuTemp, cpu.Temperature.ToString());
-        SetVariableValue(HardwareStatsParameter.GpuUsage, gpu.Usage.ToString("0.00"));
+        SetVariableValue(HardwareStatsParameter.GpuUsage, gpu.Usage.ToString(format));
         SetVariableValue(HardwareStatsParameter.GpuPower, gpu.Power.ToString());
         SetVariableValue(HardwareStatsParameter.GpuTemp, gpu.Temperature.ToString());
-        SetVariableValue(HardwareStatsParameter.RamUsage, ram.Usage.ToString("0.00"));
-        SetVariableValue(HardwareStatsParameter.RamTotal, ram.Total.ToString("0.0"));
-        SetVariableValue(HardwareStatsParameter.RamUsed, ram.Used.ToString("0.0"));
-        SetVariableValue(HardwareStatsParameter.RamAvailable, ram.Available.ToString("0.0"));
-        SetVariableValue(HardwareStatsParameter.VRamUsage, (gpu.MemoryUsage * 100f).ToString("0.0"));
-        SetVariableValue(HardwareStatsParameter.VRamFree, (gpu.MemoryFree / 1000f).ToString("0.0"));
-        SetVariableValue(HardwareStatsParameter.VRamUsed, (gpu.MemoryUsed / 1000f).ToString("0.0"));
-        SetVariableValue(HardwareStatsParameter.VRamTotal, (gpu.MemoryTotal / 1000f).ToString("0.0"));
+        SetVariableValue(HardwareStatsParameter.RamUsage, ram.Usage.ToString(format));
+        SetVariableValue(HardwareStatsParameter.RamTotal, ram.Total.ToString(format));
+        SetVariableValue(HardwareStatsParameter.RamUsed, ram.Used.ToString(format));
+        SetVariableValue(HardwareStatsParameter.RamAvailable, ram.Available.ToString(format));
+        SetVariableValue(HardwareStatsParameter.VRamUsage, (gpu.MemoryUsage * 100f).ToString(format));
+        SetVariableValue(HardwareStatsParameter.VRamFree, (gpu.MemoryFree / 1000f).ToString(format));
+        SetVariableValue(HardwareStatsParameter.VRamUsed, (gpu.MemoryUsed / 1000f).ToString(format));
+        SetVariableValue(HardwareStatsParameter.VRamTotal, (gpu.MemoryTotal / 1000f).ToString(format));
     }
 
     protected override void OnModuleStop()
@@ -134,7 +136,8 @@ protected override void OnModuleStop()
     private enum HardwareStatsSetting
     {
         SelectedCPU,
-        SelectedGPU
+        SelectedGPU,
+        ChatBoxFormatting
     }
 
     private enum HardwareStatsParameter