80 {.name =
"scene_create_entities_batch",
82 "Create empty entities in one undoable action. Each item: name (required), optional "
83 "parent_id, position/rotation_euler/scale, space (world default|local).",
85 R
"json({"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"parent_id":{"type":"string"},"space":{"type":"string","enum":["world","local"]},"position":{"type":"array","items":{"type":"number"},"minItems":3,"maxItems":3},"rotation_euler":{"type":"array","items":{"type":"number"},"minItems":3,"maxItems":3},"scale":{"type":"array","items":{"type":"number"},"minItems":3,"maxItems":3}},"required":["name"]}}},"required":["items"]})json",
93 return {.text =
error, .is_error =
true};
95 simdjson::dom::array items_arr;
96 if(!read_items_array(args, items_arr,
error))
98 return {.text =
error, .is_error =
true};
107 std::vector<item_t>
items;
108 for(
auto el : items_arr)
110 simdjson::dom::object obj;
113 return {.text =
"Each item must be an object", .is_error =
true};
116 if(!
read_string(obj,
"name", item.name) || item.name.empty())
118 return {.text =
"Item missing name", .is_error =
true};
121 item.is_local = item_space_is_local(obj);
123 items.push_back(std::move(item));
127 return {.text =
"items array is empty", .is_error =
true};
129 std::vector<entt::handle> created;
132 "MCP Batch Create Entities",
136 created.reserve(
items.size());
137 for(
const auto& item :
items)
139 entt::handle parent{};
140 if(!item.parent_id.empty())
150 created.push_back(
entity);
154 return summarize_created(created,
items.size());
156 .mutates_scene =
true});
159 {.name =
"scene_create_from_prefab_batch",
161 "Instantiate prefab assets in one undoable action. Each item: asset_key (required), "
162 "optional name/parent_id, position/rotation_euler/scale, space (world default|local).",
164 R
"json({"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"asset_key":{"type":"string"},"name":{"type":"string"},"parent_id":{"type":"string"},"space":{"type":"string","enum":["world","local"]},"position":{"type":"array","items":{"type":"number"},"minItems":3,"maxItems":3},"rotation_euler":{"type":"array","items":{"type":"number"},"minItems":3,"maxItems":3},"scale":{"type":"array","items":{"type":"number"},"minItems":3,"maxItems":3}},"required":["asset_key"]}}},"required":["items"]})json",
168 scene* scn =
nullptr;
172 return {.text =
error, .is_error =
true};
174 simdjson::dom::array items_arr;
175 if(!read_items_array(args, items_arr,
error))
177 return {.text =
error, .is_error =
true};
181 std::string asset_key;
187 std::vector<item_t>
items;
188 for(
auto el : items_arr)
190 simdjson::dom::object obj;
193 return {.text =
"Each item must be an object", .is_error =
true};
196 if(!
read_string(obj,
"asset_key", item.asset_key) || item.asset_key.empty())
198 return {.text =
"Item missing asset_key", .is_error =
true};
202 item.is_local = item_space_is_local(obj);
204 items.push_back(std::move(item));
208 return {.text =
"items array is empty", .is_error =
true};
210 std::vector<entt::handle> created;
213 "MCP Batch Create Prefabs",
217 for(
const auto& item :
items)
220 if(item.pose.has_position && !item.is_local)
232 if(!item.name.empty())
236 tag->name = item.name;
239 if(!item.parent_id.empty())
248 created.push_back(
entity);
252 return summarize_created(created,
items.size());
254 .mutates_scene =
true});
257 {.name =
"scene_create_meshes_batch",
259 "Create mesh entities from asset keys in one undoable action. Each item: asset_key "
260 "(required), optional name/parent_id, position/rotation_euler/scale, space.",
262 R
"json({"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"asset_key":{"type":"string"},"name":{"type":"string"},"parent_id":{"type":"string"},"space":{"type":"string","enum":["world","local"]},"position":{"type":"array","items":{"type":"number"},"minItems":3,"maxItems":3},"rotation_euler":{"type":"array","items":{"type":"number"},"minItems":3,"maxItems":3},"scale":{"type":"array","items":{"type":"number"},"minItems":3,"maxItems":3}},"required":["asset_key"]}}},"required":["items"]})json",
266 scene* scn =
nullptr;
270 return {.text =
error, .is_error =
true};
272 simdjson::dom::array items_arr;
273 if(!read_items_array(args, items_arr,
error))
275 return {.text =
error, .is_error =
true};
279 std::string asset_key;
285 std::vector<item_t>
items;
286 for(
auto el : items_arr)
288 simdjson::dom::object obj;
291 return {.text =
"Each item must be an object", .is_error =
true};
294 if(!
read_string(obj,
"asset_key", item.asset_key) || item.asset_key.empty())
296 return {.text =
"Item missing asset_key", .is_error =
true};
300 item.is_local = item_space_is_local(obj);
302 items.push_back(std::move(item));
306 return {.text =
"items array is empty", .is_error =
true};
308 std::vector<entt::handle> created;
311 "MCP Batch Create Meshes",
315 for(
const auto& item :
items)
317 const math::vec3 spawn =
318 (!item.is_local && item.pose.has_position) ? item.pose.position : math::vec3{0, 0, 0};
324 if(!item.name.empty())
328 tag->name = item.name;
331 if(!item.parent_id.empty())
340 created.push_back(
entity);
344 return summarize_created(created,
items.size());
346 .mutates_scene =
true});
349 {.name =
"scene_set_parents_batch",
351 "Reparent many entities in one undoable action. Each item: entity_id, optional parent_id "
352 "(omit/empty to detach). Keeps WORLD pose.",
354 R
"json({"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"entity_id":{"type":"string"},"parent_id":{"type":"string"}},"required":["entity_id"]}}},"required":["items"]})json",
358 scene* scn =
nullptr;
362 return {.text =
error, .is_error =
true};
364 simdjson::dom::array items_arr;
365 if(!read_items_array(args, items_arr,
error))
367 return {.text =
error, .is_error =
true};
372 entt::handle old_parent{};
373 entt::handle new_parent{};
376 for(
auto el : items_arr)
378 simdjson::dom::object obj;
381 return {.text =
"Each item must be an object", .is_error =
true};
383 std::string entity_id;
386 return {.text =
"Item missing entity_id", .is_error =
true};
391 return {.text =
"Entity not found or missing transform: " + entity_id, .is_error =
true};
402 return {.text =
"Parent not found: " +
parent_id, .is_error =
true};
409 return {.text =
"items array is empty", .is_error =
true};
413 "MCP Batch Set Parents",
434 return {.text = fmt::format(R
"({{"ok":true,"count":{}}})", entries.size()), .is_error = false};
436 .mutates_scene =
true});
439 {.name =
"scene_set_names_batch",
440 .description =
"Set display names on many entities in one undoable action.",
442 R
"json({"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"entity_id":{"type":"string"},"name":{"type":"string"}},"required":["entity_id","name"]}}},"required":["items"]})json",
446 scene* scn =
nullptr;
450 return {.text =
error, .is_error =
true};
452 simdjson::dom::array items_arr;
453 if(!read_items_array(args, items_arr,
error))
455 return {.text =
error, .is_error =
true};
460 std::string old_name;
461 std::string new_name;
464 for(
auto el : items_arr)
466 simdjson::dom::object obj;
469 return {.text =
"Each item must be an object", .is_error =
true};
471 std::string entity_id;
475 return {.text =
"Item missing entity_id or name", .is_error =
true};
480 return {.text =
"Entity not found: " + entity_id, .is_error =
true};
486 return {.text =
"items array is empty", .is_error =
true};
490 "MCP Batch Set Names",
497 tag->name = e.new_name;
507 tag->name = e.old_name;
511 return {.text = fmt::format(R
"({{"ok":true,"count":{}}})", entries.size()), .is_error = false};
513 .mutates_scene =
true});
516 {.name =
"scene_set_active_batch",
517 .description =
"Set active flags on many entities in one undoable action.",
519 R
"json({"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"entity_id":{"type":"string"},"active":{"type":"boolean"}},"required":["entity_id","active"]}}},"required":["items"]})json",
523 scene* scn =
nullptr;
527 return {.text =
error, .is_error =
true};
529 simdjson::dom::array items_arr;
530 if(!read_items_array(args, items_arr,
error))
532 return {.text =
error, .is_error =
true};
537 bool old_active{
true};
538 bool new_active{
true};
541 for(
auto el : items_arr)
543 simdjson::dom::object obj;
546 return {.text =
"Each item must be an object", .is_error =
true};
548 std::string entity_id;
552 return {.text =
"Item missing entity_id or active", .is_error =
true};
557 return {.text =
"Entity not found: " + entity_id, .is_error =
true};
563 return {.text =
"items array is empty", .is_error =
true};
567 "MCP Batch Set Active",
588 return {.text = fmt::format(R
"({{"ok":true,"count":{}}})", entries.size()), .is_error = false};
590 .mutates_scene =
true});
593 {.name =
"scene_add_components_batch",
595 "Add engine components to many entities in one undoable action. Use "
596 "scene_list_component_types for valid names.",
598 R
"json({"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"entity_id":{"type":"string"},"component_type":{"type":"string"}},"required":["entity_id","component_type"]}}},"required":["items"]})json",
602 scene* scn =
nullptr;
606 return {.text =
error, .is_error =
true};
608 simdjson::dom::array items_arr;
609 if(!read_items_array(args, items_arr,
error))
611 return {.text =
error, .is_error =
true};
616 entt::meta_type
type{};
619 for(
auto el : items_arr)
621 simdjson::dom::object obj;
624 return {.text =
"Each item must be an object", .is_error =
true};
626 std::string entity_id;
627 std::string component_type;
630 return {.text =
"Item missing entity_id or component_type", .is_error =
true};
635 return {.text =
"Entity not found: " + entity_id, .is_error =
true};
637 auto type = resolve_addable_component(component_type);
640 return {.text =
"Unknown or non-addable component_type: " + component_type, .is_error =
true};
646 return {.text =
"items array is empty", .is_error =
true};
653 return {.text = fmt::format(R
"({{"ok":true,"count":{}}})", entries.size()), .is_error = false};
655 .mutates_scene =
true});
658 {.name =
"scene_remove_components_batch",
659 .description =
"Remove components from many entities in one undoable action.",
661 R
"json({"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"entity_id":{"type":"string"},"component_type":{"type":"string"}},"required":["entity_id","component_type"]}}},"required":["items"]})json",
665 scene* scn =
nullptr;
669 return {.text =
error, .is_error =
true};
671 simdjson::dom::array items_arr;
672 if(!read_items_array(args, items_arr,
error))
674 return {.text =
error, .is_error =
true};
679 entt::meta_type
type{};
682 for(
auto el : items_arr)
684 simdjson::dom::object obj;
687 return {.text =
"Each item must be an object", .is_error =
true};
689 std::string entity_id;
690 std::string component_type;
693 return {.text =
"Item missing entity_id or component_type", .is_error =
true};
698 return {.text =
"Entity not found: " + entity_id, .is_error =
true};
700 auto type = resolve_addable_component(component_type);
703 type = entt::resolve(entt::hashed_string{component_type.c_str()});
707 return {.text =
"Unknown component_type: " + component_type, .is_error =
true};
713 return {.text =
"items array is empty", .is_error =
true};
720 return {.text = fmt::format(R
"({{"ok":true,"count":{}}})", entries.size()), .is_error = false};
722 .mutates_scene =
true});
725 {.name =
"scene_add_scripts_batch",
727 "Add C# ScriptComponent types to many entities. type_name from scripts_list_types.",
729 R
"json({"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"entity_id":{"type":"string"},"type_name":{"type":"string"}},"required":["entity_id","type_name"]}}},"required":["items"]})json",
733 scene* scn =
nullptr;
737 return {.text =
error, .is_error =
true};
741 return {.text =
"Script system unavailable", .is_error =
true};
743 simdjson::dom::array items_arr;
744 if(!read_items_array(args, items_arr,
error))
746 return {.text =
error, .is_error =
true};
751 for(
auto el : items_arr)
753 simdjson::dom::object obj;
756 return {.text =
"Each item must be an object", .is_error =
true};
758 std::string entity_id;
759 std::string type_name;
762 return {.text =
"Item missing entity_id or type_name", .is_error =
true};
767 return {.text =
"Entity not found: " + entity_id, .is_error =
true};
769 if(!script_sys.get_type_by_fullname(type_name).valid())
771 return {.text =
"Unknown script type: " + type_name, .is_error =
true};
776 return {.text = fmt::format(R
"({{"ok":true,"count":{}}})", count), .is_error = count == 0};
778 .mutates_scene = true});
781 {.name =
"scene_remove_scripts_batch",
782 .description =
"Remove C# ScriptComponent types from many entities by type_name.",
784 R
"json({"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"entity_id":{"type":"string"},"type_name":{"type":"string"}},"required":["entity_id","type_name"]}}},"required":["items"]})json",
788 scene* scn =
nullptr;
792 return {.text =
error, .is_error =
true};
794 simdjson::dom::array items_arr;
795 if(!read_items_array(args, items_arr,
error))
797 return {.text =
error, .is_error =
true};
801 for(
auto el : items_arr)
803 simdjson::dom::object obj;
806 return {.text =
"Each item must be an object", .is_error =
true};
808 std::string entity_id;
809 std::string type_name;
812 return {.text =
"Item missing entity_id or type_name", .is_error =
true};
817 return {.text =
"Entity not found: " + entity_id, .is_error =
true};
822 return {.text = fmt::format(R
"({{"ok":true,"count":{}}})", count), .is_error = count == 0};
824 .mutates_scene = true});
827 {.name =
"scene_get_transforms_batch",
829 "Get transforms for many entities. Each item: entity_id, optional space world|local "
830 "(omit space for both, same as scene_list_entities_batch fields).",
832 R
"json({"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"entity_id":{"type":"string"},"space":{"type":"string","enum":["world","local"]}},"required":["entity_id"]}}},"required":["items"]})json",
838 if(!scn || !scn->registry)
840 return {.text =
"No active scene", .is_error =
true};
842 simdjson::dom::array items_arr;
844 if(!read_items_array(args, items_arr,
error))
846 return {.text =
error, .is_error =
true};
848 std::string json =
"[";
850 for(
auto el : items_arr)
852 simdjson::dom::object obj;
855 return {.text =
"Each item must be an object", .is_error =
true};
857 std::string entity_id;
860 return {.text =
"Item missing entity_id", .is_error =
true};
865 return {.text =
"Entity not found or missing transform: " + entity_id, .is_error =
true};
882 return {.text =
error, .is_error =
true};
885 const auto pos =
is_local ? t.get_position_local() : t.get_position_global();
886 const auto rot =
is_local ? t.get_rotation_euler_local() : t.get_rotation_euler_global();
887 const auto scl =
is_local ? t.get_scale_local() : t.get_scale_global();
889 R
"({{"id":{},"space":{},"position":[{:.6g},{:.6g},{:.6g}],"rotation_euler":[{:.6g},{:.6g},{:.6g}],"scale":[{:.6g},{:.6g},{:.6g}]}})",
905 return {.text = fmt::format(R
"({{"transforms":{},"count":{}}})", json, count), .is_error = false};
907 .mutates_scene =
false});
910 {.name =
"scene_inspect_entities_batch",
912 "Inspect many entities. Provide entity_ids array, or items with entity_id. Optional "
913 "include_components (default false).",
915 R
"json({"type":"object","properties":{"entity_ids":{"type":"array","items":{"type":"string"}},"items":{"type":"array","items":{"type":"object","properties":{"entity_id":{"type":"string"}},"required":["entity_id"]}},"include_components":{"type":"boolean"}}})json",
919 bool include_components =
false;
920 read_bool(args,
"include_components", include_components);
921 std::vector<std::string> ids;
922 simdjson::dom::array id_arr;
923 if(!args[
"entity_ids"].get(id_arr))
925 for(
auto el : id_arr)
927 std::string_view id_view;
930 return {.text =
"entity_ids must be strings", .is_error =
true};
932 ids.emplace_back(id_view);
935 simdjson::dom::array items_arr;
936 if(!args[
"items"].get(items_arr))
938 for(
auto el : items_arr)
940 simdjson::dom::object obj;
943 return {.text =
"Each item must be an object", .is_error =
true};
945 std::string entity_id;
948 return {.text =
"Item missing entity_id", .is_error =
true};
950 ids.push_back(entity_id);
955 return {.text =
"Provide entity_ids or items", .is_error =
true};
957 std::string json =
"[";
958 for(
size_t i = 0; i < ids.size(); ++i)
968 return {.text =
error.empty() ?
"Inspect failed" :
error, .is_error =
true};
973 return {.text = fmt::format(R
"({{"entities":{},"count":{}}})", json, ids.size()), .is_error = false};
975 .mutates_scene =
false});
978 {.name =
"scene_list_scripts_batch",
979 .description =
"List ScriptComponent instances on many entities (entity_ids required).",
981 R
"json({"type":"object","properties":{"entity_ids":{"type":"array","items":{"type":"string"}}},"required":["entity_ids"]})json",
987 if(!scn || !scn->registry)
989 return {.text =
"No active scene", .is_error =
true};
991 simdjson::dom::array ids;
992 if(args[
"entity_ids"].get(ids))
994 return {.text =
"Missing entity_ids", .is_error =
true};
996 std::string json =
"[";
1000 std::string_view id_view;
1003 return {.text =
"entity_ids must be strings", .is_error =
true};
1008 return {.text =
"Entity not found: " + std::string(id_view), .is_error =
true};
1014 std::string scripts =
"[";
1015 bool first_script =
true;
1018 for(
const auto& obj : sc->get_script_components())
1028 first_script =
false;
1029 const auto type_name = obj.pinned->get_object().get_type().get_fullname();
1030 const auto source = sc->get_script_source_location(obj);
1031 scripts += fmt::format(R
"({{"type":{},"source_path":{}}})",
1037 json += fmt::format(R
"({{"entity_id":{},"scripts":{}}})",
1043 return {.text = fmt::format(R
"({{"entities":{},"count":{}}})", json, count), .is_error = false};
1045 .mutates_scene =
false});
std::tuple< test_component, model_component, animation_component, camera_component, volume_component, auto_exposure_component, tonemapping_component, assao_component, bloom_component, fxaa_component, taa_component, ssr_component, ssil_component, light_component, skylight_component, reflection_probe_component, physics_component, character_controller_component, audio_source_component, audio_listener_component, text_component, particle_emitter_component, ui_document_component > all_addable_components