diff --git a/BeatSaberHTTPStatus/BeatSaberHTTPStatusPlugin.csproj b/BeatSaberHTTPStatus/BeatSaberHTTPStatusPlugin.csproj
index 43fcfb0..ca3e041 100644
--- a/BeatSaberHTTPStatus/BeatSaberHTTPStatusPlugin.csproj
+++ b/BeatSaberHTTPStatus/BeatSaberHTTPStatusPlugin.csproj
@@ -66,6 +66,10 @@
$(GameDirPath)\Beat Saber_Data\Managed\BGNet.dll
False
+
+ $(GameDirPath)\Beat Saber_Data\Managed\Colors.dll
+ False
+
diff --git a/BeatSaberHTTPStatus/GameStatus.cs b/BeatSaberHTTPStatus/GameStatus.cs
index 965138a..0a5be57 100644
--- a/BeatSaberHTTPStatus/GameStatus.cs
+++ b/BeatSaberHTTPStatus/GameStatus.cs
@@ -1,4 +1,5 @@
using System;
+using UnityEngine;
namespace BeatSaberHTTPStatus {
[Serializable]
@@ -32,6 +33,13 @@ public class GameStatus {
public int maxScore = 0;
public string maxRank = "E";
public string environmentName = null;
+ public Color? colorSaberA = null;
+ public Color? colorSaberB = null;
+ public Color? colorEnvironment0 = null;
+ public Color? colorEnvironment1 = null;
+ public Color? colorEnvironmentBoost0 = null;
+ public Color? colorEnvironmentBoost1 = null;
+ public Color? colorObstacle = null;
// Performance
public int rawScore = 0;
@@ -140,6 +148,13 @@ public void ResetMapInfo() {
this.maxScore = 0;
this.maxRank = "E";
this.environmentName = null;
+ this.colorSaberA = null;
+ this.colorSaberB = null;
+ this.colorEnvironment0 = null;
+ this.colorEnvironment1 = null;
+ this.colorEnvironmentBoost0 = null;
+ this.colorEnvironmentBoost1 = null;
+ this.colorObstacle = null;
}
public void ResetPerformance() {
diff --git a/BeatSaberHTTPStatus/Plugin.cs b/BeatSaberHTTPStatus/Plugin.cs
index 50cf610..27d544f 100644
--- a/BeatSaberHTTPStatus/Plugin.cs
+++ b/BeatSaberHTTPStatus/Plugin.cs
@@ -364,6 +364,17 @@ public async void HandleSongStart() {
gameStatus.obstaclesCount = diff.beatmapData.obstaclesCount;
gameStatus.environmentName = level.environmentInfo.sceneInfo.sceneName;
+ ColorScheme colorScheme = gameplayCoreSceneSetupData.colorScheme ?? new ColorScheme(gameplayCoreSceneSetupData.environmentInfo.colorScheme);
+ gameStatus.colorSaberA = colorScheme.saberAColor;
+ gameStatus.colorSaberB = colorScheme.saberBColor;
+ gameStatus.colorEnvironment0 = colorScheme.environmentColor0;
+ gameStatus.colorEnvironment1 = colorScheme.environmentColor1;
+ if (colorScheme.supportsEnvironmentColorBoost) {
+ gameStatus.colorEnvironmentBoost0 = colorScheme.environmentColor0Boost;
+ gameStatus.colorEnvironmentBoost1 = colorScheme.environmentColor1Boost;
+ }
+ gameStatus.colorObstacle = colorScheme.obstaclesColor;
+
try {
// From https://support.unity3d.com/hc/en-us/articles/206486626-How-can-I-get-pixels-from-unreadable-textures-
var texture = (await level.GetCoverImageAsync(CancellationToken.None)).texture;
diff --git a/BeatSaberHTTPStatus/StatusManager.cs b/BeatSaberHTTPStatus/StatusManager.cs
index 1191318..0d018f4 100644
--- a/BeatSaberHTTPStatus/StatusManager.cs
+++ b/BeatSaberHTTPStatus/StatusManager.cs
@@ -98,6 +98,32 @@ private void UpdateBeatmapJSON() {
beatmapJSON["maxScore"] = gameStatus.maxScore;
beatmapJSON["maxRank"] = gameStatus.maxRank;
beatmapJSON["environmentName"] = gameStatus.environmentName;
+
+ if (beatmapJSON["color"] == null) beatmapJSON["color"] = new JSONObject();
+ JSONObject colorJSON = (JSONObject) beatmapJSON["color"];
+
+ UpdateColor(gameStatus.colorSaberA, colorJSON, "saberA");
+ UpdateColor(gameStatus.colorSaberB, colorJSON, "saberB");
+ UpdateColor(gameStatus.colorEnvironment0, colorJSON, "environment0");
+ UpdateColor(gameStatus.colorEnvironment1, colorJSON, "environment1");
+ UpdateColor(gameStatus.colorEnvironmentBoost0, colorJSON, "environment0Boost");
+ UpdateColor(gameStatus.colorEnvironmentBoost1, colorJSON, "environment1Boost");
+ UpdateColor(gameStatus.colorObstacle, colorJSON, "obstacle");
+ }
+
+ private void UpdateColor(Color? color, JSONObject parent, String key) {
+ if (color == null) {
+ parent[key] = JSONNull.CreateOrGet();
+ return;
+ }
+
+ var arr = parent[key] as JSONArray ?? new JSONArray();
+
+ arr[0] = Mathf.RoundToInt(((Color) color).r * 255);
+ arr[1] = Mathf.RoundToInt(((Color) color).g * 255);
+ arr[2] = Mathf.RoundToInt(((Color) color).b * 255);
+
+ parent[key] = arr;
}
private void UpdatePerformanceJSON() {
diff --git a/protocol.md b/protocol.md
index a6ac45c..cfce6ab 100644
--- a/protocol.md
+++ b/protocol.md
@@ -59,6 +59,15 @@ StatusObject = {
"maxScore": Integer, // Max score obtainable on the map with modifier multiplier
"maxRank": "SSS" | "SS" | "S" | "A" | "B" | "C" | "D" | "E", // Max rank obtainable using current modifiers
"environmentName": String, // Name of the environment this beatmap requested // TODO: list available names
+ "color": { // Contains colors used by this environment. If overrides were set by the player, they replace the values provided by the environment. SongCore may override the colors based on beatmap settings, including player overrides. Each color is stored as an array of three integers in the range [0..255] representing the red, green, and blue values in order.
+ "saberA": [Integer, Integer, Integer], // Color of the left saber and its notes
+ "saberB": [Integer, Integer, Integer], // Color of the right saber and its notes
+ "environment0": [Integer, Integer, Integer], // First environment color
+ "environment1": [Integer, Integer, Integer], // Second environment color
+ "environment0Boost": null | [Integer, Integer, Integer], // First environment boost color. If a boost color isn't set, this property will be `null`, and the value of `environment0` should be used instead.
+ "environment1Boost": null | [Integer, Integer, Integer], // Second environment boost color. If a boost color isn't set, this property will be `null`, and the value of `environment1` should be used instead.
+ "obstacle": [Integer, Integer, Integer], // Color of obstacles
+ },
},
"performance": null | {
"rawScore": Integer, // Current score without the modifier multiplier