stan před 2 dny
rodič
revize
1120748c6f
34 změnil soubory, kde provedl 368 přidání a 215 odebrání
  1. 4 0
      .github/workflows/build.yml
  2. 34 0
      Sunrise/Sunrise.vcxproj
  3. 27 13
      Sunrise/src/client/content/activity/activity_sdk_lua_contract.cpp
  4. 35 26
      Sunrise/src/client/content/activity/activity_sdk_squad_graph_edges.cpp
  5. 7 8
      Sunrise/src/middleware/bap/activity_message/activity_scriptable_auth_mission_body_codec.cpp
  6. 34 11
      Sunrise/src/middleware/bap/activity_message/activity_sense_update_decoder.cpp
  7. 1 1
      Sunrise/src/middleware/bap/activity_message/activity_sensor_auth_blocks.cpp
  8. 5 5
      Sunrise/src/middleware/bap/activity_message/activity_sensor_auth_bodies.cpp
  9. 1 2
      Sunrise/src/middleware/bap/activity_message/auth_fields.h
  10. 0 1
      Sunrise/src/middleware/bap/activity_message/combatant_auth.h
  11. 1 2
      Sunrise/src/middleware/bap/activity_message/mission_auth_patch.h
  12. 8 14
      Sunrise/src/middleware/bap/activity_message/scriptable_auth_internal.h
  13. 2 3
      Sunrise/src/server/activity/activity_sdk_device_prepare.cpp
  14. 5 2
      Sunrise/src/server/activity/activity_sdk_mission_prepare.cpp
  15. 7 3
      Sunrise/src/server/activity/activity_sdk_mission_runtime.cpp
  16. 2 2
      Sunrise/src/server/activity/activity_sdk_squad_runtime.cpp
  17. 1 2
      Sunrise/src/server/activity/host_runtime_scriptable_requests.cpp
  18. 12 9
      Sunrise/src/server/activity/host_runtime_sense.cpp
  19. 1 2
      Sunrise/src/server/activity/mission/mission_script_lua_context_api.cpp
  20. 6 3
      Sunrise/src/server/activity/mission/mission_script_lua_event_api.cpp
  21. 83 37
      Sunrise/src/server/activity/mission/mission_script_lua_event_derived.cpp
  22. 3 1
      Sunrise/src/server/activity/mission/mission_script_lua_key_api.cpp
  23. 29 26
      Sunrise/src/server/activity/mission/mission_script_lua_slot_api.cpp
  24. 1 0
      Sunrise/src/server/activity/mission/mission_script_lua_value_api.cpp
  25. 4 2
      Sunrise/src/server/activity/mission/mission_script_runtime.cpp
  26. 2 3
      Sunrise/src/server/activity/mission/mission_script_runtime_dispatch.cpp
  27. 39 28
      Sunrise/src/server/activity/mission/mission_script_runtime_edges.cpp
  28. 1 2
      Sunrise/src/server/activity/mission/mission_script_runtime_feed.cpp
  29. 5 1
      Sunrise/src/server/activity/mission/mission_script_vm.cpp
  30. 2 2
      Sunrise/src/server/bap/bap_route.cpp
  31. 2 1
      Sunrise/src/server/bap/encrypted/push/activity/activity_keepalive_push.cpp
  32. 1 1
      Sunrise/src/server/bap/encrypted/push/activity/activity_roster_snapshot.cpp
  33. 1 1
      Sunrise/src/server/transport/bap_listener.cpp
  34. 2 1
      Sunrise/src/state/activity/membership/activity_membership_query.cpp

+ 4 - 0
.github/workflows/build.yml

@@ -19,12 +19,16 @@ jobs:
 
       - name: Add MSBuild to PATH
         uses: microsoft/setup-msbuild@v2
+        with:
+          msbuild-architecture: x64
 
+      # The x86-hosted compiler runs out of heap on the large static tables. Force the x64 host.
       - name: Build
         run: >
           msbuild Sunrise.sln /m
           /p:Configuration=Release
           /p:Platform=x64
+          /p:PreferredToolArchitecture=x64
           /verbosity:minimal
 
       - name: Upload artifact

+ 34 - 0
Sunrise/Sunrise.vcxproj

@@ -2044,6 +2044,40 @@
     <ClInclude Include="src\middleware\gameplay\group\notice_messages.h" />
     <ClInclude Include="src\server\gameplay\group\group_migration_receipts.h" />
     <ClInclude Include="src\core\runtime\server_clock.h" />
+    <ClInclude Include="src\client\content\activity\entity_object_type_build.h" />
+    <ClInclude Include="src\client\content\activity\entity_position_profile_build.h" />
+    <ClInclude Include="src\middleware\bap\activity_message\auth_fields.h" />
+    <ClInclude Include="src\middleware\bap\activity_message\combatant_auth.h" />
+    <ClInclude Include="src\middleware\bap\activity_message\damage_monitor_auth.h" />
+    <ClInclude Include="src\middleware\bap\activity_message\darkness_zone_auth.h" />
+    <ClInclude Include="src\middleware\bap\activity_message\ghost_link_auth.h" />
+    <ClInclude Include="src\middleware\bap\activity_message\interactable_object_auth.h" />
+    <ClInclude Include="src\middleware\bap\activity_message\mission_auth_patch.h" />
+    <ClInclude Include="src\middleware\bap\activity_message\mission_effect_auth.h" />
+    <ClInclude Include="src\middleware\bap\activity_message\music_section_auth.h" />
+    <ClInclude Include="src\middleware\bap\activity_message\roster_presence.h" />
+    <ClInclude Include="src\middleware\bap\activity_message\scene_events_auth.h" />
+    <ClInclude Include="src\middleware\bap\activity_message\sense_observation_packet.h" />
+    <ClInclude Include="src\middleware\bap\activity_message\squad_objective_auth.h" />
+    <ClInclude Include="src\middleware\content\packages\tables\entity_position_profile_extractor.h" />
+    <ClInclude Include="src\middleware\gameplay\external\entity_identity_metadata.h" />
+    <ClInclude Include="src\server\activity\mission\mission_script_actor_path_sense.h" />
+    <ClInclude Include="src\server\activity\mission\mission_script_event_batch.h" />
+    <ClInclude Include="src\server\activity\mission\mission_script_ghost_sense.h" />
+    <ClInclude Include="src\server\activity\mission\mission_script_object_sense.h" />
+    <ClInclude Include="src\server\activity\mission\mission_script_player_sense.h" />
+    <ClInclude Include="src\server\activity\mission\mission_script_squad_sense.h" />
+    <ClInclude Include="src\server\activity\activity_sdk_behavior_scope.h" />
+    <ClInclude Include="src\server\bap\encrypted\push\activity\mission_seed_world_change.h" />
+    <ClInclude Include="src\server\bap\encrypted\queuez\queuez_reward_staging.h" />
+    <ClInclude Include="src\server\gameplay\entity_identities.h" />
+    <ClInclude Include="src\server\gameplay\squad_entity_retirement.h" />
+    <ClInclude Include="src\server\transport\bap_frame_batch.h" />
+    <ClInclude Include="src\state\account\inventory\item_state.h" />
+    <ClInclude Include="src\state\gameplay\external\entity_identity.h" />
+    <ClInclude Include="src\state\gameplay\external\entity_object_types.h" />
+    <ClInclude Include="src\state\gameplay\external\rsat_decode_plans.h" />
+    <ClInclude Include="src\state\gameplay\external\squad_entity_retirement.h" />
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="src\middleware\bap\activity_message\squad_sense_state.cpp" />

+ 27 - 13
Sunrise/src/client/content/activity/activity_sdk_lua_contract.cpp

