mission_script_lua_slot_api.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. #include <array>
  2. #include <cstddef>
  3. #include <cstdint>
  4. #include <limits>
  5. #include <span>
  6. #include <string_view>
  7. #include "../../../middleware/bap/activity_message/auth_fields.h"
  8. #include "../../../middleware/bap/activity_message/auth_schema_catalog.h"
  9. #include "mission_script_lua_internal.h"
  10. namespace sunrise::server::activity::mission::lua_vm::detail {
  11. namespace format = state::activity_sdk::format;
  12. namespace scriptable_auth = middleware::bap::activity_message::scriptable_auth;
  13. namespace auth_fields = middleware::bap::activity_message::auth_fields;
  14. namespace auth_catalog = middleware::bap::activity_message::auth_schema_catalog;
  15. /** Positive 31-bit generations and revisions are the counters every typed Auth body accepts. */
  16. [[nodiscard]] bool valid_counter(lua_Integer value) noexcept {
  17. return value > 0 && value <= auth_fields::kMaximumCounter;
  18. }
  19. /**
  20. * Reads one optional slot-handle argument into a ClientRef.
  21. * @param slotType Slot type the referenced slot must have.
  22. * @param output Left unset when the argument is nil.
  23. * @return False when the argument is present but stale or of another type.
  24. */
  25. [[nodiscard]] bool optional_slot_reference(lua_State* state,
  26. const char* name,
  27. std::uint32_t slotType,
  28. scriptable_auth::Type2LaneClientRef& output) {
  29. lua_getfield(state, 2, name);
  30. bool valid = true;
  31. if (!lua_isnil(state, -1)) {
  32. const auto* const handle =
  33. static_cast<const SlotHandle*>(luaL_checkudata(state, -1, kSlotMetatable));
  34. SlotDefinition definition{};
  35. valid = current_slot(state, *handle, definition) && definition.slotType == slotType
  36. && definition.slotIndex <= auth_fields::kMaximumClientRefIndex;
  37. if (valid) {
  38. output = {definition.registryKey,
  39. static_cast<std::int8_t>(slotType),
  40. static_cast<std::int16_t>(definition.slotIndex)};
  41. }
  42. }
  43. lua_pop(state, 1);
  44. return valid;
  45. }
  46. /** Stages one authored native Auth body on the guarded message-5 route. */
  47. [[nodiscard]] int queue_slot_auth(lua_State* state,
  48. const SlotDefinition& slot,
  49. std::uint32_t schema,
  50. std::size_t bitCount,
  51. std::span<const std::byte> body,
  52. IntentKind kind,
  53. bool active) {
  54. Impl* const impl = impl_from_state(state);
  55. std::array<std::byte, 32> sdkBuildSha256{};
  56. if (!decode_sdk_build_sha256(std::string_view(impl->identity.sdkBuildId.data()),
  57. sdkBuildSha256)) {
  58. return luaL_error(state, "loaded SDK generation identity is invalid");
  59. }
  60. CallFrame& frame = active_frame(state);
  61. Intent intent{};
  62. intent.kind = kind;
  63. intent.active = active;
  64. intent.sdkBuildSha256 = sdkBuildSha256;
  65. intent.firstRow = slot.nativeRow;
  66. if (kind == IntentKind::runActorProgram && active) {
  67. if (impl->definitions.resolveActorProgramSource == nullptr
  68. || !impl->definitions.resolveActorProgramSource(
  69. impl->definitions.context, slot.nativeRow, intent.secondRow)) {
  70. return luaL_error(state, "actor creation has no exact authored source");
  71. }
  72. }
  73. intent.objectTag = slot.objectTag;
  74. intent.registryKey = slot.registryKey;
  75. intent.authSchema = schema;
  76. intent.authBitCount = static_cast<std::uint16_t>(bitCount);
  77. intent.slotIndex = static_cast<std::uint16_t>(slot.slotIndex);
  78. intent.slotType = static_cast<std::uint8_t>(slot.slotType);
  79. intent.authByteCount = static_cast<std::uint16_t>(body.size());
  80. try {
  81. intent.authBody.assign(body.begin(), body.end());
  82. } catch (const std::bad_alloc&) {
  83. return luaL_error(state, "mission Auth body allocation failed");
  84. }
  85. return queue_intent(state, frame, intent);
  86. }
  87. /** Reads one integer field from a generated directive declaration. */
  88. [[nodiscard]] lua_Integer directive_integer(lua_State* state, int table, const char* field) {
  89. lua_getfield(state, table, field);
  90. const lua_Integer value = luaL_checkinteger(state, -1);
  91. lua_pop(state, 1);
  92. return value;
  93. }
  94. /** Reads one Slot row member, its syntax methods, and its authorized actions. */
  95. [[nodiscard]] int slot_index(lua_State* state) {
  96. const auto* const handle =
  97. static_cast<const SlotHandle*>(luaL_checkudata(state, 1, kSlotMetatable));
  98. SlotDefinition definition{};
  99. if (!current_slot(state, *handle, definition)) {
  100. return luaL_error(state, "activity slot is stale");
  101. }
  102. const std::string_view key = lua_string_view(state, 2);
  103. if (key == "row") {
  104. lua_pushinteger(state, definition.localRow);
  105. } else if (key == "applied") {
  106. lua_pushcfunction(state, &slot_applied);
  107. } else if (key == "id") {
  108. lua_pushlstring(state, definition.id.data(), definition.id.size());
  109. } else if (key == "name") {
  110. lua_pushlstring(state, definition.name.data(), definition.name.size());
  111. } else if (key == "object_id") {
  112. lua_pushlstring(state, definition.objectId.data(), definition.objectId.size());
  113. } else if (key == "object_tag") {
  114. lua_pushinteger(state, definition.objectTag);
  115. } else if (key == "registry_key") {
  116. lua_pushinteger(state, definition.registryKey);
  117. } else if (key == "slot_index") {
  118. lua_pushinteger(state, definition.slotIndex);
  119. } else if (key == "slot_type") {
  120. lua_pushinteger(state, definition.slotType);
  121. } else if (key == "component_class") {
  122. lua_pushinteger(state, definition.componentClass);
  123. } else if (key == "sense_schema") {
  124. lua_pushinteger(state, definition.senseSchema);
  125. } else if (key == "auth_schema") {
  126. lua_pushinteger(state, definition.authSchema);
  127. } else if (key == "sense_schema_id") {
  128. lua_pushlstring(state, definition.senseSchemaId.data(), definition.senseSchemaId.size());
  129. } else if (key == "auth_schema_id") {
  130. lua_pushlstring(state, definition.authSchemaId.data(), definition.authSchemaId.size());
  131. } else if (key == "auth_type" || key == "auth_min_bits" || key == "auth_max_bits"
  132. || key == "auth_component_offset" || key == "auth_dynamic"
  133. || key == "auth_writable") {
  134. const auth_catalog::Type* const auth = auth_catalog::find(
  135. static_cast<std::uint8_t>(definition.slotType), definition.authSchema);
  136. if (auth == nullptr) {
  137. lua_pushnil(state);
  138. } else if (key == "auth_type") {
  139. lua_pushlstring(state, auth->name.data(), auth->name.size());
  140. } else if (key == "auth_min_bits") {
  141. lua_pushinteger(state, auth->minimumBits);
  142. } else if (key == "auth_max_bits") {
  143. lua_pushinteger(state, auth->maximumBits);
  144. } else if (key == "auth_component_offset") {
  145. if (auth->hasContiguousMirror) {
  146. lua_pushinteger(state, auth->componentOffset);
  147. } else {
  148. lua_pushnil(state);
  149. }
  150. } else if (key == "auth_dynamic") {
  151. lua_pushboolean(state, auth->hasDynamicBody);
  152. } else {
  153. lua_pushboolean(state, auth->writable);
  154. }
  155. } else if (key == "flags") {
  156. lua_pushinteger(state, definition.flags);
  157. } else if (key == "set_object_filter") {
  158. lua_pushcfunction(state, &slot_set_object_filter);
  159. } else if (key == "watch_damage") {
  160. lua_pushcfunction(state, &slot_watch_damage);
  161. } else if (key == "set_object_active") {
  162. lua_pushcfunction(state, &slot_set_object_active);
  163. } else if (key == "set_channel") {
  164. lua_pushcfunction(state, &slot_set_channel);
  165. } else if (key == "transition") {
  166. lua_pushcfunction(state, &slot_transition);
  167. } else if (key == "set_occupancy_condition") {
  168. lua_pushcfunction(state, &slot_set_occupancy_condition);
  169. } else if (key == "generate_map") {
  170. lua_pushcfunction(state, &slot_generate_map);
  171. } else if (key == "set_directive") {
  172. lua_pushcfunction(state, &slot_set_directive);
  173. } else if (key == "clear_directives") {
  174. lua_pushcfunction(state, &slot_clear_directives);
  175. } else if (key == "set_darkness_zone") {
  176. lua_pushcfunction(state, &slot_set_darkness_zone);
  177. } else if (key == "set_music_section") {
  178. lua_pushcfunction(state, &slot_set_music_section);
  179. } else if (key == "set_interactable_object") {
  180. lua_pushcfunction(state, &slot_set_interactable_object);
  181. } else if (key == "set_ghost_link") {
  182. lua_pushcfunction(state, &slot_set_ghost_link);
  183. } else if (key == "ghost_link") {
  184. lua_pushcfunction(state, &slot_ghost_link);
  185. } else if (key == "set_public_event_state") {
  186. lua_pushcfunction(state, &slot_set_public_event_state);
  187. } else if (key == "assign_combat_objective") {
  188. lua_pushcfunction(state, &slot_assign_combat_objective);
  189. } else if (key == "play_actor_path") {
  190. lua_pushcfunction(state, &slot_play_actor_path);
  191. } else if (key == "play_actor_action") {
  192. lua_pushcfunction(state, &slot_play_actor_action);
  193. } else if (key == "retire_actor") {
  194. lua_pushcfunction(state, &slot_retire_actor);
  195. } else if (key == "bind_combatant_to_squad") {
  196. lua_pushcfunction(state, &slot_bind_combatant_to_squad);
  197. } else if (key == "run_atoms") {
  198. lua_pushcfunction(state, &slot_run_atoms);
  199. } else if (key == "fire_trigger") {
  200. lua_pushcfunction(state, &slot_fire_trigger);
  201. } else if (key == "disarm_trigger") {
  202. lua_pushcfunction(state, &slot_disarm_trigger);
  203. } else if (key == "play_sequence") {
  204. lua_pushcfunction(state,
  205. exact_combatant_slot(definition) ? &slot_play_actor_sequence
  206. : &slot_play_sequence);
  207. } else if (key == "sequences") {
  208. lua_pushcfunction(state, &slot_actor_sequences);
  209. } else if (key == "set_cinematic_active") {
  210. lua_pushcfunction(state, &slot_set_cinematic_active);
  211. } else if (key == "reset_objectives") {
  212. lua_pushcfunction(state, &slot_reset_objectives);
  213. } else if (key == "advance_task") {
  214. lua_pushcfunction(state, &slot_advance_task);
  215. } else if (key == "play_dialogue_cue") {
  216. lua_pushcfunction(state, &slot_play_dialogue_cue);
  217. } else if (key == "play_performance") {
  218. lua_pushcfunction(state, &slot_play_performance);
  219. } else {
  220. lua_pushnil(state);
  221. }
  222. return 1;
  223. }
  224. void register_slot_metatables(lua_State* state) {
  225. register_metatable(state, kSlotMetatable, &slot_index);
  226. }
  227. } // namespace sunrise::server::activity::mission::lua_vm::detail