| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300 |
- #include <array>
- #include <cstdio>
- #include "../../../../../core/logging/log.h"
- #include "../../queuez/queuez_state_validation.h"
- #include "../snapshot/internal.h"
- #include "queuez_push_reporting.h"
- #include "queuez_update_frame.h"
- namespace sunrise::server::bap::encrypted::push {
- /**
- * Appends the opcode-504 Family-4 move as one increment above the peer's current version.
- * @param scratch Lock-owned transform buffers.
- * @param select Staged after-image, object definitions, and both character keys.
- * @param key Active AES-GCM session key.
- * @param nonce Push-direction nonce after the correlated svc-11 response.
- * @param response Caller-owned output containing the existing response prefix.
- * @param written Existing byte count, updated after the complete push is appended.
- * @return True when the 3 object operations and the whole svc-123 frame fit.
- */
- bool append_select_character_notification(Scratch& scratch,
- const queuez::SelectCharacter& select,
- std::span<const std::byte, state::kAesKeySize> key,
- std::span<const std::byte, state::kBapNonceSize> nonce,
- std::span<std::byte> response,
- std::size_t& written) noexcept {
- snapshot::Prepared prepared{};
- if (!snapshot::prepare_selection_move(scratch, select, prepared)) {
- return false;
- }
- const std::size_t objectCount = prepared.family.objects.size();
- const std::size_t beforeBytes = written;
- if (!queuez_frame::append(scratch,
- prepared.family,
- prepared.rawClearSize,
- prepared.compressedClearSize,
- key,
- nonce,
- response,
- written)) {
- return false;
- }
- queuez_report::push(
- "select", queuez::kAccountFamilyType, objectCount, written - beforeBytes, 1);
- return true;
- }
- /** Appends the opcode-403 character upsert as one increment above the current peer version. */
- bool append_equipment_swap_notification(Scratch& scratch,
- const queuez::EquipmentSwap& swap,
- const state::PendingEquipmentSwap& mutation,
- std::span<const std::byte, state::kAesKeySize> key,
- std::span<const std::byte, state::kBapNonceSize> nonce,
- std::span<std::byte> response,
- std::size_t& written) noexcept {
- snapshot::Prepared prepared{};
- if (!snapshot::prepare_equipment_swap(scratch, swap, mutation, prepared)) {
- return false;
- }
- const std::size_t objectCount = prepared.family.objects.size();
- if (objectCount == 1) {
- const middleware::queuez::Object& object = prepared.family.objects.front();
- std::array<char, core::log::kLineCapacity> line{};
- const int count =
- std::snprintf(line.data(),
- line.size(),
- "ev=equip stage=queuez_object result=ok family_version=%d object_id=%u "
- "object_version=0x%llX encoding=%u payload_bytes=%zu",
- prepared.family.version,
- object.id,
- static_cast<unsigned long long>(object.version),
- static_cast<unsigned>(object.encoding),
- object.payload.size());
- if (count > 0) {
- core::log::write(core::log::Channel::server,
- core::log::Level::debug,
- {line.data(), static_cast<std::size_t>(count)});
- }
- }
- const std::size_t beforeBytes = written;
- if (!queuez_frame::append(scratch,
- prepared.family,
- prepared.rawClearSize,
- prepared.compressedClearSize,
- key,
- nonce,
- response,
- written)) {
- return false;
- }
- queuez_report::push("equip", queuez::kAccountFamilyType, objectCount, written - beforeBytes, 1);
- return true;
- }
- /** Appends one opcode-406 selected-character item-state upsert. */
- bool append_item_state_notification(Scratch& scratch,
- const queuez::EquipmentSwap& update,
- const state::PendingItemState& mutation,
- std::span<const std::byte, state::kAesKeySize> key,
- std::span<const std::byte, state::kBapNonceSize> nonce,
- std::span<std::byte> response,
- std::size_t& written) noexcept {
- snapshot::Prepared prepared{};
- if (!snapshot::prepare_item_state(scratch, update, mutation, prepared)) {
- return false;
- }
- const std::size_t objectCount = prepared.family.objects.size();
- const std::size_t beforeBytes = written;
- if (objectCount != 1 || prepared.family.objects.front().id != update.characterDefinitionId
- || prepared.family.objects.front().version != update.characterSoid
- || prepared.family.objects.front().encoding != middleware::queuez::Encoding::oodle
- || prepared.family.objects.front().payload.empty()
- || !queuez_frame::append(scratch,
- prepared.family,
- prepared.rawClearSize,
- prepared.compressedClearSize,
- key,
- nonce,
- response,
- written)) {
- return false;
- }
- queuez_report::push(
- "item_state", queuez::kAccountFamilyType, objectCount, written - beforeBytes, 1);
- return true;
- }
- /** Appends one socket item upsert and its charged account balances when required. */
- bool append_socket_plug_notification(Scratch& scratch,
- const queuez::SocketPlug& socketPlug,
- const state::PendingSocketPlug& mutation,
- std::span<const std::byte, state::kAesKeySize> key,
- std::span<const std::byte, state::kBapNonceSize> nonce,
- std::span<std::byte> response,
- std::size_t& written) noexcept {
- snapshot::Prepared prepared{};
- if (!snapshot::prepare_socket_plug(scratch, socketPlug, mutation, prepared)) {
- return false;
- }
- const std::size_t objectCount = prepared.family.objects.size();
- const std::size_t expectedObjectCount = socketPlug.updatesAccount ? 2U : 1U;
- const std::size_t beforeBytes = written;
- if (objectCount != expectedObjectCount
- || prepared.family.objects.front().id != socketPlug.itemInstanceDefinitionId
- || prepared.family.objects.front().version != socketPlug.targetInstanceSoid
- || prepared.family.objects.front().encoding != middleware::queuez::Encoding::oodle
- || prepared.family.objects.front().payload.empty()
- || (socketPlug.updatesAccount
- && (prepared.family.objects[1].id != socketPlug.accountDefinitionId
- || prepared.family.objects[1].version != socketPlug.accountSoid
- || prepared.family.objects[1].encoding != middleware::queuez::Encoding::oodle
- || prepared.family.objects[1].payload.empty()))
- || !queuez_frame::append(scratch,
- prepared.family,
- prepared.rawClearSize,
- prepared.compressedClearSize,
- key,
- nonce,
- response,
- written)) {
- return false;
- }
- queuez_report::push(
- "socket_plug", queuez::kAccountFamilyType, objectCount, written - beforeBytes, 1);
- return true;
- }
- /** Appends one atomic new-instance-before-character Family-4 acquisition update. */
- bool append_item_acquisition_notification(Scratch& scratch,
- const queuez::ItemAcquisition& acquisition,
- const state::PendingItemAcquisition& mutation,
- std::span<const std::byte, state::kAesKeySize> key,
- std::span<const std::byte, state::kBapNonceSize> nonce,
- std::span<std::byte> response,
- std::size_t& written) noexcept {
- snapshot::Prepared prepared{};
- if (!snapshot::prepare_item_acquisition(scratch, acquisition, mutation, prepared)) {
- return false;
- }
- const std::size_t objectCount = prepared.family.objects.size();
- const std::size_t beforeBytes = written;
- const std::size_t expectedObjectCount = acquisition.updatesAccount ? 3U : 2U;
- if (objectCount != expectedObjectCount
- || prepared.family.objects[0].id != acquisition.itemInstanceDefinitionId
- || prepared.family.objects[0].version != acquisition.acquiredInstanceSoid
- || prepared.family.objects[0].encoding != middleware::queuez::Encoding::oodle
- || prepared.family.objects[0].payload.empty()
- || prepared.family.objects[1].id != acquisition.characterDefinitionId
- || prepared.family.objects[1].version != acquisition.characterSoid
- || prepared.family.objects[1].encoding != middleware::queuez::Encoding::oodle
- || prepared.family.objects[1].payload.empty()
- || (acquisition.updatesAccount
- && (prepared.family.objects[2].id != acquisition.accountDefinitionId
- || prepared.family.objects[2].version != acquisition.accountSoid
- || prepared.family.objects[2].encoding != middleware::queuez::Encoding::oodle
- || prepared.family.objects[2].payload.empty()))
- || !queuez_frame::append(scratch,
- prepared.family,
- prepared.rawClearSize,
- prepared.compressedClearSize,
- key,
- nonce,
- response,
- written)) {
- return false;
- }
- queuez_report::push(
- "acquire", queuez::kAccountFamilyType, objectCount, written - beforeBytes, 1);
- return true;
- }
- /** Appends an optional new profile resident followed by the full account after-image. */
- bool append_profile_item_acquisition_notification(
- Scratch& scratch,
- const queuez::ProfileItemAcquisition& acquisition,
- const state::PendingProfileItemAcquisition& mutation,
- std::span<const std::byte, state::kAesKeySize> key,
- std::span<const std::byte, state::kBapNonceSize> nonce,
- std::span<std::byte> response,
- std::size_t& written) noexcept {
- snapshot::Prepared prepared{};
- if (!snapshot::prepare_profile_item_acquisition(scratch, acquisition, mutation, prepared)) {
- return false;
- }
- const std::size_t objectCount = prepared.family.objects.size();
- const std::size_t beforeBytes = written;
- const std::size_t expectedObjectCount = acquisition.appendedResident ? 2U : 1U;
- const std::size_t accountIndex = acquisition.appendedResident ? 1U : 0U;
- if (prepared.family.type != queuez::kAccountFamilyType
- || prepared.family.rootSoid != acquisition.after.family4RootSoid
- || prepared.family.version != acquisition.after.family4Version || prepared.family.flags != 0
- || objectCount != expectedObjectCount || accountIndex >= objectCount
- || prepared.family.objects[accountIndex].id != acquisition.accountDefinitionId
- || prepared.family.objects[accountIndex].version != acquisition.accountSoid
- || prepared.family.objects[accountIndex].encoding != middleware::queuez::Encoding::oodle
- || prepared.family.objects[accountIndex].payload.empty()
- || (acquisition.appendedResident
- && (prepared.family.objects.front().id != acquisition.itemInstanceDefinitionId
- || prepared.family.objects.front().version != acquisition.acquiredInstanceSoid
- || prepared.family.objects.front().encoding != middleware::queuez::Encoding::oodle
- || prepared.family.objects.front().payload.empty()))
- || !queuez_frame::append(scratch,
- prepared.family,
- prepared.rawClearSize,
- prepared.compressedClearSize,
- key,
- nonce,
- response,
- written)) {
- return false;
- }
- queuez_report::push(
- "profile_acquire", queuez::kAccountFamilyType, objectCount, written - beforeBytes, 1);
- return true;
- }
- /** Appends one atomic dismantle update, including any account-wide material payout. */
- bool append_item_dismantle_notification(Scratch& scratch,
- const queuez::ItemDismantle& dismantle,
- const state::PendingItemDismantle& mutation,
- std::span<const std::byte, state::kAesKeySize> key,
- std::span<const std::byte, state::kBapNonceSize> nonce,
- std::span<std::byte> response,
- std::size_t& written) noexcept {
- snapshot::Prepared prepared{};
- if (!snapshot::prepare_item_dismantle(scratch, dismantle, mutation, prepared)) {
- return false;
- }
- const std::size_t objectCount = prepared.family.objects.size();
- const std::size_t beforeBytes = written;
- const std::size_t expectedObjectCount = dismantle.updatesAccount ? 3U : 2U;
- if (objectCount != expectedObjectCount
- || prepared.family.objects[0].id != dismantle.characterDefinitionId
- || prepared.family.objects[0].version != dismantle.characterSoid
- || prepared.family.objects[1].id != dismantle.itemInstanceDefinitionId
- || prepared.family.objects[1].version != dismantle.dismantledInstanceSoid
- || prepared.family.objects[1].encoding != middleware::queuez::Encoding::oodle
- || !prepared.family.objects[1].payload.empty()
- || (dismantle.updatesAccount
- && (prepared.family.objects[2].id != dismantle.accountDefinitionId
- || prepared.family.objects[2].version != dismantle.accountSoid
- || prepared.family.objects[2].encoding != middleware::queuez::Encoding::oodle
- || prepared.family.objects[2].payload.empty()))
- || !queuez_frame::append(scratch,
- prepared.family,
- prepared.rawClearSize,
- prepared.compressedClearSize,
- key,
- nonce,
- response,
- written)) {
- return false;
- }
- queuez_report::push(
- "dismantle", queuez::kAccountFamilyType, objectCount, written - beforeBytes, 1);
- return true;
- }
- } // namespace sunrise::server::bap::encrypted::push
|