| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150 |
- #include <algorithm>
- #include <array>
- #include <bit>
- #include <cassert>
- #include <cstddef>
- #include <cstdint>
- #include <iostream>
- #include <vector>
- #include "../Sunrise/src/middleware/bap/activity_message/cinematic_incident.h"
- #include "../Sunrise/src/middleware/bap/activity_message/incident.h"
- #include "../Sunrise/src/middleware/bap/activity_message/player_trigger_incident.h"
- #include "../Sunrise/src/server/activity/mission/mission_script_cinematic.h"
- namespace incident = sunrise::middleware::bap::activity_message::incident;
- namespace cinematic = sunrise::middleware::bap::activity_message::cinematic_incident;
- namespace trigger = sunrise::middleware::bap::activity_message::player_trigger_incident;
- namespace bits = sunrise::middleware::encoding::bits;
- namespace resolver = sunrise::server::activity::mission::cinematic;
- namespace catalog = sunrise::state::build_data::scriptables;
- static std::vector<std::byte> encode(const incident::Incident& input) {
- std::vector<std::byte> bytes(incident::kMaximumBodyBytes);
- bits::Writer writer(bytes);
- assert(incident::write(writer, input));
- std::size_t size = 0;
- assert(writer.finish(size));
- bytes.resize(size);
- return bytes;
- }
- static void round_trip_fields() {
- // Extra targets move the selector/payload across every possible byte alignment.
- for (unsigned extras = 0; extras < 8; ++extras) {
- for (bool selector : {false, true}) {
- for (bool optional : {false, true}) {
- incident::Incident input{};
- input.primaryTarget = cinematic::kTerminatedTarget;
- input.extraTargetCount = extras;
- for (unsigned i = 0; i < extras; ++i)
- input.extraTargets[i] = 100 + i;
- input.hasCompressedSelector = selector;
- input.selectorLength = selector ? incident::kSelectorMaximum : 0;
- for (unsigned i = 0; i < input.selectorLength; ++i)
- input.selector[i] = static_cast<std::byte>((i * 19 + 7) & 255);
- input.hasOptionalBlock = optional;
- input.optionalWordA = optional ? 0xFEDCBA98U : 0;
- input.optionalWordB = optional ? 0x76543210U : 0;
- input.payloadLength = incident::kPayloadMaximum;
- for (unsigned i = 0; i < input.payloadLength; ++i)
- input.payload[i] = static_cast<std::byte>((i * 37 + 13) & 255);
- const auto encoded = encode(input);
- incident::Incident parsed{};
- assert(incident::validate(encoded, parsed) == incident::Verdict::accepted);
- assert(parsed.hasCompressedSelector == selector
- && parsed.hasOptionalBlock == optional);
- assert(parsed.selector == input.selector && parsed.payload == input.payload);
- assert(parsed.optionalWordA == input.optionalWordA
- && parsed.optionalWordB == input.optionalWordB);
- assert(parsed.hasPayload && parsed.payloadLength == input.payloadLength);
- assert(encode(parsed) == encoded);
- for (std::size_t size = 0; size < encoded.size(); ++size)
- assert(incident::validate(std::span(encoded).first(size), parsed)
- == incident::Verdict::truncated);
- }
- }
- }
- incident::Incident empty{};
- empty.primaryTarget = 100;
- empty.hasCompressedSelector = true; // Presence is distinct from a nonzero length.
- incident::Incident parsed{};
- assert(incident::validate(encode(empty), parsed) == incident::Verdict::accepted);
- assert(parsed.hasCompressedSelector && !parsed.hasPayload && parsed.payloadLength == 0);
- }
- static void cinematic_handoff() {
- constexpr std::uint32_t registry = 0x91EAC345U;
- constexpr std::uint64_t runtime = 0x123456789ABCDEF0ULL;
- std::array<std::byte, cinematic::kPayloadBytes> body{};
- bits::Writer writer(body);
- for (unsigned i = 0; i < 5; ++i)
- assert(writer.write(0xABABABABABABABABULL, 64));
- assert(writer.write(0x1234, 15)); // 335 bits of schema prefix.
- assert(writer.write(registry, 32));
- assert(writer.write(6 + 1, 7));
- assert(writer.write(32768, 16)); // Authored slot zero.
- assert(writer.write(runtime, 64));
- assert(writer.write(std::bit_cast<std::uint32_t>(1.0F), 32));
- std::size_t size = 0;
- assert(writer.finish(size) && size == body.size());
- catalog::Snapshot world{};
- catalog::Object object{};
- object.registryKey = registry;
- object.objectTag = 0x81234567U;
- object.stateRow = 3; // Alternate-state identity must survive the event path.
- world.objects.push_back(object);
- catalog::Slot slot{};
- slot.slotType = 6;
- world.slots.push_back(slot);
- for (const auto target : {cinematic::kStartedTarget, cinematic::kTerminatedTarget, cinematic::kSkipTarget}) {
- cinematic::Signal signal{};
- assert(cinematic::signal_for_target(target, signal));
- if (target == cinematic::kSkipTarget) assert(signal == cinematic::Signal::skipRequested);
- incident::Incident input{};
- input.primaryTarget = target;
- input.payloadLength = body.size();
- std::copy(body.begin(), body.end(), input.payload.begin());
- incident::Incident parsed{};
- assert(incident::validate(encode(input), parsed) == incident::Verdict::accepted);
- cinematic::Payload movie{};
- assert(cinematic::decode(std::span(parsed.payload).first(parsed.payloadLength), movie));
- assert(movie.registryKey == registry && movie.slotType == 6 && movie.slotIndex == 0);
- assert(movie.runtimeObjectId == runtime && movie.eventValue == 1.0F);
- resolver::Source source{};
- assert(resolver::resolve(world, movie, source) == resolver::ResolveStatus::ready);
- assert(source.registryKey == registry && source.objectTag == object.objectTag);
- movie.registryKey ^= 1;
- assert(resolver::resolve(world, movie, source) == resolver::ResolveStatus::absent);
- }
- }
- static void player_trigger_payload() {
- incident::Incident input{};
- input.primaryTarget = trigger::kPrimaryTarget;
- input.payloadLength = trigger::kPayloadBytes;
- bits::Writer writer(std::span(input.payload).first(input.payloadLength));
- for (unsigned i = 0; i < 5; ++i)
- assert(writer.write(0, 64));
- assert(writer.write(0, 15));
- assert(writer.write(0x87654321, 32));
- assert(writer.write(32, 7)); // Type 31 plus bias.
- assert(writer.write(32768 + 70, 16));
- assert(writer.write(0x10203040, 32));
- std::size_t size = 0;
- assert(writer.finish(size) && size == input.payloadLength);
- incident::Incident parsed{};
- assert(incident::validate(encode(input), parsed) == incident::Verdict::accepted);
- trigger::Payload decoded{};
- assert(trigger::decode(std::span(parsed.payload).first(parsed.payloadLength), decoded));
- assert(decoded.registryKey == 0x87654321 && decoded.slotType == 31 && decoded.slotIndex == 70);
- assert(decoded.resolvedObjectId == 0x10203040);
- }
- int main() {
- round_trip_fields();
- cinematic_handoff();
- player_trigger_payload();
- std::cout << "Incident retention, truncation, cinematic resolution and player-trigger decoding "
- "passed\n";
- }
|