opcode1901_codec.cpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. #include <cstddef>
  2. #include "../../encoding/bit_reader.h"
  3. #include "opcode1901.h"
  4. namespace sunrise::middleware::web_service::messages::opcode1901 {
  5. namespace {
  6. /** The reflected opcode-1901 request occupies exactly 192 bits. */
  7. constexpr std::size_t kPayloadSize = 24;
  8. /** The native fixed replacement array reserves twelve entries, so its count uses four bits. */
  9. constexpr std::uint8_t kReplacementCountWidth = 4;
  10. /** This codec supports the single replacement emitted by one shader Apply action. */
  11. constexpr std::uint64_t kCanonicalReplacementCount = 1;
  12. /** Signed native definition indices use one presence bit followed by fifteen value bits. */
  13. constexpr std::uint8_t kDefinitionIndexWidth = 15;
  14. /** The canonical socket-kind byte is signed and biased from INT8_MIN. */
  15. constexpr std::uint8_t kCanonicalSocketKindWidth = 8;
  16. /** The compact model socket-kind discriminator occupies two bits. */
  17. constexpr std::uint8_t kModelSocketKindWidth = 2;
  18. /** The signed socket index is biased from INT32_MIN. */
  19. constexpr std::uint8_t kSocketIndexWidth = 32;
  20. /** The replacement auxiliary identity and semantic equipment selector are optional 64-bit fields.
  21. */
  22. constexpr std::uint8_t kOptionalIdentityWidth = 64;
  23. /** Nonnegative signed 8-bit values have this bit set after native descriptor biasing. */
  24. constexpr std::uint64_t kCanonicalSocketKindBias = 0x80ULL;
  25. /** Nonnegative signed 32-bit values have this bit set after native descriptor biasing. */
  26. constexpr std::uint64_t kSocketIndexBias = 0x80000000ULL;
  27. /** Model socket-kind zero is encoded as one so wire zero remains the absent sentinel. */
  28. constexpr std::uint64_t kModelSocketKindBias = 1;
  29. /** Shader Apply targets an ordinary item socket model. */
  30. constexpr std::uint64_t kShaderModelSocketKind = 0;
  31. /** Collection-backed shader action sources carry no auxiliary instance identity. */
  32. constexpr std::uint64_t kShaderAuxiliary = 0;
  33. /** The character screen's selector is four times the instance identity it names. */
  34. constexpr std::uint64_t kSelectorStride = 4;
  35. } // namespace
  36. /** Compares a decoded selector against the part of an instance identity the wire carries. */
  37. bool identifies_instance(std::uint64_t instanceIdentityToken,
  38. std::uint64_t instanceSoid) noexcept {
  39. return instanceIdentityToken != 0
  40. && (instanceSoid & kInstanceIdentityMask) == instanceIdentityToken;
  41. }
  42. /** Parses the complete native equipped shader socket-action descriptor. */
  43. bool parse_request(const Message& message, Request& request) noexcept {
  44. request = {};
  45. if (message.opcode != kOpcode || message.payload.size() != kPayloadSize) {
  46. return false;
  47. }
  48. encoding::bits::Reader reader(message.payload);
  49. std::uint64_t replacementCount = 0;
  50. std::uint64_t plugDefinitionPresent = 0;
  51. std::uint64_t encodedPlugDefinition = 0;
  52. std::uint64_t encodedCanonicalSocketKind = 0;
  53. std::uint64_t modelSocketKind = 0;
  54. std::uint64_t encodedSocketIndex = 0;
  55. std::uint64_t auxiliaryPresent = 0;
  56. std::uint64_t equipmentSelectorPresent = 0;
  57. if (!reader.read(kReplacementCountWidth, replacementCount)
  58. || !reader.read(1, plugDefinitionPresent)
  59. || !reader.read(kDefinitionIndexWidth, encodedPlugDefinition)
  60. || !reader.read(kCanonicalSocketKindWidth, encodedCanonicalSocketKind)
  61. || !reader.read(kModelSocketKindWidth, modelSocketKind)
  62. || !reader.read(kSocketIndexWidth, encodedSocketIndex) || !reader.read(1, auxiliaryPresent)
  63. || !reader.read(kOptionalIdentityWidth, request.auxiliary)
  64. || !reader.read(1, equipmentSelectorPresent)
  65. || !reader.read(kOptionalIdentityWidth, request.equipmentSelector)
  66. || reader.remaining_bits() != 0 || replacementCount != kCanonicalReplacementCount
  67. || plugDefinitionPresent == 0 || auxiliaryPresent == 0 || equipmentSelectorPresent == 0
  68. || encodedCanonicalSocketKind < kCanonicalSocketKindBias
  69. || modelSocketKind < kModelSocketKindBias || encodedSocketIndex < kSocketIndexBias
  70. || modelSocketKind - kModelSocketKindBias != kShaderModelSocketKind
  71. || request.auxiliary != kShaderAuxiliary) {
  72. request = {};
  73. return false;
  74. }
  75. // The selector is a wire encoding of an instance identity, so it is decoded here rather than
  76. // handed on as a raw number for a later layer to divide.
  77. if (request.equipmentSelector == 0 || request.equipmentSelector % kSelectorStride != 0
  78. || request.equipmentSelector / kSelectorStride > kInstanceIdentityMask) {
  79. const std::uint64_t selector = request.equipmentSelector;
  80. request = {};
  81. request.equipmentSelector = selector;
  82. return false;
  83. }
  84. request.instanceIdentityToken = request.equipmentSelector / kSelectorStride;
  85. request.plugDefinitionIndex = static_cast<std::uint16_t>(encodedPlugDefinition);
  86. request.canonicalSocketKind =
  87. static_cast<std::uint8_t>(encodedCanonicalSocketKind - kCanonicalSocketKindBias);
  88. request.modelSocketKind = static_cast<std::uint8_t>(modelSocketKind - kModelSocketKindBias);
  89. request.socketIndex = static_cast<std::uint32_t>(encodedSocketIndex - kSocketIndexBias);
  90. return request.canonicalSocketKind == request.socketIndex;
  91. }
  92. } // namespace sunrise::middleware::web_service::messages::opcode1901