common.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. #include <cstdint>
  2. #include <cstring>
  3. #include "../../../core/settings/settings.h"
  4. #include "../internal.h"
  5. namespace sunrise::steam::interfaces::methods {
  6. namespace {
  7. /** Steam callback id for receiving the current user stats. */
  8. constexpr int kUserStatsReceivedCallback = 1101;
  9. /** Steam result code for success. */
  10. constexpr int kResultOk = 1;
  11. /**
  12. * Account id for the single local user. The Client builds its whole account identity from it,
  13. * so the authored `primary_soid` is tied to this value and the two move together.
  14. */
  15. constexpr std::uint64_t kLocalSteamId = 0x0110000130AA9EC5ULL;
  16. /** Steam universe value for the public network. */
  17. constexpr int kConnectedUniverse = 1;
  18. /** FNV-1a 64-bit offset basis for stable action handles. */
  19. constexpr std::uint64_t kFnvOffsetBasis = 14695981039346656037ULL;
  20. /** FNV-1a 64-bit prime for stable action handles. */
  21. constexpr std::uint64_t kFnvPrime = 1099511628211ULL;
  22. /** The user-stats callback is 24 bytes. */
  23. constexpr std::size_t kUserStatsReceivedSize = 24;
  24. /** Steam current-user-stats callback layout. */
  25. struct UserStatsReceived {
  26. std::uint64_t gameId{};
  27. int result{};
  28. DWORD padding{};
  29. std::uint64_t userId{};
  30. };
  31. static_assert(sizeof(UserStatsReceived) == kUserStatsReceivedSize);
  32. /** @param value Action name. @return FNV-1a handle, or zero for a missing name. */
  33. [[nodiscard]] std::uint64_t hash_name(const char* value) noexcept {
  34. if (value == nullptr || *value == '\0') {
  35. return 0;
  36. }
  37. std::uint64_t hash = kFnvOffsetBasis;
  38. while (*value != '\0') {
  39. hash ^= static_cast<unsigned char>(*value++);
  40. hash *= kFnvPrime;
  41. }
  42. return hash == 0 ? 1 : hash;
  43. }
  44. } // namespace
  45. /** @return Zero. The call is not supported. */
  46. ULONG_PTR empty([[maybe_unused]] void* self) noexcept {
  47. return 0;
  48. }
  49. /** @return True. This capability holds no state. */
  50. bool return_true([[maybe_unused]] void* self) noexcept {
  51. return true;
  52. }
  53. /** @return Language token from settings. It lasts for the whole process. */
  54. const char* language([[maybe_unused]] void* self) noexcept {
  55. return core::settings::get().steam.language.data();
  56. }
  57. /** @return The stable local user handle. */
  58. UserHandle get_user_handle([[maybe_unused]] void* self) noexcept {
  59. return user_handle();
  60. }
  61. /**
  62. * @param result Caller storage for the SteamId.
  63. * @return The same storage, or null when none was given.
  64. */
  65. SteamId* get_steam_id([[maybe_unused]] void* self, SteamId* result) noexcept {
  66. if (result != nullptr) {
  67. result->value = kLocalSteamId;
  68. }
  69. return result;
  70. }
  71. /**
  72. * Reports every application as installed. A DLC id reported as owned but not installed makes the
  73. * Client treat its content as missing.
  74. * @return True for every id.
  75. */
  76. bool app_is_installed([[maybe_unused]] void* self, [[maybe_unused]] DWORD candidate) noexcept {
  77. return true;
  78. }
  79. /** @return True when the stats callback is queued. */
  80. bool request_current_stats([[maybe_unused]] void* self) noexcept {
  81. const UserStatsReceived received{app_id(), kResultOk, 0, 0};
  82. return queue_callback(kUserStatsReceivedCallback, 0, &received, sizeof(received));
  83. }
  84. /**
  85. * @param achieved Receives false when storage is given.
  86. * @return True when the output storage is valid.
  87. */
  88. bool get_achievement([[maybe_unused]] void* self,
  89. [[maybe_unused]] const char* name,
  90. bool* achieved) noexcept {
  91. if (achieved == nullptr) {
  92. return false;
  93. }
  94. *achieved = false;
  95. return true;
  96. }
  97. /** @return Stable nonzero action handle, or zero for a missing name. */
  98. std::uint64_t input_handle([[maybe_unused]] void* self, const char* name) noexcept {
  99. return hash_name(name);
  100. }
  101. /** @return Two false flags. The digital action is never active. */
  102. InputDigitalActionData input_digital_data([[maybe_unused]] void* self,
  103. [[maybe_unused]] std::uint64_t controllerHandle,
  104. [[maybe_unused]] std::uint64_t actionHandle) noexcept {
  105. return {};
  106. }
  107. /** @return A zeroed record. The analog action is never active. */
  108. InputAnalogActionData input_analog_data([[maybe_unused]] void* self,
  109. [[maybe_unused]] std::uint64_t controllerHandle,
  110. [[maybe_unused]] std::uint64_t actionHandle) noexcept {
  111. return {};
  112. }
  113. /** @return A zeroed motion record. */
  114. InputMotionData input_motion_data([[maybe_unused]] void* self,
  115. [[maybe_unused]] std::uint64_t controllerHandle) noexcept {
  116. return {};
  117. }
  118. /**
  119. * Copies the input text through unchanged. Nothing is filtered.
  120. * @param outputSize Output size, including the null.
  121. * @return Bytes copied, without the null.
  122. */
  123. int filter_text([[maybe_unused]] void* self,
  124. char* output,
  125. DWORD outputSize,
  126. const char* input,
  127. [[maybe_unused]] bool compatibilityFlag) noexcept {
  128. if (output == nullptr || outputSize == 0) {
  129. return 0;
  130. }
  131. if (input == nullptr) {
  132. output[0] = '\0';
  133. return 0;
  134. }
  135. DWORD count{};
  136. while (count + 1 < outputSize && input[count] != '\0') {
  137. output[count] = input[count];
  138. ++count;
  139. }
  140. output[count] = '\0';
  141. return static_cast<int>(count);
  142. }
  143. /** @return The serialized networking interface, or null for bad input. */
  144. void* get_generic_interface([[maybe_unused]] void* self,
  145. UserHandle user,
  146. PipeHandle pipe,
  147. const char* version) noexcept {
  148. if (user != user_handle() || pipe != pipe_handle() || version == nullptr) {
  149. return nullptr;
  150. }
  151. return std::strcmp(version, versions::kSerializedNetworking) == 0
  152. ? tables::serialized_networking()
  153. : nullptr;
  154. }
  155. /** @return The user interface, or null for bad input. */
  156. void* get_client_user([[maybe_unused]] void* self,
  157. UserHandle user,
  158. PipeHandle pipe,
  159. const char* version) noexcept {
  160. return user == user_handle() && pipe == pipe_handle() && version != nullptr
  161. && std::strcmp(version, versions::kUser) == 0
  162. ? tables::user()
  163. : nullptr;
  164. }
  165. /** @return The utils interface, or null for bad input. */
  166. void* get_client_utils([[maybe_unused]] void* self, PipeHandle pipe, const char* version) noexcept {
  167. return pipe == pipe_handle() && version != nullptr
  168. && std::strcmp(version, versions::kUtils) == 0
  169. ? tables::utils()
  170. : nullptr;
  171. }
  172. /** @return The HTTP interface, or null for bad input. */
  173. void* get_client_http([[maybe_unused]] void* self,
  174. UserHandle user,
  175. PipeHandle pipe,
  176. const char* version) noexcept {
  177. return user == user_handle() && pipe == pipe_handle() && version != nullptr
  178. && std::strcmp(version, versions::kHttp) == 0
  179. ? tables::http()
  180. : nullptr;
  181. }
  182. /** @return The Steam public-universe id. */
  183. int connected_universe([[maybe_unused]] void* self) noexcept {
  184. return kConnectedUniverse;
  185. }
  186. } // namespace sunrise::steam::interfaces::methods