combatant_path_test.cpp 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. #include "../Sunrise/src/middleware/bap/activity_message/squad_objective_auth.h"
  2. #include <cassert>
  3. #include <array>
  4. #include <string_view>
  5. #include "../Sunrise/src/middleware/bap/activity_message/combatant_path_auth.h"
  6. #include "../Sunrise/src/middleware/bap/activity_message/combatant_delivery_auth.h"
  7. #include "../Sunrise/src/middleware/bap/activity_message/combatant_retire_auth.h"
  8. #include "../Sunrise/src/middleware/bap/activity_message/squad_auth_body.h"
  9. #include "../Sunrise/src/server/activity/mission/mission_script_actor_path_sense.h"
  10. namespace sense = sunrise::middleware::bap::activity_message::sense_update;
  11. namespace {
  12. sense::TargetStatus group(const void*, std::uint32_t key, sense::GroupTarget& out) noexcept {
  13. if (key != 0xF6FFB59E) return sense::TargetStatus::targetUnavailable;
  14. out.objectTag = 0x80B3CB5E;
  15. return sense::TargetStatus::resolved;
  16. }
  17. sense::TargetStatus slot(const void*, const sense::GroupTarget&, std::uint8_t type,
  18. std::uint16_t index, sense::SlotTarget& out) noexcept {
  19. if (type != 2 || index != 22) return sense::TargetStatus::targetUnavailable;
  20. out.senseSchema = 0x80807DA2;
  21. return sense::TargetStatus::resolved;
  22. }
  23. void packet_regression() {
  24. namespace delivery = sunrise::middleware::bap::activity_message::combatant_delivery;
  25. std::array<delivery::SquadReference,2> manifest{{{0xf6ffb59e,23},{0xf6ffb59e,25}}};
  26. std::array<std::byte,delivery::kMaxBytes> manifestBody{};
  27. std::size_t manifestBytes{}, manifestBits{};
  28. assert(delivery::encode_many(1,1,manifest,manifestBody,manifestBytes,manifestBits));
  29. assert(manifestBits==187 && manifestBytes==24);
  30. assert(delivery::validate(std::span(manifestBody).first(manifestBytes),manifestBits));
  31. manifest[1]=manifest[0];
  32. assert(!delivery::encode_many(1,1,manifest,manifestBody,manifestBytes,manifestBits));
  33. assert(!delivery::encode_many(1,1,{},manifestBody,manifestBytes,manifestBits));
  34. using namespace sunrise::server::activity::mission;
  35. // Independent complete msg-6 packets: initial movement cursor, delivery start,
  36. // delivery stop with absent movement fields, then real movement completion.
  37. constexpr std::array<std::string_view, 4> fixtures{
  38. "000000000000000000000000000000003edff6b3c0000019df6ffb59e07002d800000013020000000440000000210000000300",
  39. "000000000000000000000000000000003edff6b3c0000010df6ffb59e07002d040000000c10000000300",
  40. "000000000000000000000000000000003edff6b3c000000cff6ffb59e07002d0108000000180",
  41. "000000000000000000000000000000003edff6b3c00000121f6ffb59e07002d183000000020840000000c0",
  42. };
  43. const sense::Resolver resolver{nullptr, &group, &slot};
  44. ActorPathLevel level{};
  45. for (std::size_t i=0;i<fixtures.size();++i) {
  46. std::array<std::byte, 51> bytes{};
  47. auto nibble = [](char c) { return c <= '9' ? c-'0' : c-'a'+10; };
  48. const auto size = fixtures[i].size()/2;
  49. for (std::size_t j=0;j<size;++j)
  50. bytes[j] = std::byte((nibble(fixtures[i][j*2])<<4) | nibble(fixtures[i][j*2+1]));
  51. sense::SenseUpdate decoded{}; std::size_t consumed{};
  52. assert(sense::decode_sense_update(std::span(bytes).first(size), resolver, decoded, consumed));
  53. assert(decoded.decoded.status == sense::DecodeStatus::complete && consumed == size*8);
  54. assert(decoded.decoded.objectCount == 1);
  55. const auto& object = decoded.decoded.objects[0];
  56. assert(object.status == sense::ObjectStatus::decoded && object.generationPlusOne == 3);
  57. const auto fields = std::span(decoded.decoded.values).subspan(object.firstValue, object.valueCount);
  58. assert(update_actor_path_level(level, fields, object.schemaRow));
  59. assert(level.generation == 1 && level.revision == 1 && !level.dead);
  60. assert(level.state == (i == 3 ? 1 : 0)); // Delivery cannot fake a completed flight.
  61. assert(level.deliveryRevision == (i == 0 ? 0 : 1));
  62. assert(level.deliveryState == (i == 1 ? 1 : 0));
  63. assert(!update_actor_path_level(level, fields, object.schemaRow));
  64. assert(!sense::decode_sense_update(std::span(bytes).first(size-1), resolver, decoded, consumed));
  65. }
  66. }
  67. void reservation_regression() {
  68. namespace squad = sunrise::middleware::bap::activity_message::squad_auth;
  69. const std::array<std::int32_t, 2> counts{3,1};
  70. squad::Preset request{counts,1,squad::Mode::reserve};
  71. std::array<std::byte, squad::kMaximumByteCount> bytes{};
  72. std::size_t written{}, bits{};
  73. assert(squad::encode(request,{},bytes,written,bits));
  74. assert(bits == squad::exact_body_bit_count(2));
  75. sunrise::middleware::encoding::bits::Reader reader{std::span(bytes).first(written)};
  76. std::uint64_t mode{};
  77. assert(reader.skip(bits-36) && reader.read(3,mode) && mode==4); // biased mode 3
  78. const auto original = bytes;
  79. request.mode = static_cast<squad::Mode>(4);
  80. assert(!squad::encode(request,{},bytes,written,bits) && bytes == original);
  81. }
  82. }
  83. int main() {
  84. packet_regression();
  85. reservation_regression();
  86. namespace objective = sunrise::middleware::bap::activity_message::squad_objective;
  87. std::array<std::byte, objective::kBytes> objectiveBytes{};
  88. assert(objective::encode({0xd8ce8390, 1, 0, -1}, objectiveBytes));
  89. constexpr std::array<unsigned,20> objectiveFixture{0xec,0x67,0x41,0xc8,0x4,0x80,0x0,0x0,0x8,0x0,0x0,0x0,0x14,0x8,0x13,0xc0,0x8e,0x4e,0xe2,0x80};
  90. for (unsigned i=0;i<20;++i) assert(std::to_integer<unsigned>(objectiveBytes[i]) == objectiveFixture[i]);
  91. assert(objective::validate(objectiveBytes,153));
  92. assert(objective::encode({0xd8ce8390,1,0,3,true},objectiveBytes));
  93. assert(objective::validate(objectiveBytes,153));
  94. sunrise::middleware::encoding::bits::Reader objectiveReader(objectiveBytes);
  95. std::uint64_t mode{};
  96. assert(objectiveReader.skip(objective::kBits-36) && objectiveReader.read(3,mode) && mode==4);
  97. assert(objective::encode({0xd8ce8390,1,0,23},objectiveBytes));
  98. assert(objective::validate(objectiveBytes,153));
  99. assert(!objective::encode({0xd8ce8390,1,0,24},objectiveBytes));
  100. assert(!objective::encode({0xd8ce8390,1,0,-2},objectiveBytes));
  101. assert(!objective::encode({0xd8ce8390,0,0,-1},objectiveBytes));
  102. objectiveBytes.back() |= std::byte{1}; assert(!objective::validate(objectiveBytes,153));
  103. namespace path = sunrise::middleware::bap::activity_message::combatant_path;
  104. std::array<std::byte, path::kBytes> bytes{};
  105. assert(path::encode({1, 1, 0xf6ffb59e, 115}, bytes));
  106. constexpr std::array<unsigned, 20> expected{0x80,0x0,0x0,0x1,0x4c,0x80,0x0,0x0,0x1,0x0,0x1a,0x3e,0xdf,0xf6,0xb3,0xce,0xe0,0x1c,0xc0,0x60};
  107. for (unsigned i = 0; i < bytes.size(); ++i) assert(std::to_integer<unsigned>(bytes[i]) == expected[i]);
  108. assert(path::validate(bytes, 156));
  109. auto atStart = bytes;
  110. atStart.back() &= ~std::byte{0x40};
  111. assert(!path::validate(atStart, 156)); // marker 0 parks at the entrance instead of unloading
  112. bytes.back() |= std::byte{1}; assert(!path::validate(bytes, 156));
  113. assert(!path::encode({0, 1, 1, 115}, bytes));
  114. assert(!path::encode({1, 0, 1, 115}, bytes));
  115. assert(!path::encode({1, 1, 1, 32768}, bytes));
  116. assert(!path::encode({1, 1, 1, 115}, std::span(bytes).first(19)));
  117. namespace retire = sunrise::middleware::bap::activity_message::combatant_retire;
  118. std::array<std::byte, retire::kBytes> disabled{};
  119. assert(retire::encode(2,disabled) && retire::validate(disabled,77));
  120. const std::array<std::byte,10> retiredFixture{std::byte{0x80},std::byte{0},std::byte{0},std::byte{2},std::byte{0x48},std::byte{0x40},std::byte{0},std::byte{0},std::byte{0},std::byte{0x10}};
  121. assert(disabled == retiredFixture);
  122. disabled[4] |= std::byte{4}; // Enabled actors cannot pass as retired.
  123. assert(!retire::validate(disabled,77));
  124. assert(!retire::encode(0,disabled));
  125. assert(!retire::encode(0x80000000,disabled));
  126. namespace delivery = sunrise::middleware::bap::activity_message::combatant_delivery;
  127. std::array<std::byte, delivery::kBytes> cargo{};
  128. assert(delivery::encode({1,1,0xf6ffb59e,23},cargo));
  129. constexpr std::array<unsigned,17> deliveryFixture{
  130. 0x80,0,0,1,0x4c,0x47,0xdb,0xfe,0xd6,0x78,0x14,0x00,0xb8,0,0,0,0x10};
  131. for (unsigned i=0;i<cargo.size();++i) assert(std::to_integer<unsigned>(cargo[i]) == deliveryFixture[i]);
  132. assert(delivery::validate(cargo,132));
  133. assert(!path::validate(cargo,132) && !delivery::validate(bytes,156));
  134. cargo[10] |= std::byte{0x08}; // A non-squad ClientRef must be rejected.
  135. assert(!delivery::validate(cargo,132));
  136. assert(!delivery::encode({1,1,1,32768},cargo));
  137. assert(!delivery::encode({1,0,1,23},cargo));
  138. assert(!delivery::encode({0,1,1,23},cargo));
  139. using namespace sunrise::server::activity::mission;
  140. using sunrise::middleware::bap::activity_message::sense_update::DecodedValue;
  141. std::array<DecodedValue, 4> fields{};
  142. const unsigned ordinals[]{0, 1, 0, 10};
  143. for (unsigned i = 0; i < 4; ++i) { fields[i].schemaRow = 10; fields[i].fieldOrdinal = ordinals[i]; }
  144. fields[1].schemaRow = fields[2].schemaRow = 0x80807F6E;
  145. fields[0].signedValue = fields[1].signedValue = 1;
  146. ActorPathLevel level{};
  147. assert(!update_actor_path_level(level, std::span(fields).first(2), 10));
  148. assert(update_actor_path_level(level, std::span(fields).subspan(2), 10));
  149. assert(level.generation == 1 && level.revision == 1 && level.state == 0 && !level.dead);
  150. assert(!update_actor_path_level(level, fields, 10));
  151. fields[0].present = fields[1].present = false; fields[2].signedValue = 1;
  152. assert(update_actor_path_level(level, fields, 10) && level.revision == 1 && level.state == 1);
  153. fields[3].unsignedValue = 1;
  154. assert(update_actor_path_level(level, fields, 10) && level.dead);
  155. }