Переглянути джерело

make language configurable via settings.json

jeff87218 3 тижнів тому
батько
коміт
65d4abee2e

+ 1 - 0
Sunrise/resources/default_settings.json

@@ -14,6 +14,7 @@
     }
   },
   "steam": {
+    "language": "english",
     "user": {
       "persona_name": "Player"
     }

+ 6 - 0
Sunrise/src/core/settings/steam/definition.h

@@ -9,6 +9,10 @@ namespace sunrise::core::settings::steam {
 inline constexpr std::size_t kMaximumPersonaNameBytes = 63;
 /** Fixed persona storage includes one trailing null byte. */
 inline constexpr std::size_t kPersonaNameCapacity = kMaximumPersonaNameBytes + 1;
+/** Comfortably longer than any published Steam API language token (e.g. "vietnamese"). */
+inline constexpr std::size_t kMaximumLanguageBytes = 15;
+/** Fixed language storage includes one trailing null byte. */
+inline constexpr std::size_t kLanguageCapacity = kMaximumLanguageBytes + 1;
 
 /** Read-only settings for the single local Steam user. */
 struct User {
@@ -20,6 +24,8 @@ struct User {
 struct Settings {
     /** Options for the single local user exposed through Steam interfaces. */
     User user;
+    /** Steam API language token answered for GetCurrentGameLanguage/GetAvailableGameLanguages. */
+    std::array<char, kLanguageCapacity> language{"english"};
 };
 
 } // namespace sunrise::core::settings::steam

+ 36 - 0
Sunrise/src/core/settings/steam/steam_settings_parser.cpp

@@ -123,6 +123,35 @@ decode_escape(std::string_view encoded, std::size_t& position, char& output) noe
     return true;
 }
 
+/**
+ * Decodes a nonempty Steam API language token into process-owned fixed storage.
+ * @param encoded Borrowed encoded JSON string bytes.
+ * @param output Receives the decoded bytes and a trailing null only on success.
+ * @return True for 1 to 15 printable ASCII bytes.
+ */
+[[nodiscard]] bool decode_language(std::string_view encoded,
+                                   std::array<char, steam::kLanguageCapacity>& output) noexcept {
+    std::array<char, steam::kLanguageCapacity> candidate{};
+    std::size_t decodedCount = 0;
+    for (std::size_t position = 0; position < encoded.size();) {
+        char value = encoded[position++];
+        if (value == '\\' && !decode_escape(encoded, position, value)) {
+            return false;
+        }
+        const auto byte = static_cast<unsigned char>(value);
+        if (byte < kMinimumPrintableAscii || byte > kMaximumPrintableAscii
+            || decodedCount >= steam::kMaximumLanguageBytes) {
+            return false;
+        }
+        candidate[decodedCount++] = value;
+    }
+    if (decodedCount == 0) {
+        return false;
+    }
+    output = candidate;
+    return true;
+}
+
 } // namespace
 
 /** Parses Steam settings on top of the fixed defaults. */
@@ -132,6 +161,7 @@ bool Parser::steam_settings(steam::Settings& output) noexcept {
     }
     steam::Settings candidate = output;
     bool hasUser = false;
+    bool hasLanguage = false;
     if (consume('}')) {
         return true;
     }
@@ -145,6 +175,12 @@ bool Parser::steam_settings(steam::Settings& output) noexcept {
                 return false;
             }
             hasUser = true;
+        } else if (key == "language") {
+            std::string_view value;
+            if (hasLanguage || !string(value) || !decode_language(value, candidate.language)) {
+                return false;
+            }
+            hasLanguage = true;
         } else if (!skip_value(0)) {
             return false;
         }

+ 3 - 4
Sunrise/src/steam/interfaces/methods/common.cpp

@@ -1,13 +1,12 @@
 #include <cstdint>
 #include <cstring>
 
+#include "../../../core/settings/settings.h"
 #include "../internal.h"
 
 namespace sunrise::steam::interfaces::methods {
 namespace {
 
-/** Steam language token used when there is no localization service. */
-constexpr char kLanguage[] = "english";
 /** Steam callback id for receiving the current user stats. */
 constexpr int kUserStatsReceivedCallback = 1101;
 /** Steam result code for success. */
@@ -61,9 +60,9 @@ bool return_true([[maybe_unused]] void* self) noexcept {
     return true;
 }
 
-/** @return Language token. It lasts for the whole process. */
+/** @return Language token from settings. It lasts for the whole process. */
 const char* language([[maybe_unused]] void* self) noexcept {
-    return kLanguage;
+    return core::settings::get().steam.language.data();
 }
 
 /** @return The stable local user handle. */