activity_sense_update_decoder.cpp 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933
  1. #include <bit>
  2. #include <limits>
  3. #include "../../encoding/bit_reader.h"
  4. #include "../../encoding/byte_order.h"
  5. #include "activity_sense_update_reader.h"
  6. #include "sense_update.h"
  7. namespace sunrise::middleware::bap::activity_message::sense_update {
  8. namespace {
  9. using namespace decoding;
  10. /** Field widths of the object header ClientRef, in bits. */
  11. constexpr std::uint8_t kKeyWidth = 32, kTypeWidth = 7, kIndexWidth = 16;
  12. /** The slot type and index are sent unsigned, biased so their absent value is zero. */
  13. constexpr std::uint32_t kTypeBias = 1, kIndexBias = 32768;
  14. /** Schema tags the sense-update objects and their nested arrays declare. */
  15. constexpr std::uint32_t kDevice = 0x80804F47U, kScene = 0x8080626AU;
  16. constexpr std::uint32_t kSquad = 0x80807ECCU, kObjective = 0x80807F04U;
  17. constexpr std::uint32_t kOccupancy = 0x80809531U;
  18. constexpr std::uint32_t kAttachment = 0x8080954AU;
  19. constexpr std::uint32_t kGhostLink = 0x80804D3EU;
  20. constexpr std::uint32_t kObject = 0x8080992EU;
  21. constexpr std::uint32_t kObjectSpawnMask = 0x80809E1BU, kObjectReplies = 0x80809AEAU;
  22. constexpr std::uint32_t kSceneEvents = 0x808094DFU, kSceneList = 0x808094E1U;
  23. constexpr std::uint32_t kSquadCounts = 0x80809491U, kSquadList = 0x80807ECFU;
  24. constexpr std::uint32_t kSquadReals = 0x80807ECDU;
  25. constexpr std::uint32_t kObjectiveBlock = 0x80807F07U, kObjectiveTasks = 0x80807F08U;
  26. constexpr std::uint32_t kCombatant = 0x80807DA2U, kCombatantAtoms = 0x80807F6EU;
  27. constexpr std::uint32_t kCombatantKeyed = 0x80807DA3U, kCombatantLanes = 0x80807DA4U;
  28. constexpr std::uint32_t kEngagement = 0x808094F0U, kEngagementList = 0x808094F8U;
  29. /** Type-13 participation root and its nested blocks, in body order. */
  30. constexpr std::uint32_t kPlayer = 0x80804F2FU, kPlayerState = 0x808094E4U;
  31. constexpr std::uint32_t kPlayerScalars = 0x80804F39U, kPlayerTail = 0x80804F35U;
  32. constexpr std::uint32_t kPlayerIdentity = 0x808094DDU, kPlayerKeys = 0x808094DFU;
  33. constexpr std::uint32_t kPlayerPairs = 0x808094E3U, kPlayerFlags = 0x80804F31U;
  34. constexpr std::uint32_t kPlayerOptional = 0x80804F34U;
  35. /** Type-20 damage monitor root: health, shield, echoed revision. */
  36. constexpr std::uint32_t kDamage = 0x80809562U;
  37. /** Registered object replies: the interaction latch and the ownership key. */
  38. constexpr std::uint32_t kInteractionReply = 0x80804FB7U, kOwnershipReply = 0x80809ACCU;
  39. /** Counted lists inside the participation body. */
  40. constexpr std::uint64_t kPlayerScalarCountMaximum = 4, kPlayerKeyCountMaximum = 32;
  41. /** Quantization ceilings the combatant reals carry in their own descriptors. */
  42. constexpr std::uint32_t kSpatialMaximumBits = 0x45000000U, kUnitMaximumBits = 0x3F800000U;
  43. enum class NativeStatus : std::uint8_t { complete, unsupported, unsafeCount, malformed };
  44. /** @param width Field width in bits. @return Low-bit mask of that width. */
  45. [[nodiscard]] constexpr std::uint64_t mask(std::uint8_t width) noexcept {
  46. return width == 64 ? (std::numeric_limits<std::uint64_t>::max)()
  47. : (std::uint64_t{1} << width) - 1;
  48. }
  49. [[nodiscard]] std::int64_t
  50. signed_value(std::uint64_t raw, std::int32_t bias, std::uint8_t storageWidth) noexcept {
  51. const std::uint64_t decoded =
  52. (raw - static_cast<std::uint64_t>(static_cast<std::int64_t>(bias))) & mask(storageWidth);
  53. if (storageWidth == 64) {
  54. return static_cast<std::int64_t>(decoded);
  55. }
  56. const std::uint64_t sign = std::uint64_t{1} << (storageWidth - 1);
  57. return static_cast<std::int64_t>((decoded ^ sign) - sign);
  58. }
  59. /** Collects decoded values into the packet, dropping them once the object's room runs out. */
  60. class Values final {
  61. public:
  62. Values(DecodedPacket& packet, DecodedObject* object) noexcept
  63. : packet_(packet), object_(object) {}
  64. /** Retains one field value, marking truncation when the packet's storage is full. */
  65. void put(std::uint32_t schema,
  66. std::uint16_t ordinal,
  67. std::uint32_t occurrence,
  68. std::uint32_t at,
  69. std::uint8_t width,
  70. ValueKind kind,
  71. std::uint64_t raw,
  72. std::int64_t signedRaw,
  73. float real,
  74. bool present) noexcept {
  75. if (object_ == nullptr) {
  76. return;
  77. }
  78. if (packet_.valueCount == packet_.values.size()) {
  79. packet_.valuesTruncated = true;
  80. return;
  81. }
  82. DecodedValue& value = packet_.values[packet_.valueCount++];
  83. value.schemaRow = schema;
  84. value.fieldRow = ordinal;
  85. value.fieldOrdinal = ordinal;
  86. value.occurrence = occurrence;
  87. value.bitOffset = at;
  88. value.width = width;
  89. value.kind = kind;
  90. value.unsignedValue = raw;
  91. value.signedValue = signedRaw;
  92. value.realValue = real;
  93. value.present = present;
  94. }
  95. private:
  96. DecodedPacket& packet_;
  97. DecodedObject* object_{};
  98. };
  99. /**
  100. * Reads one optional or required unsigned field and records it.
  101. * @param optional True when a presence bit precedes the value.
  102. * @return True when the presence bit and any value were complete.
  103. */
  104. [[nodiscard]] bool read_unsigned(Reader& reader,
  105. Values& values,
  106. std::uint32_t schema,
  107. std::uint16_t ordinal,
  108. std::uint8_t width,
  109. bool optional,
  110. std::uint32_t occurrence = 0) noexcept {
  111. const auto at = static_cast<std::uint32_t>(reader.position());
  112. bool exists = true;
  113. if (!present(reader, optional, exists)) {
  114. return false;
  115. }
  116. std::uint64_t raw = 0;
  117. if (exists && !reader.read(width, raw)) {
  118. return false;
  119. }
  120. values.put(schema,
  121. ordinal,
  122. occurrence,
  123. at,
  124. exists ? width : 0,
  125. ValueKind::unsignedInteger,
  126. raw,
  127. 0,
  128. 0.0F,
  129. exists);
  130. return true;
  131. }
  132. /** Removes wire bias and sign-extends to the host width after reading a complete selected field. */
  133. [[nodiscard]] bool read_signed(Reader& reader,
  134. Values& values,
  135. std::uint32_t schema,
  136. std::uint16_t ordinal,
  137. std::uint8_t wireWidth,
  138. std::uint8_t storageWidth,
  139. std::int32_t bias,
  140. bool optional,
  141. std::uint32_t occurrence = 0) noexcept {
  142. const auto at = static_cast<std::uint32_t>(reader.position());
  143. bool exists = true;
  144. if (!present(reader, optional, exists)) {
  145. return false;
  146. }
  147. std::uint64_t raw = 0;
  148. if (exists && !reader.read(wireWidth, raw)) {
  149. return false;
  150. }
  151. const std::int64_t decoded = exists ? signed_value(raw, bias, storageWidth) : 0;
  152. values.put(schema,
  153. ordinal,
  154. occurrence,
  155. at,
  156. exists ? wireWidth : 0,
  157. ValueKind::signedInteger,
  158. static_cast<std::uint64_t>(decoded),
  159. decoded,
  160. 0.0F,
  161. exists);
  162. return true;
  163. }
  164. /** Reads one boolean field into the value table. */
  165. [[nodiscard]] bool read_bool(Reader& reader,
  166. Values& values,
  167. std::uint32_t schema,
  168. std::uint16_t ordinal,
  169. bool optional,
  170. std::uint32_t occurrence = 0) noexcept {
  171. const auto at = static_cast<std::uint32_t>(reader.position());
  172. bool exists = true;
  173. if (!present(reader, optional, exists)) {
  174. return false;
  175. }
  176. std::uint64_t raw = 0;
  177. if (exists && !reader.read(1, raw)) {
  178. return false;
  179. }
  180. values.put(
  181. schema, ordinal, occurrence, at, exists ? 1 : 0, ValueKind::boolean, raw, 0, 0.0F, exists);
  182. return true;
  183. }
  184. /** Quantized endpoints stay exact; width 32 carries raw float bits. */
  185. [[nodiscard]] float
  186. real_value(std::uint64_t raw, std::uint8_t width, std::uint32_t maximumBits) noexcept {
  187. if (width == 32) {
  188. return std::bit_cast<float>(static_cast<std::uint32_t>(raw));
  189. }
  190. const float maximum = std::bit_cast<float>(maximumBits);
  191. const std::uint64_t levels = std::uint64_t{1} << width;
  192. if (raw == 0) {
  193. return 0.0F;
  194. }
  195. if (raw == levels - 1) {
  196. return maximum;
  197. }
  198. const float step = maximum / static_cast<float>(levels - 2);
  199. return static_cast<float>(raw - 1) * step + step * 0.5F;
  200. }
  201. /** Records a real only when its presence bit and selected value fit. */
  202. [[nodiscard]] bool read_real(Reader& reader,
  203. Values& values,
  204. std::uint32_t schema,
  205. std::uint16_t ordinal,
  206. std::uint8_t width,
  207. bool optional,
  208. std::uint32_t occurrence = 0,
  209. std::uint32_t maximumBits = 0) noexcept {
  210. const auto at = static_cast<std::uint32_t>(reader.position());
  211. bool exists = true;
  212. if (!present(reader, optional, exists)) {
  213. return false;
  214. }
  215. std::uint64_t raw = 0;
  216. if (exists && !reader.read(width, raw)) {
  217. return false;
  218. }
  219. values.put(schema,
  220. ordinal,
  221. occurrence,
  222. at,
  223. exists ? width : 0,
  224. ValueKind::real32,
  225. raw,
  226. 0,
  227. exists ? real_value(raw, width, maximumBits) : 0.0F,
  228. exists);
  229. return true;
  230. }
  231. /** Decodes three device channels within the object's bit budget. */
  232. [[nodiscard]] NativeStatus decode_device(Reader& reader, Values& values) noexcept {
  233. for (std::uint16_t channel = 0; channel < 3; ++channel) {
  234. if (!read_real(reader, values, kDevice, channel * 2, 32, true)
  235. || !read_signed(reader,
  236. values,
  237. kDevice,
  238. channel * 2 + 1,
  239. 32,
  240. 32,
  241. (std::numeric_limits<std::int32_t>::min)(),
  242. true)) {
  243. return NativeStatus::malformed;
  244. }
  245. }
  246. return NativeStatus::complete;
  247. }
  248. /** Decodes the occupancy flags and signed values within the object's bit budget. */
  249. [[nodiscard]] NativeStatus decode_occupancy(Reader& reader, Values& values) noexcept {
  250. return read_bool(reader, values, kOccupancy, 0, false)
  251. && read_bool(reader, values, kOccupancy, 1, false)
  252. && read_signed(reader,
  253. values,
  254. kOccupancy,
  255. 2,
  256. 32,
  257. 32,
  258. (std::numeric_limits<std::int32_t>::min)(),
  259. false)
  260. && read_signed(reader,
  261. values,
  262. kOccupancy,
  263. 3,
  264. 32,
  265. 32,
  266. (std::numeric_limits<std::int32_t>::min)(),
  267. false)
  268. ? NativeStatus::complete
  269. : NativeStatus::malformed;
  270. }
  271. /** Decodes a scene and refuses event counts above the native capacity. */
  272. [[nodiscard]] NativeStatus decode_scene(Reader& reader, Values& values) noexcept {
  273. if (!read_signed(
  274. reader, values, kScene, 0, 32, 32, (std::numeric_limits<std::int32_t>::min)(), false)
  275. || !read_bool(reader, values, kScene, 1, false)
  276. || !read_signed(reader, values, kScene, 2, 31, 32, 0, true)
  277. || !read_signed(reader, values, kScene, 3, 2, 8, 1, false)) {
  278. return NativeStatus::malformed;
  279. }
  280. std::uint64_t count = 0;
  281. const auto at = static_cast<std::uint32_t>(reader.position());
  282. if (!reader.read(6, count)) {
  283. return NativeStatus::malformed;
  284. }
  285. if (count > 32) {
  286. return NativeStatus::unsafeCount;
  287. }
  288. values.put(kSceneList, 0, 0, at, 6, ValueKind::unsignedInteger, count, 0, 0.0F, true);
  289. for (std::uint32_t index = 0; index < count; ++index) {
  290. if (!read_unsigned(reader, values, kSceneEvents, 0, 32, false, index)) {
  291. return NativeStatus::malformed;
  292. }
  293. }
  294. return NativeStatus::complete;
  295. }
  296. /** Decodes squad fields and bounded member lists within the object's bit budget. */
  297. [[nodiscard]] NativeStatus decode_squad(Reader& reader, Values& values) noexcept {
  298. if (!read_signed(reader, values, kSquad, 0, 31, 32, 0, true)
  299. || !read_signed(reader, values, kSquad, 1, 31, 32, 0, true)
  300. || !read_signed(reader, values, kSquad, 2, 31, 32, 0, true)
  301. || !read_signed(reader, values, kSquad, 3, 6, 32, 0, true)
  302. || !read_real(reader, values, kSquad, 4, 7, true, 0, 1157562368U)
  303. || !read_signed(reader, values, kSquad, 5, 31, 32, 0, true)
  304. || !read_signed(reader, values, kSquad, 6, 2, 8, 1, false)
  305. || !read_signed(reader, values, kSquad, 7, 3, 8, 1, false)
  306. || !read_bool(reader, values, kSquad, 8, false)
  307. || !read_bool(reader, values, kSquad, 9, false)
  308. || !read_bool(reader, values, kSquad, 10, false)) {
  309. return NativeStatus::malformed;
  310. }
  311. bool exists = false;
  312. if (!present(reader, true, exists)) {
  313. return NativeStatus::malformed;
  314. }
  315. if (exists) {
  316. std::uint64_t count = 0;
  317. const auto at = static_cast<std::uint32_t>(reader.position());
  318. if (!reader.read(4, count)) {
  319. return NativeStatus::malformed;
  320. }
  321. if (count > 8) {
  322. return NativeStatus::unsafeCount;
  323. }
  324. values.put(kSquadList, 0, 0, at, 4, ValueKind::unsignedInteger, count, 0, 0.0F, true);
  325. for (std::uint32_t index = 0; index < count; ++index) {
  326. if (!read_signed(reader,
  327. values,
  328. kSquadCounts,
  329. 0,
  330. 32,
  331. 32,
  332. (std::numeric_limits<std::int32_t>::min)(),
  333. false,
  334. index)) {
  335. return NativeStatus::malformed;
  336. }
  337. }
  338. }
  339. if (!present(reader, true, exists)) {
  340. return NativeStatus::malformed;
  341. }
  342. if (exists) {
  343. for (std::uint32_t index = 0; index < 24; ++index) {
  344. if (!read_real(reader, values, kSquadReals, 0, 7, true, index, 1157562368U)) {
  345. return NativeStatus::malformed;
  346. }
  347. }
  348. }
  349. return NativeStatus::complete;
  350. }
  351. /** Decodes the optional objective blocks and their fixed task arrays. */
  352. [[nodiscard]] NativeStatus decode_objective(Reader& reader, Values& values) noexcept {
  353. bool exists = false;
  354. if (!present(reader, true, exists)) {
  355. return NativeStatus::malformed;
  356. }
  357. if (exists) {
  358. for (std::uint32_t block = 0; block < 24; ++block) {
  359. if (!read_signed(reader, values, kObjectiveBlock, 0, 7, 8, 0, true, block)
  360. || !read_unsigned(reader, values, kObjectiveBlock, 1, 1, false, block)) {
  361. return NativeStatus::malformed;
  362. }
  363. bool tasks = false;
  364. if (!present(reader, true, tasks)) {
  365. return NativeStatus::malformed;
  366. }
  367. if (!tasks) {
  368. continue;
  369. }
  370. for (std::uint32_t task = 0; task < 24; ++task) {
  371. if (!read_signed(
  372. reader, values, kObjectiveTasks, 0, 7, 8, 0, true, block * 24 + task)) {
  373. return NativeStatus::malformed;
  374. }
  375. }
  376. }
  377. }
  378. return read_signed(reader, values, kObjective, 1, 31, 32, 0, true)
  379. && read_unsigned(reader, values, kObjective, 2, 32, true)
  380. ? NativeStatus::complete
  381. : NativeStatus::malformed;
  382. }
  383. /** Decodes an object and accepts only the registered interaction and ownership replies. */
  384. [[nodiscard]] NativeStatus decode_object(Reader& reader, Values& values) noexcept {
  385. if (!read_signed(
  386. reader, values, kObject, 0, 32, 32, (std::numeric_limits<std::int32_t>::min)(), false)
  387. || !read_bool(reader, values, kObject, 1, false)
  388. || !read_bool(reader, values, kObject, 2, false)
  389. || !read_signed(reader,
  390. values,
  391. kObject,
  392. 3,
  393. 32,
  394. 32,
  395. (std::numeric_limits<std::int32_t>::min)(),
  396. false)) {
  397. return NativeStatus::malformed;
  398. }
  399. for (std::uint32_t index = 0; index < 2; ++index) {
  400. if (!read_unsigned(reader, values, kObjectSpawnMask, 0, 32, false, index)) {
  401. return NativeStatus::malformed;
  402. }
  403. }
  404. std::uint64_t count = 0;
  405. const auto at = static_cast<std::uint32_t>(reader.position());
  406. if (!reader.read(2, count)) {
  407. return NativeStatus::malformed;
  408. }
  409. values.put(kObjectReplies, 0, 0, at, 2, ValueKind::unsignedInteger, count, 0, 0.0F, true);
  410. for (std::uint32_t index = 0; index < count; ++index) {
  411. std::uint64_t exists = 0, schema = 0;
  412. if (!reader.read(1, exists)) {
  413. return NativeStatus::malformed;
  414. }
  415. if (!exists) {
  416. continue;
  417. }
  418. if (!reader.read(32, schema)) {
  419. return NativeStatus::malformed;
  420. }
  421. if (schema == kInteractionReply) {
  422. // The interaction latch and the revision that set it.
  423. if (!read_bool(reader, values, kInteractionReply, 0, false, index)
  424. || !read_signed(reader,
  425. values,
  426. kInteractionReply,
  427. 1,
  428. 32,
  429. 32,
  430. (std::numeric_limits<std::int32_t>::min)(),
  431. false,
  432. index)) {
  433. return NativeStatus::malformed;
  434. }
  435. } else if (schema == kOwnershipReply) {
  436. // The owner key is always written, zero when nobody holds the object.
  437. if (!read_bool(reader, values, kOwnershipReply, 0, false, index)
  438. || !read_unsigned(reader, values, kOwnershipReply, 1, 64, false, index)) {
  439. return NativeStatus::malformed;
  440. }
  441. } else {
  442. return NativeStatus::unsupported;
  443. }
  444. }
  445. return NativeStatus::complete;
  446. }
  447. /** Decodes combatant generations, program state, keyed lanes and root flags within the budget. */
  448. [[nodiscard]] NativeStatus decode_combatant(Reader& reader, Values& values) noexcept {
  449. if (!read_signed(reader, values, kCombatant, 0, 31, 32, 0, true)
  450. || !read_real(reader, values, kCombatant, 1, 9, true, 0, kSpatialMaximumBits)
  451. || !read_signed(reader, values, kCombatant, 2, 31, 32, 0, true)) {
  452. return NativeStatus::malformed;
  453. }
  454. bool exists = false;
  455. if (!present(reader, true, exists)) {
  456. return NativeStatus::malformed;
  457. }
  458. if (exists
  459. && (!read_signed(reader, values, kCombatantAtoms, 0, 6, 32, 0, true)
  460. || !read_signed(reader, values, kCombatantAtoms, 1, 31, 32, 0, true)
  461. || !read_signed(reader, values, kCombatantAtoms, 2, 31, 32, 0, true)
  462. || !read_bool(reader, values, kCombatantAtoms, 3, false))) {
  463. return NativeStatus::malformed;
  464. }
  465. if (!present(reader, true, exists)) {
  466. return NativeStatus::malformed;
  467. }
  468. if (exists) {
  469. bool lanes = false;
  470. if (!present(reader, true, lanes)) {
  471. return NativeStatus::malformed;
  472. }
  473. for (std::uint32_t index = 0; lanes && index < 8; ++index) {
  474. if (!read_signed(reader, values, kCombatantLanes, 0, 31, 32, 0, true, index)) {
  475. return NativeStatus::malformed;
  476. }
  477. }
  478. if (!read_unsigned(reader, values, kCombatantKeyed, 1, 32, true)) {
  479. return NativeStatus::malformed;
  480. }
  481. }
  482. if (!read_signed(reader, values, kCombatant, 5, 31, 32, 0, true)
  483. || !read_signed(reader, values, kCombatant, 6, 2, 8, 1, false)
  484. || !read_signed(reader, values, kCombatant, 7, 31, 32, 0, true)
  485. || !read_real(reader, values, kCombatant, 8, 7, true, 0, kUnitMaximumBits)
  486. || !read_real(reader, values, kCombatant, 9, 7, true, 0, kUnitMaximumBits)
  487. || !read_bool(reader, values, kCombatant, 10, false)
  488. || !read_bool(reader, values, kCombatant, 11, false)) {
  489. return NativeStatus::malformed;
  490. }
  491. return NativeStatus::complete;
  492. }
  493. /**
  494. * The observed engagement list is empty. Nonempty custom35 elements remain unsupported until
  495. * their native codec is established; a storage size is not a wire width.
  496. */
  497. [[nodiscard]] NativeStatus decode_engagement(Reader& reader, Values& values) noexcept {
  498. constexpr std::uint64_t capacity = 16;
  499. std::uint64_t count = 0;
  500. const auto at = static_cast<std::uint32_t>(reader.position());
  501. if (!reader.read(5, count)) {
  502. return NativeStatus::malformed;
  503. }
  504. if (count > capacity) {
  505. return NativeStatus::unsafeCount;
  506. }
  507. if (count != 0) {
  508. return NativeStatus::unsupported;
  509. }
  510. values.put(kEngagementList, 0, 0, at, 5, ValueKind::unsignedInteger, count, 0, 0.0F, true);
  511. return read_signed(reader, values, kEngagement, 1, 16, 16, 32768, false)
  512. ? NativeStatus::complete
  513. : NativeStatus::malformed;
  514. }
  515. /** Build86657's attachment Sense has three required s32 counters and one bool. */
  516. [[nodiscard]] NativeStatus decode_attachment(Reader& reader, Values& values) noexcept {
  517. for (std::uint16_t ordinal = 0; ordinal < 3; ++ordinal) {
  518. if (!read_signed(reader,
  519. values,
  520. kAttachment,
  521. ordinal,
  522. 32,
  523. 32,
  524. (std::numeric_limits<std::int32_t>::min)(),
  525. false)) {
  526. return NativeStatus::malformed;
  527. }
  528. }
  529. return read_bool(reader, values, kAttachment, 3, false) ? NativeStatus::complete
  530. : NativeStatus::malformed;
  531. }
  532. /**
  533. * Decodes the type-13 participation body. The whole body is read before its Ghost flag counts,
  534. * because a player mid-load publishes a body with the flag but without a settled actor.
  535. */
  536. [[nodiscard]] NativeStatus decode_player(Reader& reader, Values& values) noexcept {
  537. // The participation field uses a signed 32-bit midpoint bias.
  538. constexpr auto signedBias = (std::numeric_limits<std::int32_t>::min)();
  539. if (!read_signed(reader, values, kPlayerState, 0, 32, 32, signedBias, true)
  540. || !read_unsigned(reader, values, kPlayerState, 1, 32, true)) {
  541. return NativeStatus::malformed;
  542. }
  543. for (std::uint16_t ordinal = 2; ordinal <= 5; ++ordinal) {
  544. if (!read_bool(reader, values, kPlayerState, ordinal, false)) {
  545. return NativeStatus::malformed;
  546. }
  547. }
  548. if (!read_signed(reader, values, kPlayerState, 6, 3, 8, 1, false)
  549. || !read_signed(reader, values, kPlayerState, 7, 2, 8, 1, false)) {
  550. return NativeStatus::malformed;
  551. }
  552. std::uint64_t count = 0;
  553. if (!reader.read(3, count)) {
  554. return NativeStatus::malformed;
  555. }
  556. if (count > kPlayerScalarCountMaximum) {
  557. return NativeStatus::unsafeCount;
  558. }
  559. for (unsigned index = 0; index < count; ++index) {
  560. if (!read_unsigned(reader, values, kPlayerScalars, 0, 32, false, index)
  561. || !read_real(reader, values, kPlayerScalars, 1, 32, false, index)) {
  562. return NativeStatus::malformed;
  563. }
  564. }
  565. if (!read_real(reader, values, kPlayerTail, 1, 32, false)
  566. || !read_signed(reader, values, kPlayerTail, 2, 5, 32, 1, false)
  567. || !read_signed(reader, values, kPlayerTail, 3, 32, 32, signedBias, true)) {
  568. return NativeStatus::malformed;
  569. }
  570. for (std::uint16_t ordinal = 4; ordinal <= 6; ++ordinal) {
  571. if (!read_bool(reader, values, kPlayerTail, ordinal, false)) {
  572. return NativeStatus::malformed;
  573. }
  574. }
  575. if (!read_unsigned(reader, values, kPlayerIdentity, 0, 64, true)
  576. || !read_unsigned(reader, values, kPlayerIdentity, 1, 5, false)
  577. || !read_signed(reader, values, kPlayerIdentity, 2, 6, 8, 3, false)) {
  578. return NativeStatus::malformed;
  579. }
  580. if (!reader.read(6, count)) {
  581. return NativeStatus::malformed;
  582. }
  583. if (count > kPlayerKeyCountMaximum) {
  584. return NativeStatus::unsafeCount;
  585. }
  586. for (unsigned index = 0; index < count; ++index) {
  587. if (!read_unsigned(reader, values, kPlayerKeys, 0, 32, false, index)) {
  588. return NativeStatus::malformed;
  589. }
  590. }
  591. if (!reader.read(6, count)) {
  592. return NativeStatus::malformed;
  593. }
  594. if (count > kPlayerKeyCountMaximum) {
  595. return NativeStatus::unsafeCount;
  596. }
  597. for (unsigned index = 0; index < count; ++index) {
  598. if (!read_unsigned(reader, values, kPlayerPairs, 0, 32, true, index)
  599. || !read_unsigned(reader, values, kPlayerPairs, 1, 64, true, index)) {
  600. return NativeStatus::malformed;
  601. }
  602. }
  603. if (!read_bool(reader, values, kPlayerFlags, 0, false)
  604. || !read_unsigned(reader, values, kPlayerFlags, 1, 4, false)
  605. || !read_unsigned(reader, values, kPlayerFlags, 2, 16, true)
  606. || !read_unsigned(reader, values, kPlayerFlags, 3, 16, true)) {
  607. return NativeStatus::malformed;
  608. }
  609. bool exists = false;
  610. if (!present(reader, true, exists)) {
  611. return NativeStatus::malformed;
  612. }
  613. if (exists && !read_unsigned(reader, values, kPlayerOptional, 0, 32, false)) {
  614. return NativeStatus::malformed;
  615. }
  616. return read_bool(reader, values, kPlayerFlags, 5, false)
  617. && read_signed(reader, values, kPlayerFlags, 6, 8, 8, 128, false)
  618. && read_signed(reader, values, kPlayer, 4, 32, 32, signedBias, false)
  619. ? NativeStatus::complete
  620. : NativeStatus::malformed;
  621. }
  622. /** Decodes one root body of the given schema; the status names how far it got. */
  623. [[nodiscard]] NativeStatus
  624. decode_body(std::uint32_t schema, Reader& reader, Values& values) noexcept {
  625. std::uint64_t root = 0;
  626. if (!reader.read(1, root)) {
  627. return NativeStatus::malformed;
  628. }
  629. if (root == 0) {
  630. return NativeStatus::complete;
  631. }
  632. switch (schema) {
  633. case kPlayer:
  634. return decode_player(reader, values);
  635. case kDamage:
  636. // Three mandatory fields: health, shield, then the echoed Auth revision.
  637. return read_real(reader, values, schema, 0, 32, false)
  638. && read_real(reader, values, schema, 1, 32, false)
  639. && read_signed(reader,
  640. values,
  641. schema,
  642. 2,
  643. 32,
  644. 32,
  645. (std::numeric_limits<std::int32_t>::min)(),
  646. false)
  647. ? NativeStatus::complete
  648. : NativeStatus::malformed;
  649. case kGhostLink:
  650. // Three mandatory fields: active, elapsed over duration, accepted Auth generation.
  651. return read_bool(reader, values, kGhostLink, 0, false)
  652. && read_real(reader, values, kGhostLink, 1, 32, false)
  653. && read_signed(reader,
  654. values,
  655. kGhostLink,
  656. 2,
  657. 32,
  658. 32,
  659. (std::numeric_limits<std::int32_t>::min)(),
  660. false)
  661. ? NativeStatus::complete
  662. : NativeStatus::malformed;
  663. case kDevice:
  664. return decode_device(reader, values);
  665. case kScene:
  666. return decode_scene(reader, values);
  667. case kSquad:
  668. return decode_squad(reader, values);
  669. case kObjective:
  670. return decode_objective(reader, values);
  671. case kOccupancy:
  672. return decode_occupancy(reader, values);
  673. case kAttachment:
  674. return decode_attachment(reader, values);
  675. case kObject:
  676. return decode_object(reader, values);
  677. case kCombatant:
  678. return decode_combatant(reader, values);
  679. case kEngagement:
  680. return decode_engagement(reader, values);
  681. default:
  682. return NativeStatus::unsupported;
  683. }
  684. }
  685. [[nodiscard]] bool skip_group(Reader& reader) noexcept {
  686. if (reader.left() == 0 || !reader.skip(reader.left() - 1)) {
  687. return false;
  688. }
  689. std::uint64_t end = 0;
  690. return reader.read(1, end) && end == 0 && reader.left() == 0;
  691. }
  692. void finish(SenseUpdate& update,
  693. bits::Reader& reader,
  694. std::size_t total,
  695. DecodeStatus status,
  696. std::size_t& consumed) noexcept {
  697. update.decoded.status = status;
  698. update.decoded.bitsConsumed = total - reader.remaining_bits();
  699. update.decoded.bitsRemaining = reader.remaining_bits();
  700. consumed = update.decoded.bitsConsumed;
  701. }
  702. } // namespace
  703. /** Decodes epoch and sensor blocks with per-group budgets and exact zero padding. */
  704. bool decode_sense_update(std::span<const std::byte> input,
  705. const Resolver& resolver,
  706. SenseUpdate& update,
  707. std::size_t& consumed) noexcept {
  708. update = {};
  709. consumed = 0;
  710. if (input.size() > kOuterByteCapacity) {
  711. return false;
  712. }
  713. const std::size_t total = input.size() * encoding::kBitsPerByte;
  714. bits::Reader reader(input);
  715. std::uint64_t literal = 0, root = 0;
  716. if (!reader.read(kEpochFieldWidth, update.epoch.first)
  717. || !reader.read(kEpochFieldWidth, update.epoch.second) || !reader.read(1, literal)
  718. || literal != 0 || !reader.read(1, root)) {
  719. finish(update, reader, total, DecodeStatus::malformed, consumed);
  720. return false;
  721. }
  722. update.tailBits = static_cast<std::uint32_t>(reader.remaining_bits() + 1);
  723. if (root != 0) {
  724. Reader rootBody(reader, reader.remaining_bits(), total);
  725. if (!consume_root_sense(rootBody)) {
  726. finish(update, reader, total, DecodeStatus::malformed, consumed);
  727. return false;
  728. }
  729. }
  730. bool partial = false;
  731. for (;;) {
  732. std::uint64_t groupPresent = 0;
  733. if (!reader.read(1, groupPresent)) {
  734. finish(update, reader, total, DecodeStatus::malformed, consumed);
  735. return false;
  736. }
  737. if (groupPresent == 0) {
  738. break;
  739. }
  740. std::uint64_t groupKey = 0, groupBits = 0;
  741. if (!reader.read(32, groupKey) || !reader.read(32, groupBits)
  742. || groupBits > kGroupByteCapacity * 8 || groupBits > reader.remaining_bits()) {
  743. finish(update, reader, total, DecodeStatus::malformed, consumed);
  744. return false;
  745. }
  746. ++update.decoded.groupsSeen;
  747. GroupTarget group{};
  748. const TargetStatus groupStatus =
  749. resolver.resolveGroup == nullptr
  750. ? TargetStatus::targetUnavailable
  751. : resolver.resolveGroup(
  752. resolver.context, static_cast<std::uint32_t>(groupKey), group);
  753. Reader body(reader, static_cast<std::size_t>(groupBits), total);
  754. if (groupStatus != TargetStatus::resolved) {
  755. if (!skip_group(body)) {
  756. finish(update, reader, total, DecodeStatus::malformed, consumed);
  757. return false;
  758. }
  759. ++update.decoded.groupsSkipped;
  760. partial = true;
  761. continue;
  762. }
  763. bool skipped = false, hasObject = false;
  764. while (!skipped) {
  765. std::uint64_t objectPresent = 0;
  766. if (!body.read(1, objectPresent)) {
  767. finish(update, reader, total, DecodeStatus::malformed, consumed);
  768. return false;
  769. }
  770. if (objectPresent == 0) {
  771. if (!hasObject || body.left() != 0) {
  772. finish(update, reader, total, DecodeStatus::malformed, consumed);
  773. return false;
  774. }
  775. ++update.decoded.groupsDecoded;
  776. break;
  777. }
  778. hasObject = true;
  779. ++update.decoded.objectsSeen;
  780. std::uint64_t objectKey = 0, typeRaw = 0, indexRaw = 0;
  781. if (!body.read(kKeyWidth, objectKey) || objectKey != groupKey
  782. || !body.read(kTypeWidth, typeRaw) || typeRaw < kTypeBias
  783. || !body.read(kIndexWidth, indexRaw) || indexRaw < kIndexBias) {
  784. finish(update, reader, total, DecodeStatus::malformed, consumed);
  785. return false;
  786. }
  787. const auto type = static_cast<std::uint8_t>(typeRaw - kTypeBias);
  788. const auto index = static_cast<std::uint16_t>(indexRaw - kIndexBias);
  789. if (!update.hasFirstObject) {
  790. update.firstGroupBits = static_cast<std::uint32_t>(groupBits);
  791. update.firstRegistryKey = static_cast<std::uint32_t>(groupKey);
  792. update.firstSlotType = type;
  793. update.firstSlotIndex = index;
  794. update.hasFirstObject = true;
  795. }
  796. DecodedObject* retained = nullptr;
  797. if (update.decoded.objectCount < update.decoded.objects.size()) {
  798. retained = &update.decoded.objects[update.decoded.objectCount++];
  799. retained->registryKey = static_cast<std::uint32_t>(groupKey);
  800. retained->objectTag = group.objectTag;
  801. retained->objectRow = group.objectRow;
  802. retained->slotType = type;
  803. retained->slotIndex = index;
  804. retained->firstValue = static_cast<std::uint32_t>(update.decoded.valueCount);
  805. } else {
  806. update.decoded.objectsTruncated = true;
  807. }
  808. SlotTarget slot{};
  809. const TargetStatus slotStatus =
  810. resolver.resolveSlot == nullptr
  811. ? TargetStatus::targetUnavailable
  812. : resolver.resolveSlot(resolver.context, group, type, index, slot);
  813. if (retained != nullptr) {
  814. retained->slotRow = slot.slotRow;
  815. retained->senseSchema = slot.senseSchema;
  816. retained->schemaRow = slot.senseSchema;
  817. }
  818. if (slotStatus != TargetStatus::resolved) {
  819. if (retained != nullptr) {
  820. retained->status = slotStatus == TargetStatus::schemaUnavailable
  821. ? ObjectStatus::schemaUnavailable
  822. : ObjectStatus::targetUnavailable;
  823. }
  824. if (!skip_group(body)) {
  825. finish(update, reader, total, DecodeStatus::malformed, consumed);
  826. return false;
  827. }
  828. skipped = true;
  829. partial = true;
  830. ++update.decoded.groupsSkipped;
  831. continue;
  832. }
  833. const std::size_t start = body.position();
  834. Values values(update.decoded, retained);
  835. const NativeStatus status = decode_body(slot.senseSchema, body, values);
  836. if (retained != nullptr) {
  837. retained->deltaBits = static_cast<std::uint32_t>(body.position() - start);
  838. retained->valueCount =
  839. static_cast<std::uint32_t>(update.decoded.valueCount - retained->firstValue);
  840. retained->status = status == NativeStatus::complete ? ObjectStatus::decoded
  841. : status == NativeStatus::unsafeCount ? ObjectStatus::unsafeCount
  842. : status == NativeStatus::unsupported
  843. ? ObjectStatus::unsupportedField
  844. : ObjectStatus::malformed;
  845. }
  846. if (status == NativeStatus::malformed) {
  847. finish(update, reader, total, DecodeStatus::malformed, consumed);
  848. return false;
  849. }
  850. if (status != NativeStatus::complete) {
  851. if (!skip_group(body)) {
  852. finish(update, reader, total, DecodeStatus::malformed, consumed);
  853. return false;
  854. }
  855. skipped = true;
  856. partial = true;
  857. ++update.decoded.groupsSkipped;
  858. continue;
  859. }
  860. std::uint64_t generation = 0;
  861. if (!body.read(32, generation)) {
  862. finish(update, reader, total, DecodeStatus::malformed, consumed);
  863. return false;
  864. }
  865. if (retained != nullptr) {
  866. retained->generationPlusOne = static_cast<std::uint32_t>(generation);
  867. retained->hasGeneration = true;
  868. retained->status = ObjectStatus::decoded;
  869. }
  870. ++update.decoded.objectsDecoded;
  871. }
  872. }
  873. std::uint64_t tail = 0;
  874. if (!reader.read(1, tail) || tail != 0 || reader.remaining_bits() > 7) {
  875. finish(update, reader, total, DecodeStatus::malformed, consumed);
  876. return false;
  877. }
  878. update.decoded.paddingBits = static_cast<std::uint8_t>(reader.remaining_bits());
  879. std::uint64_t padding = 0;
  880. if (!reader.read(update.decoded.paddingBits, padding) || padding != 0) {
  881. finish(update, reader, total, DecodeStatus::malformed, consumed);
  882. return false;
  883. }
  884. finish(
  885. update, reader, total, partial ? DecodeStatus::partial : DecodeStatus::complete, consumed);
  886. return true;
  887. }
  888. /** @return Stable log spelling for one packet decode status. */
  889. const char* decode_status_name(DecodeStatus status) noexcept {
  890. switch (status) {
  891. case DecodeStatus::complete:
  892. return "complete";
  893. case DecodeStatus::partial:
  894. return "partial";
  895. case DecodeStatus::schemaUnavailable:
  896. return "unsupported_native_layout";
  897. case DecodeStatus::malformed:
  898. return "malformed";
  899. }
  900. return "unknown";
  901. }
  902. /** @return Stable log spelling for one object decode status. */
  903. const char* object_status_name(ObjectStatus status) noexcept {
  904. switch (status) {
  905. case ObjectStatus::decoded:
  906. return "decoded";
  907. case ObjectStatus::targetUnavailable:
  908. return "target_unavailable";
  909. case ObjectStatus::schemaUnavailable:
  910. case ObjectStatus::unsupportedField:
  911. return "unsupported_native_layout";
  912. case ObjectStatus::unsafeCount:
  913. return "unsafe_count";
  914. case ObjectStatus::malformed:
  915. return "malformed";
  916. }
  917. return "unknown";
  918. }
  919. } // namespace sunrise::middleware::bap::activity_message::sense_update