actor_entity_registry.cpp 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. #include "actor_entity_registry.h"
  2. #include "../../bap/activity_message/scriptable_auth_body.h"
  3. #include "../../content/packages/tables/slot_descriptor_reader.h"
  4. #include "composite_entity_codec.h"
  5. #include "entity_identity_metadata.h"
  6. namespace sunrise::middleware::gameplay::external {
  7. namespace {
  8. namespace format = state::activity_sdk::format;
  9. /** @return True when the slot still holds the incarnation a token names. */
  10. [[nodiscard]] bool same_token(const ActorEntitySlot& slot, const EntityToken& token) noexcept {
  11. return slot.occupied && slot.incarnation == token.incarnation;
  12. }
  13. /**
  14. * Resolves one RSAT tag to its single actor class.
  15. * A duplicate tag, or a row whose reverse definition tag disagrees, resolves to nothing.
  16. * @param catalog Pinned actor-class rows.
  17. * @param rsatTag Tag taken from a create baseline.
  18. * @param output Receives the class index.
  19. * @return True when exactly one consistent row owns that tag.
  20. */
  21. [[nodiscard]] bool resolve_actor_class(const ActorEntityCatalog& catalog,
  22. std::uint32_t rsatTag,
  23. std::uint32_t& output) noexcept {
  24. const std::span<const format::ActorClass> actors = catalog.classes;
  25. std::uint32_t found = format::kAbsentIndex;
  26. for (std::size_t index = 0; index < actors.size(); ++index) {
  27. const format::ActorClass& actor = actors[index];
  28. if (actor.rsatTag != rsatTag) {
  29. continue;
  30. }
  31. if (found != format::kAbsentIndex || actor.definitionTag == 0
  32. || actor.definitionTag == format::kAbsentIndex
  33. || actor.rsatReverseDefinitionTag != actor.definitionTag) {
  34. return false;
  35. }
  36. found = static_cast<std::uint32_t>(index);
  37. }
  38. if (found == format::kAbsentIndex) {
  39. return false;
  40. }
  41. output = found;
  42. return true;
  43. }
  44. /** Pins one catalog view. Every slot is cleared when the rows change owner. */
  45. void bind_catalog(ActorEntityRegistry& registry, const ActorEntityCatalog& catalog) noexcept {
  46. if (registry.catalog == catalog.owner && registry.classData == catalog.classes.data()
  47. && registry.classCount == catalog.classes.size()) {
  48. return;
  49. }
  50. registry.catalog = catalog.owner;
  51. registry.classData = catalog.classes.data();
  52. registry.classCount = catalog.classes.size();
  53. registry.slots.fill({});
  54. }
  55. } // namespace
  56. /**
  57. * Applies one accepted allocation and its exact decoded actor-source relation.
  58. * @param registry Slot table to update.
  59. * @param catalog Pinned actor-class rows.
  60. * @param record Decoded record.
  61. * @return What the record did to the slot it names.
  62. */
  63. ActorEntityApplyResult apply_actor_entity_record(ActorEntityRegistry& registry,
  64. const ActorEntityCatalog& catalog,
  65. const EntityRecord& record) noexcept {
  66. if (catalog.classes.empty() || !valid_token(record.token)) {
  67. return ActorEntityApplyResult::invalid;
  68. }
  69. const bool catalogChanged = registry.catalog != catalog.owner
  70. || registry.classData != catalog.classes.data()
  71. || registry.classCount != catalog.classes.size();
  72. const ActorEntitySlot previous =
  73. catalogChanged ? ActorEntitySlot{} : registry.slots[record.token.slot];
  74. ActorEntitySlot candidate = previous;
  75. const bool creating = (record.flags & entityCreate) != 0;
  76. const bool removing = (record.flags & entityRemove) != 0;
  77. if (removing && !creating) {
  78. if (!same_token(previous, record.token)) {
  79. return ActorEntityApplyResult::staleToken;
  80. }
  81. bind_catalog(registry, catalog);
  82. registry.slots[record.token.slot] = {};
  83. return ActorEntityApplyResult::actorRemoved;
  84. }
  85. bool fresh = false;
  86. if (creating) {
  87. if (record.type != EntityType::sobject) {
  88. bind_catalog(registry, catalog);
  89. registry.slots[record.token.slot] = {};
  90. return ActorEntityApplyResult::nonActor;
  91. }
  92. std::uint32_t rsatTag{};
  93. if (!composite_sobject_rsat(record.baseline, rsatTag)) {
  94. return ActorEntityApplyResult::invalid;
  95. }
  96. std::uint32_t actorClassIndex = format::kAbsentIndex;
  97. if (!resolve_actor_class(catalog, rsatTag, actorClassIndex)) {
  98. bind_catalog(registry, catalog);
  99. registry.slots[record.token.slot] = {};
  100. return ActorEntityApplyResult::nonActor;
  101. }
  102. fresh = !same_token(previous, record.token) || previous.rsatTag != rsatTag
  103. || previous.actorClassIndex != actorClassIndex
  104. || previous.allocationSequence != record.allocationSequence;
  105. if (fresh) {
  106. candidate = {};
  107. }
  108. candidate.actorClassIndex = actorClassIndex;
  109. candidate.rsatTag = rsatTag;
  110. candidate.incarnation = record.token.incarnation;
  111. candidate.allocationSequence = record.allocationSequence;
  112. candidate.occupied = true;
  113. } else if (!same_token(previous, record.token)) {
  114. return ActorEntityApplyResult::staleToken;
  115. }
  116. if (removing) {
  117. bind_catalog(registry, catalog);
  118. registry.slots[record.token.slot] = {};
  119. return ActorEntityApplyResult::actorRemoved;
  120. }
  121. state::gameplay::entity_identity::ActorSourceReference source{};
  122. if ((record.flags & entityUpdate) != 0 && record.update.actorSource.known) {
  123. if (!extract_actor_source_reference(record, source)) {
  124. return ActorEntityApplyResult::invalid;
  125. }
  126. candidate.authoredSource = source;
  127. }
  128. const bool membershipChanged = candidate.authoredSource != previous.authoredSource;
  129. bind_catalog(registry, catalog);
  130. registry.slots[record.token.slot] = candidate;
  131. return fresh ? ActorEntityApplyResult::actorCreated
  132. : (membershipChanged ? ActorEntityApplyResult::membershipChanged
  133. : ActorEntityApplyResult::unchanged);
  134. }
  135. /** Catalog and source relations end with their exact peer view. */
  136. void reset_actor_entity_registry(ActorEntityRegistry& registry) noexcept {
  137. registry.catalog.reset();
  138. registry.classData = nullptr;
  139. registry.classCount = 0;
  140. registry.slots.fill({});
  141. }
  142. } // namespace sunrise::middleware::gameplay::external