@@ -168,7 +168,8 @@ local EventKind = {
 ---@field on_event_fireteam_state? SunriseEventHandler
 ---@field on_event_object_state? SunriseEventHandler
 ---@field on_event_damage_state? SunriseEventHandler
----@field on_event_cinematic_skip_requested? fun(context: any, state: SunriseState, event: SunriseCinematicEvent)
+---@field on_event_cinematic_skip_requested? fun(context: any, state: SunriseState, )lua"
+            R"lua(event: SunriseCinematicEvent)
 
 ---@class SunriseVector3
 ---@field x number
@@ -190,19 +191,32 @@ local EventKind = {
 ---@field auth_dynamic boolean|nil
 ---@field auth_writable boolean|nil
 ---@field set_object_active fun(SunriseSlot, SunriseObjectArguments?): SunriseRequestKey
----@field assign_combat_objective fun(self: SunriseSlot, args: {objective: SunriseSlot, revision: integer, task_group: integer, reserved: boolean?}): SunriseRequestKey
----@field play_actor_path fun(self: SunriseSlot, args: {generation: integer, revision: integer, path: SunriseSlot}): SunriseRequestKey
----@field deliver_squads fun(self: SunriseSlot, args: {generation: integer, revision: integer, squads: SunriseSlot[]}): SunriseRequestKey
----@field deliver_squad fun(self: SunriseSlot, args: {generation: integer, revision: integer, squad: SunriseSlot}): SunriseRequestKey
----@field play_actor_action fun(self: SunriseSlot, args: {generation: integer, revision: integer, group: integer, action: integer}): SunriseRequestKey
+---@field assign_combat_objective fun(self: SunriseSlot, args: {objective: SunriseSlot, )lua"
+            R"lua(revision: integer, task_group: integer, reserved: boolean?}): SunriseRequestKey
+---@field play_actor_path fun(self: SunriseSlot, args: {generation: integer, )lua"
+            R"lua(revision: integer, path: SunriseSlot}): SunriseRequestKey
+---@field deliver_squads fun(self: SunriseSlot, args: {generation: integer, )lua"
+            R"lua(revision: integer, squads: SunriseSlot[]}): SunriseRequestKey
+---@field deliver_squad fun(self: SunriseSlot, args: {generation: integer, revision: integer, )lua"
+            R"lua(squad: SunriseSlot}): SunriseRequestKey
+---@field play_actor_action fun(self: SunriseSlot, args: {generation: integer, )lua"
+            R"lua(revision: integer, group: integer, action: integer}): SunriseRequestKey
 ---@field retire_actor fun(self: SunriseSlot, args: {generation: integer}): SunriseRequestKey
----@field set_darkness_zone fun(self: SunriseSlot, args: {enabled: boolean, wipe_seconds: integer?}): SunriseRequestKey
----@field set_interactable_object fun(self: SunriseSlot, args: {generation: integer, track_owner: boolean?, active: boolean?}): SunriseRequestKey
----@field set_music_section fun(self: SunriseSlot, args: {section: integer, enabled: boolean?}): SunriseRequestKey
----@field watch_damage fun(self: SunriseSlot, args: {target: SunriseSlot, revision: integer}): SunriseRequestKey
----@field set_object_filter fun(self: SunriseSlot, args: {players: boolean?, target: SunriseSlot?, inside: SunriseSlot?, inside_any: SunriseSlot[]?}): SunriseRequestKey
----@field set_mission_effect fun(self: SunriseSlot, args: {filter: SunriseSlot?, enabled: boolean, revision: integer}): SunriseRequestKey
----@field set_ghost_link fun(self: SunriseSlot, args: {generation: integer, enabled: boolean}): SunriseRequestKey
+---@field set_darkness_zone fun(self: SunriseSlot, args: {enabled: boolean, )lua"
+            R"lua(wipe_seconds: integer?}): SunriseRequestKey
+---@field set_interactable_object fun(self: SunriseSlot, args: {generation: integer, )lua"
+            R"lua(track_owner: boolean?, active: boolean?}): SunriseRequestKey
+---@field set_music_section fun(self: SunriseSlot, args: {section: integer, )lua"
+            R"lua(enabled: boolean?}): SunriseRequestKey
+---@field watch_damage fun(self: SunriseSlot, args: {target: SunriseSlot, )lua"
+            R"lua(revision: integer}): SunriseRequestKey
+---@field set_object_filter fun(self: SunriseSlot, args: {players: boolean?, )lua"
+            R"lua(target: SunriseSlot?, inside: SunriseSlot?, )lua"
+            R"lua(inside_any: SunriseSlot[]?}): SunriseRequestKey
+---@field set_mission_effect fun(self: SunriseSlot, args: {filter: SunriseSlot?, )lua"
+            R"lua(enabled: boolean, revision: integer}): SunriseRequestKey
+---@field set_ghost_link fun(self: SunriseSlot, args: {generation: integer, )lua"
+            R"lua(enabled: boolean}): SunriseRequestKey
 ---@field bind_combatant_to_squad fun(self: SunriseSlot): SunriseRequestKey
 ---@field transition fun(SunriseSlot, SunriseDeviceTransitionArguments): SunriseRequestKey
 ---@field fire_trigger fun(self: SunriseSlot): SunriseRequestKey

+ 35 - 26
Sunrise/src/client/content/activity/activity_sdk_squad_graph_edges.cpp

@@ -318,9 +318,10 @@ template <typename Index> void canonicalize_scenarios(Index& index) {
     std::map<TargetGroup, std::vector<std::uint32_t>> groups{};
     std::size_t authoritativeCount = 0;
     const GraphSpawner& spawner = graph.spawners[spawnerRow];
-    const auto sourceStatus = scopedSource != format::kAbsentIndex
-        ? SourceDescriptorStatus::exact : spawner.sourceDescriptorStatus;
-    const auto sourceRow = scopedSource != format::kAbsentIndex ? scopedSource : spawner.sourceDescriptorRow;
+    const auto sourceStatus = scopedSource != format::kAbsentIndex ? SourceDescriptorStatus::exact
+                                                                   : spawner.sourceDescriptorStatus;
+    const auto sourceRow =
+        scopedSource != format::kAbsentIndex ? scopedSource : spawner.sourceDescriptorRow;
     for (const std::uint32_t descriptorRow : candidates) {
         const GraphDescriptor& descriptor = graph.descriptors[descriptorRow];
         // Object keys are reused by campaign and arcade scenarios. A reference can only
@@ -392,21 +393,26 @@ template <typename Index> void canonicalize_scenarios(Index& index) {
 
 /** A reused config is unambiguous in disjoint scenario contexts. Never resolve two
  * different source slots that coexist in the same scenario by arbitrary row order. */
-[[nodiscard]] std::vector<std::uint32_t> scoped_sources(const GraphSnapshot& graph,
-    const GraphSpawner& spawner, const std::vector<std::vector<std::uint32_t>>& scenarios) {
-    std::map<std::pair<std::uint32_t,std::uint32_t>,std::uint32_t> logical;
-    for (std::uint32_t i=0;i<spawner.sourceDescriptorCandidates.count;++i) {
-        const auto row=graph.sourceDescriptorCandidates[spawner.sourceDescriptorCandidates.first+i].descriptorRow;
-        const auto& d=graph.descriptors[row];logical.try_emplace({d.objectIndex,d.slotIndex},row);
+[[nodiscard]] std::vector<std::uint32_t>
+scoped_sources(const GraphSnapshot& graph,
+               const GraphSpawner& spawner,
+               const std::vector<std::vector<std::uint32_t>>& scenarios) {
+    std::map<std::pair<std::uint32_t, std::uint32_t>, std::uint32_t> logical;
+    for (std::uint32_t i = 0; i < spawner.sourceDescriptorCandidates.count; ++i) {
+        const auto row =
+            graph.sourceDescriptorCandidates[spawner.sourceDescriptorCandidates.first + i]
+                .descriptorRow;
+        const auto& d = graph.descriptors[row];
+        logical.try_emplace({d.objectIndex, d.slotIndex}, row);
     }
     std::vector<std::uint32_t> result;
-    for (const auto& [identity,row]:logical) {
-        const auto& owned=scenarios[identity.first];
-        const bool overlap=std::any_of(logical.begin(),logical.end(),[&](const auto& other) {
-            if (other.first==identity) return false;
-            const auto& peers=scenarios[other.first.first];
-            return std::any_of(owned.begin(),owned.end(),[&](auto scenario) {
-                return std::binary_search(peers.begin(),peers.end(),scenario);
+    for (const auto& [identity, row] : logical) {
+        const auto& owned = scenarios[identity.first];
+        const bool overlap = std::any_of(logical.begin(), logical.end(), [&](const auto& other) {
+            if (other.first == identity) return false;
+            const auto& peers = scenarios[other.first.first];
+            return std::any_of(owned.begin(), owned.end(), [&](auto scenario) {
+                return std::binary_search(peers.begin(), peers.end(), scenario);
             });
         });
         if (!overlap) result.push_back(row);
@@ -478,7 +484,7 @@ template <typename Index> void canonicalize_scenarios(Index& index) {
         }
 
         spawner.references.first = static_cast<std::uint32_t>(graph.references.size());
-        auto sources = scoped_sources(graph,spawner,scenariosByObject);
+        auto sources = scoped_sources(graph, spawner, scenariosByObject);
         if (sources.empty()) sources.push_back(format::kAbsentIndex);
         for (const auto sourceRow : sources) {
             std::map<TargetGroup, ExactTarget> exactTargets{};
@@ -494,13 +500,15 @@ template <typename Index> void canonicalize_scenarios(Index& index) {
                                        rulesByConfig,
                                        scenariosByObject,
                                        exactTargets,
-                                       statuses[ordinal], sourceRow)) {
+                                       statuses[ordinal],
+                                       sourceRow)) {
                     return false;
                 }
             }
-            const bool hasAmbiguous =
-                std::find(statuses.begin(), statuses.end(), ReferenceResolutionStatus::targetAmbiguous)
-                != statuses.end();
+            const bool hasAmbiguous = std::find(statuses.begin(),
+                                                statuses.end(),
+                                                ReferenceResolutionStatus::targetAmbiguous)
+                                      != statuses.end();
             const bool hasOther = std::any_of(statuses.begin(), statuses.end(), [](auto status) {
                 return status != ReferenceResolutionStatus::exact
                        && status != ReferenceResolutionStatus::invalidEncoding;
@@ -509,16 +517,16 @@ template <typename Index> void canonicalize_scenarios(Index& index) {
             const bool bothAbsent = std::all_of(statuses.begin(), statuses.end(), [](auto status) {
                 return status == ReferenceResolutionStatus::invalidEncoding;
             });
-            if (bothAbsent && spawner.hasInlinePointSet && spawner.inlineRuleRow != format::kAbsentIndex
+            if (bothAbsent && spawner.hasInlinePointSet
+                && spawner.inlineRuleRow != format::kAbsentIndex
                 && sourceRow != format::kAbsentIndex && exactTargets.empty()) {
                 const GraphDescriptor& source = graph.descriptors[sourceRow];
                 ExactTarget& target =
                     exactTargets[{spawner.inlineRuleRow, source.objectIndex, source.slotIndex}];
                 target.descriptors = {sourceRow};
             }
-            const bool associationExact =
-                sourceRow != format::kAbsentIndex && !hasAmbiguous && !hasOther
-                && !exactTargets.empty();
+            const bool associationExact = sourceRow != format::kAbsentIndex && !hasAmbiguous
+                                          && !hasOther && !exactTargets.empty();
             if (sourceRow == format::kAbsentIndex) {
                 continue;
             }
@@ -569,7 +577,8 @@ template <typename Index> void canonicalize_scenarios(Index& index) {
                 output.push_back(std::move(edge));
             }
         }
-        spawner.references.count = static_cast<std::uint32_t>(graph.references.size()) - spawner.references.first;
+        spawner.references.count =
+            static_cast<std::uint32_t>(graph.references.size()) - spawner.references.first;
     }
     std::sort(
         output.begin(), output.end(), [](const PendingEdge& first, const PendingEdge& second) {

+ 7 - 8
Sunrise/src/middleware/bap/activity_message/activity_scriptable_auth_mission_body_codec.cpp

@@ -427,7 +427,8 @@ bool encode_type68(const Type68Preset& preset,
                    && reference.registryKey != kClientRefAbsentKey);
     };
     // A navpoint rides only on a visible entry in the enter state.
-    const bool navpointAllowed = preset.navpoint.slotIndex < 0 || (preset.visible && preset.state == 0);
+    const bool navpointAllowed =
+        preset.navpoint.slotIndex < 0 || (preset.visible && preset.state == 0);
     if (!valid_reference(preset.audience, kType70SlotType)
         || !valid_reference(preset.navpoint, kType47SlotType) || !navpointAllowed
         || output.size() < kType68ByteCount || preset.state < 0 || preset.state > 2
@@ -446,13 +447,11 @@ bool encode_type68(const Type68Preset& preset,
                         kClientRefIndexWidth)
         && write_absent_client_ref(writer);
     for (std::size_t index = 0; encoded && index < kType68EntryCount; ++index) {
-        encoded = index == 0 && preset.visible
-                      ? write_directive_entry(writer,
-                                              preset.nameHash,
-                                              preset.elementIndex,
-                                              preset.state,
-                                              preset.navpoint)
-                      : write_directive_entry(writer, kClientRefAbsentKey, 0, -1);
+        encoded =
+            index == 0 && preset.visible
+                ? write_directive_entry(
+                      writer, preset.nameHash, preset.elementIndex, preset.state, preset.navpoint)
+                : write_directive_entry(writer, kClientRefAbsentKey, 0, -1);
     }
     encoded = encoded && writer.write(preset.visible ? 1U : 0U, kDirectiveActiveIndexWidth);
     return encoded && writer.bit_count() == kType68BitCount && writer.finish(written)

+ 34 - 11
Sunrise/src/middleware/bap/activity_message/activity_sense_update_decoder.cpp

@@ -529,15 +529,23 @@ real_value(std::uint64_t raw, std::uint8_t width, std::uint32_t maximumBits) noe
         if (schema == kInteractionReply) {
             // The interaction latch and the revision that set it.
             if (!read_bool(reader, values, kInteractionReply, 0, false, index)
-                || !read_signed(reader, values, kInteractionReply, 1, 32, 32,
-                    (std::numeric_limits<std::int32_t>::min)(), false, index))
+                || !read_signed(reader,
+                                values,
+                                kInteractionReply,
+                                1,
+                                32,
+                                32,
+                                (std::numeric_limits<std::int32_t>::min)(),
+                                false,
+                                index))
                 return NativeStatus::malformed;
         } else if (schema == kOwnershipReply) {
             // The owner key is always written, zero when nobody holds the object.
             if (!read_bool(reader, values, kOwnershipReply, 0, false, index)
                 || !read_unsigned(reader, values, kOwnershipReply, 1, 64, false, index))
                 return NativeStatus::malformed;
-        } else return NativeStatus::unsupported;
+        } else
+            return NativeStatus::unsupported;
     }
     return NativeStatus::complete;
 }
@@ -605,7 +613,8 @@ real_value(std::uint64_t raw, std::uint8_t width, std::uint32_t maximumBits) noe
         return NativeStatus::malformed;
     }
     for (std::uint16_t ordinal = 2; ordinal <= 5; ++ordinal) {
-        if (!read_bool(reader, values, kPlayerState, ordinal, false)) return NativeStatus::malformed;
+        if (!read_bool(reader, values, kPlayerState, ordinal, false))
+            return NativeStatus::malformed;
     }
     if (!read_signed(reader, values, kPlayerState, 6, 3, 8, 1, false)
         || !read_signed(reader, values, kPlayerState, 7, 2, 8, 1, false)) {
@@ -682,17 +691,31 @@ decode_body(std::uint32_t schema, Reader& reader, Values& values) noexcept {
     case kDamage:
         // Three mandatory fields: health, shield, then the echoed Auth revision.
         return read_real(reader, values, schema, 0, 32, false)
-            && read_real(reader, values, schema, 1, 32, false)
-            && read_signed(reader, values, schema, 2, 32, 32,
-                (std::numeric_limits<std::int32_t>::min)(), false)
-            ? NativeStatus::complete : NativeStatus::malformed;
+                       && read_real(reader, values, schema, 1, 32, false)
+                       && read_signed(reader,
+                                      values,
+                                      schema,
+                                      2,
+                                      32,
+                                      32,
+                                      (std::numeric_limits<std::int32_t>::min)(),
+                                      false)
+                   ? NativeStatus::complete
+                   : NativeStatus::malformed;
     case kGhostLink:
         // Three mandatory fields: active, elapsed over duration, accepted Auth generation.
         return read_bool(reader, values, kGhostLink, 0, false)
                        && read_real(reader, values, kGhostLink, 1, 32, false)
-                       && read_signed(reader, values, kGhostLink, 2, 32, 32,
-                                      (std::numeric_limits<std::int32_t>::min)(), false)
-                   ? NativeStatus::complete : NativeStatus::malformed;
+                       && read_signed(reader,
+                                      values,
+                                      kGhostLink,
+                                      2,
+                                      32,
+                                      32,
+                                      (std::numeric_limits<std::int32_t>::min)(),
+                                      false)
+                   ? NativeStatus::complete
+                   : NativeStatus::malformed;
     case kDevice:
         return decode_device(reader, values);
     case kScene:

+ 1 - 1
Sunrise/src/middleware/bap/activity_message/activity_sensor_auth_blocks.cpp

@@ -1,7 +1,7 @@
 #include <algorithm>
 
-#include "sensor_auth_update.h"
 #include "roster_presence.h"
+#include "sensor_auth_update.h"
 
 namespace sunrise::middleware::bap::activity_message::sensor_auth_update {
 namespace {

+ 5 - 5
Sunrise/src/middleware/bap/activity_message/activity_sensor_auth_bodies.cpp

@@ -146,17 +146,17 @@ constexpr std::size_t kSpawnKeyCount = 32;
     // name hash; zero is a hash that no row matches.
     bool encoded = writer.write(std::uint32_t{snapshot.lifetime} + kLifetimeBias, kLifetimeWidth)
                    && writer.write(1, 3) && writer.write(0, kPresenceWidth)
-                   && writer.write(kSignedZero, 32) && writer.write(kEmptyNameHash, 32)
+                   && writer.write(kSignedZero, 32)
+                   && writer.write(kEmptyNameHash, 32)
                    // Under a darkness policy the lifetime names the bubble, or -1 when disabled.
                    && writer.write(!snapshot.hasDarknessPolicy ? kSignedZero
                                    : snapshot.darknessEnabled && snapshot.hasRegion
                                        ? kSignedZero + snapshot.region / kStatesPerBubble
                                        : kSignedMinusOne,
                                    32)
-                   && writer.write(1, 6)
-                   && writer.write(kWaitingSwitchKey, 32) && writer.write(1, kPresenceWidth)
-                   && writer.write(kWaitingSwitchClass, 32) && writer.write(kSignedZero, 32)
-                   && writer.write(kSignedZero, 32);
+                   && writer.write(1, 6) && writer.write(kWaitingSwitchKey, 32)
+                   && writer.write(1, kPresenceWidth) && writer.write(kWaitingSwitchClass, 32)
+                   && writer.write(kSignedZero, 32) && writer.write(kSignedZero, 32);
     for (std::size_t index = 0; encoded && index < kSpawnOverrideCount; ++index) {
         const std::uint32_t slice =
             snapshot.hasSpawnOverride ? snapshot.spawnSliceSet + kSpawnOverrideIndexBias : 0U;

+ 1 - 2
Sunrise/src/middleware/bap/activity_message/auth_fields.h

@@ -23,8 +23,7 @@ inline constexpr std::uint32_t kSigned32Bias = 0x80000000U;
 /** Generations and revisions are 31-bit counters that the client accepts only while positive. */
 inline constexpr std::uint8_t kCounterWidth = 31;
 inline constexpr std::uint32_t kMaximumCounter = 0x7FFFFFFFU;
-/** A nested ClientRef is a 32-bit registry key, a 7-bit biased slot type and a 16-bit biased index.
- */
+/** A ClientRef is a 32-bit registry key, a 7-bit biased slot type and a 16-bit biased index. */
 inline constexpr std::uint8_t kClientRefKeyWidth = 32;
 inline constexpr std::uint8_t kClientRefTypeWidth = 7;
 inline constexpr std::uint8_t kClientRefIndexWidth = 16;

+ 0 - 1
Sunrise/src/middleware/bap/activity_message/combatant_auth.h

@@ -58,7 +58,6 @@ inline constexpr std::size_t kPathBytes = 20;
 inline constexpr std::size_t kActionBits = 254;
 inline constexpr std::size_t kActionBytes = 32;
 inline constexpr std::size_t kDeliveryBits = 132;
-inline constexpr std::size_t kDeliveryBytes = 17;
 inline constexpr std::size_t kDeliveryMaximumBytes =
     (kDeliveryBits + kManifestSquadBits * (kMaximumManifestSquads - 1) + 7) / 8;
 inline constexpr std::size_t kRetireBits = 77;

+ 1 - 2
Sunrise/src/middleware/bap/activity_message/mission_auth_patch.h

@@ -84,8 +84,7 @@ inline constexpr std::array<FieldRule, kCombatantFieldCount> kCombatantRules{{
     {Kind::manifest, true, 0}, // .7
 }};
 
-/** Combatant .6 program layout: revision, two 6-bit header words, a presence bit, kind, completion.
- */
+/** Combatant .6 program layout: revision, two 6-bit header words, presence, kind, completion. */
 inline constexpr std::size_t kProgramLeadBits = 31 + 6;
 inline constexpr std::uint8_t kProgramHeaderWidth = 6;
 inline constexpr std::uint32_t kProgramHeaderSecond = 1;

+ 8 - 14
Sunrise/src/middleware/bap/activity_message/scriptable_auth_internal.h

@@ -6,6 +6,7 @@
 
 #include "../../encoding/bit_reader.h"
 #include "../../encoding/bit_writer.h"
+#include "auth_fields.h"
 #include "scriptable_auth_body.h"
 
 // Constants and primitives shared by the scriptable-auth codecs.
@@ -15,11 +16,8 @@ namespace sunrise::middleware::bap::activity_message::scriptable_auth {
 
 /** Widths of the scalar wire fields, in bits, and the value a present flag carries. */
 inline constexpr std::uint8_t kReal32Width = 32;
-inline constexpr std::uint8_t kBoolWidth = 1;
 inline constexpr std::uint8_t kEnabled = 1;
 inline constexpr std::uint8_t kSigned32Width = 32;
-/** Signed 32-bit schema fields store zero at the middle of the unsigned wire range. */
-inline constexpr std::uint32_t kSigned32Bias = 0x80000000U;
 /** Signed 16-bit schema fields store zero at the middle of the unsigned wire range. */
 inline constexpr std::uint32_t kSigned16Bias = 0x8000;
 /** Wide schema integers travel as 64-bit fields. */
@@ -29,11 +27,13 @@ inline constexpr std::uint8_t kModeWidth = 2;
 inline constexpr std::int8_t kMinimumMode = -1;
 inline constexpr std::int8_t kMaximumMode = 2;
 inline constexpr std::uint32_t kModeBias = 1;
-/** The nested 0x80809C42 ClientRef is unset when it holds this key, type 0, and index -1. */
-inline constexpr std::uint32_t kClientRefAbsentKey = 0x811C9DC5U;
-inline constexpr std::uint8_t kClientRefTypeWidth = 7;
-inline constexpr std::uint8_t kClientRefIndexWidth = 16;
-inline constexpr std::uint32_t kClientRefIndexBias = 32'768;
+using auth_fields::kBoolWidth;
+using auth_fields::kClientRefAbsentKey;
+using auth_fields::kClientRefIndexBias;
+using auth_fields::kClientRefIndexWidth;
+using auth_fields::kClientRefTypeWidth;
+using auth_fields::kSigned32Bias;
+using auth_fields::write_absent_client_ref;
 
 /** @return True when the unused low bits in the final byte are zero. */
 [[nodiscard]] inline bool finish_padding(encoding::bits::Reader& reader) noexcept {
@@ -43,12 +43,6 @@ inline constexpr std::uint32_t kClientRefIndexBias = 32'768;
            && padding == 0 && reader.remaining_bits() == 0;
 }
 
-/** Writes the exact nested 0x80809C42 unset ClientRef. */
-[[nodiscard]] inline bool write_absent_client_ref(encoding::bits::Writer& writer) noexcept {
-    return writer.write(kClientRefAbsentKey, 32) && writer.write(0, kClientRefTypeWidth)
-           && writer.write(kClientRefIndexBias - 1U, kClientRefIndexWidth);
-}
-
 /** Reads and requires the exact nested 0x80809C42 unset ClientRef. */
 [[nodiscard]] inline bool read_absent_client_ref(encoding::bits::Reader& reader) noexcept {
     std::uint64_t key = 0;

+ 2 - 3
Sunrise/src/server/activity/activity_sdk_device_prepare.cpp

@@ -473,9 +473,8 @@ prepare_slot(const sdk::BoundView& view, std::uint32_t slotRow, PreparedDevice&
         || typed(message::ghost_link::kSlotType,
                  message::ghost_link::kComponentClass,
                  message::ghost_link::kAuthSchema)
-        || typed(format::kSquadSlotType,
-                 format::kSquadComponentClass,
-                 message::squad_objective::kSchema)
+        || typed(
+            format::kSquadSlotType, format::kSquadComponentClass, message::squad_objective::kSchema)
         || typed(auth::kType2SlotType, auth::kType2ComponentClass, auth::kType2Schema);
     const bool occupancy = slotType == format::kOccupancySlotType
                            && authSchema == format::kOccupancyAuthSchema

+ 5 - 2
Sunrise/src/server/activity/activity_sdk_mission_prepare.cpp

@@ -134,8 +134,11 @@ namespace {
         return SceneStatus::missionSeedUnavailable;
     }
     if (lease.plan.stateRow != stateRow
-        && !behavior_scope::live_state(view.catalog->states(), view.catalog->bubbles(),
-            view.scenarioRow, stateRow, link.effectiveRegion)) {
+        && !behavior_scope::live_state(view.catalog->states(),
+                                       view.catalog->bubbles(),
+                                       view.scenarioRow,
+                                       stateRow,
+                                       link.effectiveRegion)) {
         return SceneStatus::wrongState;
     }
     if (lease.publicationPending || lease.publishedRevision != lease.revision) {

+ 7 - 3
Sunrise/src/server/activity/activity_sdk_mission_runtime.cpp

@@ -513,9 +513,13 @@ set_cinematic_active_reserved(const sdk::BoundView& view,
     server::bap::ActivityLinkView link{};
     const SceneStatus live = scene_binding_status(view, link);
     if (live != SceneStatus::ready) return live;
-    const auto selected = behavior_scope::select(occurrences, view.catalog->states(),
-        view.catalog->bubbles(), view.scenarioRow, slots[slotRow].objectIndex,
-        snapshot.plan.stateRow, link.effectiveRegion);
+    const auto selected = behavior_scope::select(occurrences,
+                                                 view.catalog->states(),
+                                                 view.catalog->bubbles(),
+                                                 view.scenarioRow,
+                                                 slots[slotRow].objectIndex,
+                                                 snapshot.plan.stateRow,
+                                                 link.effectiveRegion);
     if (selected.ambiguous) return SceneStatus::ambiguousTarget;
     occurrenceRow = selected.row;
     return occurrenceRow == sdk::format::kAbsentIndex ? SceneStatus::targetUnavailable

+ 2 - 2
Sunrise/src/server/activity/activity_sdk_squad_runtime.cpp

@@ -97,8 +97,8 @@ struct PreparedSquad final {
     const auto actors = catalog.actor_classes();
     bool found = false;
     // A named type-2 member needs its parent's authored profile but zero loose actors.
-    const bool loose = std::any_of(requestedCounts.begin(), requestedCounts.end(),
-                                    [](auto count) { return count > 0; });
+    const bool loose = std::any_of(
+        requestedCounts.begin(), requestedCounts.end(), [](auto count) { return count > 0; });
     for (std::size_t index = 0; index < members.size(); ++index) {
         if (loose && requestedCounts[index] <= 0) {
             continue;

+ 1 - 2
Sunrise/src/server/activity/host_runtime_scriptable_requests.cpp

@@ -363,8 +363,7 @@ bool request_squad_override(
                 : stateLocalRosterGroup != nullptr)
         || requestedCounts.size() < squad::kMinimumRequestedCountLength
         || requestedCounts.size() > squad::kMaximumRequestedCountLength
-        || expectedActivityClientGeneration == 0
-        || !squad::valid_mode(mode)
+        || expectedActivityClientGeneration == 0 || !squad::valid_mode(mode)
         || !std::ranges::all_of(requestedCounts, [](std::int32_t count) { return count >= 0; })) {
         return false;
     }

+ 12 - 9
Sunrise/src/server/activity/host_runtime_sense.cpp

@@ -38,7 +38,8 @@ packet_has_sense_key(const middleware::bap::activity_message::sense_update::Deco
                      const SenseObservationKey& key,
                      std::size_t first) noexcept {
     for (std::size_t index = first; index < packet.objectCount; ++index) {
-        if (packet.objects[index].status == middleware::bap::activity_message::sense_update::ObjectStatus::decoded
+        if (packet.objects[index].status
+                == middleware::bap::activity_message::sense_update::ObjectStatus::decoded
             && packet.objects[index].hasGeneration && same_sense_key(key, packet.objects[index])) {
             return true;
         }
@@ -51,11 +52,11 @@ packet_has_sense_key(const middleware::bap::activity_message::sense_update::Deco
     namespace sense = middleware::bap::activity_message::sense_update;
     const auto& packet = input.decoded;
     return input.sourceGeneration != 0 && input.clientMessageSequence != 0
-        && input.verdict == state::activity::receipts::Verdict::framed
-        && input.decodeStatus == packet.status && sense::observation_packet(packet)
-        && input.groupsSeen == packet.groupsSeen && input.groupsDecoded == packet.groupsDecoded
-        && input.groupsSkipped == packet.groupsSkipped && input.objectsSeen == packet.objectsSeen
-        && input.objectsDecoded == packet.objectsDecoded;
+           && input.verdict == state::activity::receipts::Verdict::framed
+           && input.decodeStatus == packet.status && sense::observation_packet(packet)
+           && input.groupsSeen == packet.groupsSeen && input.groupsDecoded == packet.groupsDecoded
+           && input.groupsSkipped == packet.groupsSkipped && input.objectsSeen == packet.objectsSeen
+           && input.objectsDecoded == packet.objectsDecoded;
 }
 
 /** Mixes one fixed-width value into the local scene change guard. */
@@ -260,8 +261,9 @@ void trace_scene_sense(Instance& instance, const SenseInput& input) noexcept {
     }
     for (std::size_t index = 0; index < packet.objectCount; ++index) {
         const sense::DecodedObject& object = packet.objects[index];
-        if (object.status != sense::ObjectStatus::decoded || !object.hasGeneration || object.slotType
-            != static_cast<std::uint8_t>(state::activity_sdk::format::kAuthoredSceneSlotType)
+        if (object.status != sense::ObjectStatus::decoded || !object.hasGeneration
+            || object.slotType
+                   != static_cast<std::uint8_t>(state::activity_sdk::format::kAuthoredSceneSlotType)
             || packet_has_sense_key(packet,
                                     {object.registryKey,
                                      object.objectTag,
@@ -338,7 +340,8 @@ void trace_scene_sense(Instance& instance, const SenseInput& input) noexcept {
     }
 }
 
-/** Replaces only fully decoded keys in an accepted packet; omitted or unsupported keys stay retained. */
+/** Replaces only fully decoded keys in an accepted packet; omitted or unsupported keys stay
+ * retained. */
 [[nodiscard]] bool
 retain_sense_observations(Instance& instance, const SenseInput& input, std::uint64_t now) noexcept {
     namespace sense = middleware::bap::activity_message::sense_update;

+ 1 - 2
Sunrise/src/server/activity/mission/mission_script_lua_context_api.cpp

@@ -37,8 +37,7 @@ namespace {
     const lua_Integer region = optional_integer_argument(state, "region", -1);
     const lua_Integer hash = optional_integer_argument(state, "spawn_set_hash", 0);
     if (region < 0 || region > ::sunrise::state::activity::membership::kMaximumSliceSetIndex
-        || hash <= 0
-        || hash >= (std::numeric_limits<std::uint32_t>::max)()) {
+        || hash <= 0 || hash >= (std::numeric_limits<std::uint32_t>::max)()) {
         return luaL_error(state, "checkpoint requires an authored region and spawn-set hash");
     }
     std::uint64_t release = 0;

+ 6 - 3
Sunrise/src/server/activity/mission/mission_script_lua_event_api.cpp

@@ -55,8 +55,10 @@ namespace sunrise::server::activity::mission::lua_vm::detail {
         return "actorPathState";
     case host::EventKind::objectInteracted:
         return "objectInteracted";
-    case host::EventKind::damageState: return "damageState";
-    case host::EventKind::objectState: return "objectState";
+    case host::EventKind::damageState:
+        return "damageState";
+    case host::EventKind::objectState:
+        return "objectState";
     case host::EventKind::ghostLinkState:
         return "ghostLinkState";
     case host::EventKind::clientMessageReceived:
@@ -164,7 +166,8 @@ namespace sunrise::server::activity::mission::lua_vm::detail {
     case host::EventKind::objectInteracted:
         return kObjectInteractionEventMetatable;
     case host::EventKind::damageState:
-    case host::EventKind::objectState: return kObjectInteractionEventMetatable;
+    case host::EventKind::objectState:
+        return kObjectInteractionEventMetatable;
     case host::EventKind::ghostLinkState:
         return kGhostLinkEventMetatable;
     }

+ 83 - 37
Sunrise/src/server/activity/mission/mission_script_lua_event_derived.cpp

@@ -270,42 +270,72 @@ push_joined_revision_member(lua_State* state, const host::Event& event, std::str
 [[nodiscard]] int actor_path_index(lua_State* state) {
     const auto& event = check_event(state, 1);
     const auto key = lua_string_view(state, 2);
-    if (push_common_member(state, event, key) || push_mission_sequence_member(state, event, key)) return 1;
+    if (push_common_member(state, event, key) || push_mission_sequence_member(state, event, key))
+        return 1;
     if (event_surface_visible(state, event.kind)) {
         if (push_slot_identity_member(state, event, key)) return 1;
-        if (key == "generation") { lua_pushinteger(state, event.actorGeneration); return 1; }
-        if (key == "revision") { lua_pushinteger(state, event.actorPathRevision); return 1; }
-        if (key == "path_state") { lua_pushinteger(state, event.actorPathState); return 1; }
+        if (key == "generation") {
+            lua_pushinteger(state, event.actorGeneration);
+            return 1;
+        }
+        if (key == "revision") {
+            lua_pushinteger(state, event.actorPathRevision);
+            return 1;
+        }
+        if (key == "path_state") {
+            lua_pushinteger(state, event.actorPathState);
+            return 1;
+        }
         if (key == "delivery_revision" && event.actorDeliveryKnown) {
-            lua_pushinteger(state, event.actorDeliveryRevision); return 1;
+            lua_pushinteger(state, event.actorDeliveryRevision);
+            return 1;
         }
         if (key == "delivery_state" && event.actorDeliveryKnown) {
-            lua_pushinteger(state, event.actorDeliveryState); return 1;
+            lua_pushinteger(state, event.actorDeliveryState);
+            return 1;
+        }
+        if (key == "dead") {
+            lua_pushboolean(state, event.actorDead);
+            return 1;
         }
-        if (key == "dead") { lua_pushboolean(state, event.actorDead); return 1; }
     }
-    lua_pushnil(state); return 1;
+    lua_pushnil(state);
+    return 1;
 }
 
+/** Lua index for one object interaction event: the common, slot and interaction members. */
 [[nodiscard]] int object_interaction_index(lua_State* state) {
-    const host::Event& event = check_event(state,1);
-    const auto key = lua_string_view(state,2);
-    if (push_common_member(state,event,key) || push_mission_sequence_member(state,event,key)
-        || (event_surface_visible(state,event.kind) && push_slot_identity_member(state,event,key))) return 1;
+    const host::Event& event = check_event(state, 1);
+    const auto key = lua_string_view(state, 2);
+    if (push_common_member(state, event, key) || push_mission_sequence_member(state, event, key)
+        || (event_surface_visible(state, event.kind)
+            && push_slot_identity_member(state, event, key)))
+        return 1;
     if (event.kind == host::EventKind::damageState) {
-        if (key == "health") lua_pushnumber(state,event.damageHealth);
-        else if (key == "shield") lua_pushnumber(state,event.damageShield);
-        else if (key == "revision") lua_pushinteger(state,event.damageRevision);
-        else lua_pushnil(state);
-        return 1;
-    }
-    if (key == "generation") lua_pushinteger(state,event.objectGeneration);
-    else if (key == "present") lua_pushboolean(state,event.objectPresent);
-    else if (key == "alive") lua_pushboolean(state,event.objectAlive);
-    else if (key == "owner_known") lua_pushboolean(state,event.objectOwnerKnown);
-    else if (key == "has_owner") lua_pushboolean(state,event.objectHasOwner);
-    else if (key == "owner_key" && event.objectOwnerKey != 0) push_u64_string(state,event.objectOwnerKey);
-    else lua_pushnil(state);
+        if (key == "health")
+            lua_pushnumber(state, event.damageHealth);
+        else if (key == "shield")
+            lua_pushnumber(state, event.damageShield);
+        else if (key == "revision")
+            lua_pushinteger(state, event.damageRevision);
+        else
+            lua_pushnil(state);
+        return 1;
+    }
+    if (key == "generation")
+        lua_pushinteger(state, event.objectGeneration);
+    else if (key == "present")
+        lua_pushboolean(state, event.objectPresent);
+    else if (key == "alive")
+        lua_pushboolean(state, event.objectAlive);
+    else if (key == "owner_known")
+        lua_pushboolean(state, event.objectOwnerKnown);
+    else if (key == "has_owner")
+        lua_pushboolean(state, event.objectHasOwner);
+    else if (key == "owner_key" && event.objectOwnerKey != 0)
+        push_u64_string(state, event.objectOwnerKey);
+    else
+        lua_pushnil(state);
     return 1;
 }
 
@@ -313,12 +343,22 @@ push_joined_revision_member(lua_State* state, const host::Event& event, std::str
 [[nodiscard]] int ghost_link_index(lua_State* state) {
     const host::Event& event = check_event(state, 1);
     const std::string_view key = lua_string_view(state, 2);
-    if (push_common_member(state, event, key) || push_mission_sequence_member(state, event, key)) return 1;
+    if (push_common_member(state, event, key) || push_mission_sequence_member(state, event, key))
+        return 1;
     if (event_surface_visible(state, event.kind)) {
         if (push_slot_identity_member(state, event, key)) return 1;
-        if (key == "generation") { lua_pushinteger(state, event.ghostGeneration); return 1; }
-        if (key == "progress") { lua_pushnumber(state, event.ghostProgress); return 1; }
-        if (key == "active") { lua_pushboolean(state, event.ghostActive); return 1; }
+        if (key == "generation") {
+            lua_pushinteger(state, event.ghostGeneration);
+            return 1;
+        }
+        if (key == "progress") {
+            lua_pushnumber(state, event.ghostProgress);
+            return 1;
+        }
+        if (key == "active") {
+            lua_pushboolean(state, event.ghostActive);
+            return 1;
+        }
     }
     lua_pushnil(state);
     return 1;
@@ -479,14 +519,20 @@ push_joined_revision_member(lua_State* state, const host::Event& event, std::str
     return 1;
 }
 
+/** Lua index for one fireteam state event: the alive, dead and unknown counts. */
 [[nodiscard]] int fireteam_state_index(lua_State* state) {
-    const auto& event=check_event(state,1);
-    const auto key=lua_string_view(state,2);
-    if (push_common_member(state,event,key) || push_mission_sequence_member(state,event,key)) return 1;
-    if (key=="alive_count") lua_pushinteger(state,event.fireteamAlive);
-    else if (key=="dead_count") lua_pushinteger(state,event.fireteamDead);
-    else if (key=="unknown_count") lua_pushinteger(state,event.fireteamUnknown);
-    else lua_pushnil(state);
+    const auto& event = check_event(state, 1);
+    const auto key = lua_string_view(state, 2);
+    if (push_common_member(state, event, key) || push_mission_sequence_member(state, event, key))
+        return 1;
+    if (key == "alive_count")
+        lua_pushinteger(state, event.fireteamAlive);
+    else if (key == "dead_count")
+        lua_pushinteger(state, event.fireteamDead);
+    else if (key == "unknown_count")
+        lua_pushinteger(state, event.fireteamUnknown);
+    else
+        lua_pushnil(state);
     return 1;
 }
 
@@ -494,7 +540,7 @@ push_joined_revision_member(lua_State* state, const host::Event& event, std::str
 
 /** Installs the derived and internal view metatables. */
 void register_derived_event_metatables(lua_State* state) {
-    register_metatable(state,kFireteamStateEventMetatable,&fireteam_state_index);
+    register_metatable(state, kFireteamStateEventMetatable, &fireteam_state_index);
     register_metatable(state, kTriggerEnteredEventMetatable, &trigger_entered_index);
     register_metatable(state, kTriggerExitedEventMetatable, &trigger_exited_index);
     register_metatable(state, kSquadStateEventMetatable, &squad_state_index);

+ 3 - 1
Sunrise/src/server/activity/mission/mission_script_lua_key_api.cpp

@@ -19,13 +19,15 @@ namespace {
     return 1;
 }
 
+/** Lua index for one request key: matches and value. */
 [[nodiscard]] int request_key_index(lua_State* state) {
     static_cast<void>(luaL_checkudata(state, 1, kRequestKeyMetatable));
     const std::string_view key = lua_string_view(state, 2);
     if (key == "matches") {
         lua_pushcfunction(state, &request_key_matches);
     } else if (key == "value") {
-        const auto* handle = static_cast<const RequestKeyHandle*>(luaL_checkudata(state, 1, kRequestKeyMetatable));
+        const auto* handle =
+            static_cast<const RequestKeyHandle*>(luaL_checkudata(state, 1, kRequestKeyMetatable));
         push_u64_string(state, handle->key);
     } else {
         lua_pushnil(state);

+ 29 - 26
Sunrise/src/server/activity/mission/mission_script_lua_slot_api.cpp

@@ -300,16 +300,13 @@ constexpr std::size_t kOccupancyAuthByteCount = 11;
                                          .elementIndex = resolved.elementIndex,
                                          .state = static_cast<std::int8_t>(directiveState),
                                          .visible = true};
-    if (!optional_slot_reference(state,
-                                 "audience",
-                                 scriptable_auth::kType70SlotType,
-                                 preset.audience)) {
-        return luaL_error(state, "directive audience requires an authored type-70 engagement sensor");
-    }
-    if (!optional_slot_reference(state,
-                                 "navpoint",
-                                 scriptable_auth::kType47SlotType,
-                                 preset.navpoint)) {
+    if (!optional_slot_reference(
+            state, "audience", scriptable_auth::kType70SlotType, preset.audience)) {
+        return luaL_error(state,
+                          "directive audience requires an authored type-70 engagement sensor");
+    }
+    if (!optional_slot_reference(
+            state, "navpoint", scriptable_auth::kType47SlotType, preset.navpoint)) {
         return luaL_error(state, "directive navpoint requires a current authored type-47 slot");
     }
     std::array<std::byte, scriptable_auth::kType68ByteCount> body{};
@@ -433,12 +430,12 @@ constexpr std::int8_t kFilterModeInside = 1;
                 || volume.slotType != auth::kType60SlotType) {
                 return luaL_error(state, "inside_any requires authored type-60 volumes");
             }
-            body.predicates[body.count++] = auth::Type34ModeFlagSlotRef{
-                kFilterModeDirect,
-                true,
-                {volume.registryKey,
-                 static_cast<std::int8_t>(auth::kType60SlotType),
-                 static_cast<std::int16_t>(volume.slotIndex)}};
+            body.predicates[body.count++] =
+                auth::Type34ModeFlagSlotRef{kFilterModeDirect,
+                                            true,
+                                            {volume.registryKey,
+                                             static_cast<std::int8_t>(auth::kType60SlotType),
+                                             static_cast<std::int16_t>(volume.slotIndex)}};
             lua_pop(state, 1);
         }
     }
@@ -459,7 +456,8 @@ constexpr std::int8_t kFilterModeInside = 1;
         return luaL_error(state, "filter inside must be an authored type-60 volume");
     }
     if (inside.slotIndex >= 0) {
-        body.predicates[body.count++] = auth::Type34ModeFlagSlotRef{kFilterModeInside, false, inside};
+        body.predicates[body.count++] =
+            auth::Type34ModeFlagSlotRef{kFilterModeInside, false, inside};
     }
     std::array<std::byte, auth::kType34MaximumByteCount> bytes{};
     std::size_t written = 0;
@@ -488,7 +486,8 @@ constexpr std::int8_t kFilterModeInside = 1;
         const bool present = !lua_isnil(state, -1);
         lua_pop(state, 1);
         if (!present
-            || !optional_slot_reference(state, "filter", scriptable_auth::kType34SlotType, filter)) {
+            || !optional_slot_reference(
+                state, "filter", scriptable_auth::kType34SlotType, filter)) {
             return luaL_error(state, "mission effect requires a type-34 filter");
         }
     }
@@ -572,7 +571,8 @@ constexpr std::int8_t kFilterModeInside = 1;
     namespace object = middleware::bap::activity_message::interactable_object;
     const auto* const handle =
         static_cast<const SlotHandle*>(luaL_checkudata(state, 1, kSlotMetatable));
-    static constexpr std::array<std::string_view, 3> kDeclared{"generation", "track_owner", "active"};
+    static constexpr std::array<std::string_view, 3> kDeclared{
+        "generation", "track_owner", "active"};
     refuse_unknown_arguments(state, kDeclared);
     SlotDefinition slot{};
     if (!current_slot(state, *handle, slot) || !exact_object_slot(slot)) {
@@ -688,7 +688,8 @@ constexpr std::int8_t kFilterModeInside = 1;
 }
 
 /** @return True when one live Slot row is an exact squad in the given registry. */
-[[nodiscard]] bool exact_squad_of(const SlotDefinition& squad, const SlotDefinition& owner) noexcept {
+[[nodiscard]] bool exact_squad_of(const SlotDefinition& squad,
+                                  const SlotDefinition& owner) noexcept {
     return squad.slotType == format::kSquadSlotType
            && squad.componentClass == format::kSquadComponentClass
            && (squad.flags & format::kSlotSchemaJoinExact) != 0
@@ -723,8 +724,8 @@ constexpr std::int8_t kFilterModeInside = 1;
     if (!valid_counter(revision) || group < objective::kNoTaskGroup
         || group >= objective::kTaskGroupCount
         || target.slotIndex > auth_fields::kMaximumClientRefIndex) {
-        return luaL_error(
-            state, "combat objective revision, group or index is outside its native range");
+        return luaL_error(state,
+                          "combat objective revision, group or index is outside its native range");
     }
     std::array<std::byte, objective::kBytes> body{};
     if (!objective::encode({target.registryKey,
@@ -759,8 +760,8 @@ constexpr std::int8_t kFilterModeInside = 1;
     }
     if (!valid_counter(generation) || !valid_counter(revision)
         || path.slotIndex > auth_fields::kMaximumClientRefIndex) {
-        return luaL_error(
-            state, "actor path generation, revision or index is outside its native range");
+        return luaL_error(state,
+                          "actor path generation, revision or index is outside its native range");
     }
     std::array<std::byte, combatant::kPathBytes> body{};
     if (!combatant::encode_path({static_cast<std::uint32_t>(generation),
@@ -865,7 +866,8 @@ constexpr std::int8_t kFilterModeInside = 1;
     SlotDefinition actor{};
     if (!current_slot(state, *handle, actor) || !exact_combatant_slot(actor)
         || !valid_counter(generation) || !valid_counter(revision)) {
-        return luaL_error(state, "delivery requires an exact actor and positive generation/revision");
+        return luaL_error(state,
+                          "delivery requires an exact actor and positive generation/revision");
     }
     lua_getfield(state, 2, "squads");
     luaL_checktype(state, -1, LUA_TTABLE);
@@ -901,7 +903,8 @@ constexpr std::int8_t kFilterModeInside = 1;
     SlotDefinition actor{};
     if (!current_slot(state, *handle, actor) || !exact_combatant_slot(actor)
         || !valid_counter(generation)) {
-        return luaL_error(state, "actor retirement requires an exact member and positive generation");
+        return luaL_error(state,
+                          "actor retirement requires an exact member and positive generation");
     }
     std::array<std::byte, combatant::kRetireBytes> body{};
     if (!combatant::encode_retire(static_cast<std::uint32_t>(generation), body)) {

+ 1 - 0
Sunrise/src/server/activity/mission/mission_script_lua_value_api.cpp

@@ -137,6 +137,7 @@ vector_squad(lua_State* state, const SquadCountVectorHandle& handle, SquadDefini
 
 } // namespace
 
+/** @return The stable Lua name of one squad mode. */
 std::string_view squad_mode_name(std::uint8_t mode) noexcept {
     if (mode == kSquadModeReinforce) {
         return "reinforce";

+ 4 - 2
Sunrise/src/server/activity/mission/mission_script_runtime.cpp

@@ -288,8 +288,10 @@ void clear_instance(RuntimeInstance& instance, bool clearPending) noexcept {
     instance.objectiveObservations = {};
     instance.sessionRoster = {};
     instance.sessionRosterObserved = false;
-    instance.playerLife={};instance.playerLifeGeneration=0;
-    instance.lastFireteamLife={};instance.fireteamLifePublished=false;
+    instance.playerLife = {};
+    instance.playerLifeGeneration = 0;
+    instance.lastFireteamLife = {};
+    instance.fireteamLifePublished = false;
     std::vector<host::Event>{}.swap(instance.scriptEvents);
     instance.firstScriptEventAttempt = 0;
     instance.nextScriptEventAttempt = 0;

+ 2 - 3
Sunrise/src/server/activity/mission/mission_script_runtime_dispatch.cpp

@@ -563,9 +563,8 @@ void dispatch_intent(RuntimeInstance& instance, std::uint64_t now) noexcept {
             report_intent_status(
                 instance,
                 kIntentStatusSceneLeasePending,
-                written > 0
-                    ? std::string_view{detail.data(), static_cast<std::size_t>(written)}
-                    : scenes::status_name(status));
+                written > 0 ? std::string_view{detail.data(), static_cast<std::size_t>(written)}
+                            : scenes::status_name(status));
         } else {
             refuse_delivery(instance,
                             sequence ? "sequence_refused" : "cinematic_refused",

+ 39 - 28
Sunrise/src/server/activity/mission/mission_script_runtime_edges.cpp

@@ -1,7 +1,7 @@
 #include <algorithm>
 #include <array>
-#include <cstddef>
 #include <cmath>
+#include <cstddef>
 #include <cstdint>
 #include <cstdio>
 #include <span>
@@ -115,8 +115,13 @@ sense_value(std::span<const sense_values::DecodedValue> body,
     if (spare == nullptr) {
         for (SquadObservation& retained : instance.squadObservations) {
             bool empty = retained.aliveCount == 0;
-            for (const auto count : retained.slotCounts) empty = empty && count == 0;
-            if (empty) { retained = {}; spare = &retained; break; }
+            for (const auto count : retained.slotCounts)
+                empty = empty && count == 0;
+            if (empty) {
+                retained = {};
+                spare = &retained;
+                break;
+            }
         }
     }
     if (spare == nullptr) {
@@ -430,6 +435,7 @@ template <typename Row, std::size_t N>
     return spare;
 }
 
+/** Raises one event per named actor whose movement or delivery level changed. */
 void push_actor_path_edges(RuntimeInstance& instance,
                            const host::SenseObservationSnapshot& sense) noexcept {
     namespace auth = middleware::bap::activity_message::scriptable_auth;
@@ -438,7 +444,8 @@ void push_actor_path_edges(RuntimeInstance& instance,
         if (!observation_of(observation, sense, auth::kType2SlotType, auth::kType2SenseSchema)) {
             continue;
         }
-        ActorPathObservation* const slot = find_slot_row(instance.actorPathObservations, observation.key);
+        ActorPathObservation* const slot =
+            find_slot_row(instance.actorPathObservations, observation.key);
         if (slot == nullptr
             || !update_actor_path_level(
                 slot->level, observation_values(observation, sense), observation.key.schemaRow)) {
@@ -454,18 +461,19 @@ void push_actor_path_edges(RuntimeInstance& instance,
         event.actorDeliveryKnown = (slot->level.seen & kActorSeenDelivery) == kActorSeenDelivery;
         event.actorDead = slot->level.dead;
         std::array<char, 160> details{};
-        const int written = std::snprintf(details.data(),
-                                          details.size(),
-                                          "registry=%08X slot=%u generation=%d revision=%d "
-                                          "state=%d dead=%u delivery_revision=%d delivery_state=%d",
-                                          slot->registryKey,
-                                          static_cast<unsigned>(slot->slotIndex),
-                                          slot->level.generation,
-                                          slot->level.revision,
-                                          slot->level.state,
-                                          slot->level.dead ? 1U : 0U,
-                                          event.actorDeliveryKnown ? slot->level.deliveryRevision : -1,
-                                          event.actorDeliveryKnown ? slot->level.deliveryState : -1);
+        const int written =
+            std::snprintf(details.data(),
+                          details.size(),
+                          "registry=%08X slot=%u generation=%d revision=%d "
+                          "state=%d dead=%u delivery_revision=%d delivery_state=%d",
+                          slot->registryKey,
+                          static_cast<unsigned>(slot->slotIndex),
+                          slot->level.generation,
+                          slot->level.revision,
+                          slot->level.state,
+                          slot->level.dead ? 1U : 0U,
+                          event.actorDeliveryKnown ? slot->level.deliveryRevision : -1,
+                          event.actorDeliveryKnown ? slot->level.deliveryState : -1);
         if (written > 0 && static_cast<std::size_t>(written) < details.size()) {
             log_line(core::log::Level::debug,
                      &instance,
@@ -477,6 +485,7 @@ void push_actor_path_edges(RuntimeInstance& instance,
     }
 }
 
+/** Raises one event per damage monitor whose health, shield or revision changed. */
 void push_damage_edges(RuntimeInstance& instance,
                        const host::SenseObservationSnapshot& sense) noexcept {
     namespace damage = middleware::bap::activity_message::damage_monitor;
@@ -519,14 +528,15 @@ void push_damage_edges(RuntimeInstance& instance,
         event.damageShield = shield;
         event.damageRevision = revision;
         std::array<char, 128> details{};
-        const int written = std::snprintf(details.data(),
-                                          details.size(),
-                                          "registry=%08X slot=%u revision=%d health=%.4f shield=%.4f",
-                                          observation.key.registryKey,
-                                          static_cast<unsigned>(observation.key.slotIndex),
-                                          revision,
-                                          static_cast<double>(health),
-                                          static_cast<double>(shield));
+        const int written =
+            std::snprintf(details.data(),
+                          details.size(),
+                          "registry=%08X slot=%u revision=%d health=%.4f shield=%.4f",
+                          observation.key.registryKey,
+                          static_cast<unsigned>(observation.key.slotIndex),
+                          revision,
+                          static_cast<double>(health),
+                          static_cast<double>(shield));
         if (written > 0 && static_cast<std::size_t>(written) < details.size()) {
             log_line(core::log::Level::debug,
                      &instance,
@@ -538,6 +548,7 @@ void push_damage_edges(RuntimeInstance& instance,
     }
 }
 
+/** Raises object state and accepted interaction events per interactable object. */
 void push_object_interaction_edges(RuntimeInstance& instance,
                                    const host::SenseObservationSnapshot& sense) noexcept {
     for (std::size_t index = 0; index < sense.observationCount; ++index) {
@@ -598,6 +609,7 @@ void push_object_interaction_edges(RuntimeInstance& instance,
     }
 }
 
+/** Raises one event per Ghost link whose level changed. */
 void push_ghost_edges(RuntimeInstance& instance,
                       const host::SenseObservationSnapshot& sense) noexcept {
     namespace ghost = middleware::bap::activity_message::ghost_link;
@@ -658,10 +670,9 @@ void push_squad_edges(RuntimeInstance& instance,
         const bool first = !squad->used;
         squad->used = true;
         const std::int32_t previousAlive = first ? 0 : squad->aliveCount;
-        const bool changed = costsChanged || first || squad->aliveCount != alive
-                             || squad->removalFlag != removal
-                             || squad->slotCountLength != countLength
-                             || squad->slotCounts != counts;
+        const bool changed =
+            costsChanged || first || squad->aliveCount != alive || squad->removalFlag != removal
+            || squad->slotCountLength != countLength || squad->slotCounts != counts;
         if (!changed) {
             continue;
         }

+ 1 - 2
Sunrise/src/server/activity/mission/mission_script_runtime_feed.cpp

@@ -139,8 +139,7 @@ void clear_pending_event(PendingMissionEvent& pending) noexcept {
            || event.kind == host::EventKind::ghostLinkState
            || event.kind == host::EventKind::cinematicSkipRequested
            || event.kind == host::EventKind::cinematicTerminated
-           || delivery_lifecycle_event(event.kind)
-           || event.has_sense_observations();
+           || delivery_lifecycle_event(event.kind) || event.has_sense_observations();
 }
 
 /** Faults the instance unless the ordered mission input arrives with no gap, starting at one. */

+ 5 - 1
Sunrise/src/server/activity/mission/mission_script_vm.cpp

@@ -147,7 +147,11 @@ inline constexpr std::array<const char*, host::kEventKindCount> kEventHandlerNam
     "on_event_damage_state",
 }};
 
-static_assert([] { for (const auto* name : kEventHandlerNames) if (name == nullptr) return false; return true; }());
+static_assert([] {
+    for (const auto* name : kEventHandlerNames)
+        if (name == nullptr) return false;
+    return true;
+}());
 
 /** Captures immutable callback references while table access remains inside lua_pcall. */
 [[nodiscard]] int capture_program(lua_State* state) {

+ 2 - 2
Sunrise/src/server/bap/bap_route.cpp

@@ -10,8 +10,8 @@
 #include <string_view>
 
 #include "../../core/logging/log.h"
-#include "../../state/activity/runtime.h"
 #include "../../state/activity/membership/activity_membership_query.h"
+#include "../../state/activity/runtime.h"
 #include "../../state/build_data/runtime.h"
 #include "../../state/matchmaking/matchmaking_state.h"
 #include "../../state/runtime/runtime.h"
@@ -19,9 +19,9 @@
 #include "activity_authority_query_owner.h"
 #include "activity_authority_reset_owner.h"
 #include "activity_mission_seed_lease.h"
-#include "encrypted/push/activity/mission_seed_world_change.h"
 #include "core/threading/srw_lock.h"
 #include "encrypted/bap_connection_publication.h"
+#include "encrypted/push/activity/mission_seed_world_change.h"
 #include "internal.h"
 #include "runtime.h"
 

+ 2 - 1
Sunrise/src/server/bap/encrypted/push/activity/activity_keepalive_push.cpp

@@ -441,7 +441,8 @@ bool consume_activity_keepalive(Session& session,
     const bool needsRepublish =
         (advertisedRegionReady
          || state::activity::membership::host_teleport_armed(session.activity.session.sessionId)
-         || state::activity::membership::hard_wipe_needs_publish(session.activity.session.sessionId))
+         || state::activity::membership::hard_wipe_needs_publish(
+             session.activity.session.sessionId))
         && state::activity::membership::acknowledged(session.activity.session.sessionId);
     bool preparedRepublish = needsRepublish
                              && state::activity::membership::prepare_republish(

+ 1 - 1
Sunrise/src/server/bap/encrypted/push/activity/activity_roster_snapshot.cpp

@@ -5,9 +5,9 @@
 #include <string_view>
 #include <vector>
 
+#include "../../../../../middleware/bap/activity_message/darkness_zone_auth.h"
 #include "../../../../../middleware/content/packages/tables/region_reader.h"
 #include "../../../../../state/activity/defaults/activity_defaults_snapshot.h"
-#include "../../../../../middleware/bap/activity_message/darkness_zone_auth.h"
 #include "../../../../../state/activity/destination/activity_destination_spawn_binding.h"
 #include "../../../../../state/activity/membership/activity_membership_query.h"
 #include "../../../../../state/activity/runtime.h"

+ 1 - 1
Sunrise/src/server/transport/bap_listener.cpp

@@ -1,5 +1,4 @@
 #include "bap_listener.h"
-#include "bap_frame_batch.h"
 
 #include <WS2tcpip.h>
 #include <WinSock2.h>
@@ -9,6 +8,7 @@
 #include "../../core/logging/log.h"
 #include "../../core/settings/settings.h"
 #include "../activity/host_runtime.h"
+#include "bap_frame_batch.h"
 #include "core/threading/data_mutex.h"
 #include "internal.h"
 

+ 2 - 1
Sunrise/src/state/activity/membership/activity_membership_query.cpp

@@ -82,7 +82,8 @@ bool arm_hard_wipe(const SessionBinding& binding,
                    std::uint64_t requestKey,
                    std::int32_t region,
                    std::uint32_t spawnSetHash) noexcept {
-    if (requestKey == 0 || region < 0 || spawnSetHash == 0 || spawnSetHash == kInvalidSpawnSetHash) {
+    if (requestKey == 0 || region < 0 || spawnSetHash == 0
+        || spawnSetHash == kInvalidSpawnSetHash) {
         return false;
     }
     bool accepted = false;