Editor bridge toolset wrapper for GameObject operations in the MCP (manifested tooling). It defines a static class BridgeGameObjectTools with many McpTool methods that call McpGate.Run to perform scene editing tasks (create, delete, align, distribute, find, select, transform, tags, scattering, grid duplicate, etc.). Each method packages arguments and invokes the MCP gate to run the corresponding tool.
// AUTO-GENERATED by scripts/emit-mcp-wrappers.mjs — DO NOT EDIT.
// Regenerate: node scripts/extract-manifest.mjs && node scripts/emit-mcp-wrappers.mjs
// Source of truth: sbox-mcp-server/src/tools/ (zod schemas) → scripts/tools-manifest.json
using System.Text.Json.Nodes;
using System.Threading.Tasks;
using Editor.Mcp;
/// <summary>
/// GameObject lifecycle, hierarchy, transforms, tags, selection, and bulk layout (align,
/// distribute, scatter, snap-to-ground, grid duplicate) in the open scene. Objects are referenced
/// by GUID from get_scene_hierarchy or find_objects.
/// </summary>
[McpToolset( "bridge_gameobject", "GameObject lifecycle, hierarchy, transforms, tags, selection, and bulk layout (align, distribute, scatter, snap-to-ground, grid duplicate) in the open scene. Objects are referenced by GUID from get_scene_hierarchy or find_objects." )]
public static class BridgeGameObjectTools
{
/// <summary>
/// Align several GameObjects on one axis so they share a coordinate. mode = first (match the first
/// object), min, max, or average; defaults to first. Returns { aligned, axis, mode, target } —
/// aligned is the object count and target the shared coordinate; verify positions with
/// get_scene_hierarchy or a screenshot.
/// </summary>
/// <param name="ids">GUIDs of the GameObjects to align (>= 2).</param>
/// <param name="axis">Axis to align on. One of: x | y | z.</param>
/// <param name="mode">Target coordinate to align to (default first). One of: first | min | max | average.</param>
[McpTool( "align_objects" )]
public static Task<object> AlignObjects( string[] ids, string axis, string mode = null )
=> McpGate.Run( "align_objects", McpGate.Args( ( "ids", ids ), ( "axis", axis ), ( "mode", mode ) ) );
/// <summary>
/// Commit a dry-run plan returned by place_along_path, grid_duplicate, or scatter_props. Plans are
/// scene-scoped, capped, and expire after 10 minutes. Success consumes the plan; a complete
/// rollback restores it for retry. The stored transforms are applied without rerolling randomness
/// or repeating ground traces. Creation rolls back on failure; grid commits reject a
/// changed/missing source before creating anything. Returns slot-to-GUID receipts.
/// </summary>
/// <param name="planId">Plan id returned by a placement tool with dryRun:true.</param>
[McpTool( "commit_placement_plan" )]
public static Task<object> CommitPlacementPlan( string planId )
=> McpGate.Run( "commit_placement_plan", McpGate.Args( ( "planId", planId ) ) );
/// <summary>
/// Create a new GameObject in the active scene. Returns its GUID for future reference.
/// </summary>
/// <param name="name">Display name (e.g. 'Player', 'Enemy Spawn Point'). Defaults to 'New Object'.</param>
/// <param name="position">World position. As "x,y,z" (or JSON {x,y,z}).</param>
/// <param name="rotation">World rotation. As "pitch,yaw,roll" degrees.</param>
/// <param name="scale">Uniform scale (number) or per-axis scale — object {x,y,z} or comma string "x,y,z". As "x,y,z" (or JSON {x,y,z}).</param>
/// <param name="parent">GUID of parent GameObject. Omit for scene root.</param>
[McpTool( "create_gameobject" )]
public static Task<object> CreateGameobject( string name = null, string position = null, string rotation = null, string scale = null, string parent = null )
=> McpGate.Run( "create_gameobject", McpGate.Args( ( "name", name ), ( "position", position ), ( "rotation", rotation ), ( "scale", scale ), ( "parent", parent ) ) );
/// <summary>
/// Delete a GameObject from the active scene by its GUID.
/// </summary>
/// <param name="id">GUID of the GameObject to delete.</param>
[McpTool( "delete_gameobject" )]
public static Task<object> DeleteGameobject( string id )
=> McpGate.Run( "delete_gameobject", McpGate.Args( ( "id", id ) ) );
/// <summary>
/// Evenly space GameObjects along an axis between the lowest and highest (keeps the two ends fixed,
/// spreads the rest evenly). Returns { distributed, axis, from, to } — the object count and the
/// fixed end coordinates the rest were spread between.
/// </summary>
/// <param name="ids">GUIDs of the GameObjects to distribute (>= 3).</param>
/// <param name="axis">Axis to distribute along. One of: x | y | z.</param>
[McpTool( "distribute_objects" )]
public static Task<object> DistributeObjects( string[] ids, string axis )
=> McpGate.Run( "distribute_objects", McpGate.Args( ( "ids", ids ), ( "axis", axis ) ) );
/// <summary>
/// Clone a GameObject with all its components. Returns { duplicated, original, gameObject } —
/// gameObject.id is the clone's new GUID; pass it to set_transform / add_component_with_properties.
/// If offset is omitted the clone lands exactly on top of the original.
/// </summary>
/// <param name="id">GUID of the GameObject to duplicate.</param>
/// <param name="name">New name for the clone.</param>
/// <param name="offset">Position offset from original so the clone doesn't overlap. As "x,y,z" (or JSON {x,y,z}).</param>
[McpTool( "duplicate_gameobject" )]
public static Task<object> DuplicateGameobject( string id, string name = null, string offset = null )
=> McpGate.Run( "duplicate_gameobject", McpGate.Args( ( "id", id ), ( "name", name ), ( "offset", offset ) ) );
/// <summary>
/// Query the scene for GameObjects by name (case-insensitive substring), component type name,
/// and/or tag — combine filters (AND). Returns {id,name} for matches (limit default 50, max 500).
/// Read-only; works during play. Use it to get GUIDs to feed into
/// align/distribute/set_tint/group/delete/etc.
/// </summary>
/// <param name="name">Name substring (case-insensitive).</param>
/// <param name="component">Component type name, e.g. 'PointLight', 'SkinnedModelRenderer'.</param>
/// <param name="tag">Tag the object must have.</param>
/// <param name="limit">Max results (default 50, max 500).</param>
[McpTool.ReadOnly( "find_objects" )]
public static Task<object> FindObjects( string name = null, string component = null, string tag = null, int? limit = null )
=> McpGate.Run( "find_objects", McpGate.Args( ( "name", name ), ( "component", component ), ( "tag", tag ), ( "limit", limit ) ) );
/// <summary>
/// Find GameObjects within a world-space radius of exactly one explicit position or originId,
/// sorted nearest first. Optional name/component/tag filters are applied before the capped result,
/// and the Scene root is excluded. Returns pivot-distance results plus
/// requestedRadius/radiusClamped and total/showing/truncated/scanned; it deliberately does not
/// pretend render or collider overlap is pivot distance. Read-only and play-aware.
/// </summary>
/// <param name="position">World-space search center; use instead of originId. As "x,y,z" (or JSON {x,y,z}).</param>
/// <param name="originId">GameObject GUID whose world position is the center.</param>
/// <param name="radius">Search radius in world units (default 256, max 1,000,000).</param>
/// <param name="limit">Maximum results (default 50).</param>
/// <param name="name">Case-insensitive GameObject name substring.</param>
/// <param name="component">Required component type name.</param>
/// <param name="tag">Required GameObject tag.</param>
/// <param name="includeOrigin">Include originId itself (default false).</param>
[McpTool.ReadOnly( "find_objects_near" )]
public static Task<object> FindObjectsNear( string position = null, string originId = null, double? radius = null, int? limit = null, string name = null, string component = null, string tag = null, bool? includeOrigin = null )
=> McpGate.Run( "find_objects_near", McpGate.Args( ( "position", position ), ( "originId", originId ), ( "radius", radius ), ( "limit", limit ), ( "name", name ), ( "component", component ), ( "tag", tag ), ( "includeOrigin", includeOrigin ) ) );
/// <summary>
/// Highlight a GameObject by selecting it in the editor. NOTE: s&box exposes no dedicated focus
/// API, so this only sets the selection — it does NOT move any camera (returns { focused, id, note
/// } saying so). To actually point the viewport at an object use frame_camera; to aim a screenshot
/// use screenshot_from.
/// </summary>
/// <param name="id">GUID of the GameObject to focus.</param>
[McpTool( "focus_object" )]
public static Task<object> FocusObject( string id )
=> McpGate.Run( "focus_object", McpGate.Args( ( "id", id ) ) );
/// <summary>
/// Get provenance-rich world bounds for a GameObject. Preserves legacy top-level
/// center/size/extents/mins/maxs/radius/position/empty for compatibility, and adds render plus
/// independent physics and solidPhysics aggregates. Collider outputs include trigger policy, capped
/// contributor GameObject IDs and component type names, unsupported counts, and the exact API
/// source. Read-only and play-aware.
/// </summary>
/// <param name="id">GUID of the GameObject to measure.</param>
[McpTool.ReadOnly( "get_bounds" )]
public static Task<object> GetBounds( string id )
=> McpGate.Run( "get_bounds", McpGate.Args( ( "id", id ) ) );
/// <summary>
/// Get the scene tree — GameObjects with their names, GUIDs, components, and parent/child
/// relationships. Pair maxDepth with rootId to drill into a subtree without paying for the whole
/// scene.
/// </summary>
/// <param name="maxDepth">Maximum recursion depth. Defaults to 10. Use 1 or 2 for cheap top-level overviews.</param>
/// <param name="rootId">Optional GUID of a GameObject to start traversal from. Omit to walk from the scene roots.</param>
[McpTool.ReadOnly( "get_scene_hierarchy" )]
public static Task<object> GetSceneHierarchy( int? maxDepth = null, string rootId = null )
=> McpGate.Run( "get_scene_hierarchy", McpGate.Args( ( "maxDepth", maxDepth ), ( "rootId", rootId ) ) );
/// <summary>
/// Get the GameObjects currently selected by the user in the s&box editor. Returns { count,
/// selected } where each entry is a serialized GameObject (id, name, enabled, position, rotation,
/// scale, components, childCount) — use the ids with set_transform, add_component_with_properties,
/// etc. Handy for 'do X to what I have selected' requests.
/// </summary>
[McpTool.ReadOnly( "get_selected_objects" )]
public static Task<object> GetSelectedObjects()
=> McpGate.Run( "get_selected_objects", McpGate.Args() );
/// <summary>
/// Read the tags currently on a GameObject. (Pair with set_tags to add/remove/clear, and
/// find_objects to query by tag.).
/// </summary>
/// <param name="id">GUID of the GameObject.</param>
[McpTool.ReadOnly( "get_tags" )]
public static Task<object> GetTags( string id )
=> McpGate.Run( "get_tags", McpGate.Args( ( "id", id ) ) );
/// <summary>
/// Clone a GameObject into an X/Y/Z grid. Existing calls mutate immediately and keep the legacy
/// result. Use dryRun:true to preview exact capped transforms and receive a planId;
/// commit_placement_plan then clones atomically and rejects the commit if the source transform or
/// parent changed after preview.
/// </summary>
/// <param name="id">GUID of the GameObject to clone.</param>
/// <param name="countX">Copies along X (default 1).</param>
/// <param name="countY">Copies along Y (default 1).</param>
/// <param name="countZ">Copies along Z (default 1).</param>
/// <param name="spacing">Spacing between copies per axis (default 100,100,100). As "x,y,z" (or JSON {x,y,z}).</param>
/// <param name="dryRun">Preview only: return deterministic transforms and planId without cloning.</param>
[McpTool( "grid_duplicate" )]
public static Task<object> GridDuplicate( string id, int? countX = null, int? countY = null, int? countZ = null, string spacing = null, bool? dryRun = null )
=> McpGate.Run( "grid_duplicate", McpGate.Args( ( "id", id ), ( "countX", countX ), ( "countY", countY ), ( "countZ", countZ ), ( "spacing", spacing ), ( "dryRun", dryRun ) ) );
/// <summary>
/// Parent a set of GameObjects under a new empty group object (placed at their centroid) — tidies
/// the hierarchy and lets you move/rotate them together.
/// </summary>
/// <param name="ids">GUIDs of the GameObjects to group.</param>
/// <param name="name">Name for the group object (default 'Group').</param>
[McpTool( "group_objects" )]
public static Task<object> GroupObjects( string[] ids, string name = null )
=> McpGate.Run( "group_objects", McpGate.Args( ( "ids", ids ), ( "name", name ) ) );
/// <summary>
/// Measure the distance between two points or two GameObjects. Provide a/b as {x,y,z} or idA/idB as
/// GUIDs. Returns straight-line distance, horizontal (ground) distance, and the delta vector.
/// Read-only (works during play).
/// </summary>
/// <param name="a">First point {x,y,z}. As "x,y,z" (or JSON {x,y,z}).</param>
/// <param name="b">Second point {x,y,z}. As "x,y,z" (or JSON {x,y,z}).</param>
/// <param name="idA">First GameObject GUID (overrides a).</param>
/// <param name="idB">Second GameObject GUID (overrides b).</param>
[McpTool.ReadOnly( "measure_distance" )]
public static Task<object> MeasureDistance( string a = null, string b = null, string idA = null, string idB = null )
=> McpGate.Run( "measure_distance", McpGate.Args( ( "a", a ), ( "b", b ), ( "idA", idA ), ( "idB", idB ) ) );
/// <summary>
/// Add natural variation to existing objects: random yaw and/or random uniform scale within a
/// range. Great for breaking up repetition in placed foliage/rocks/crates. Seeded — the same seed
/// reproduces the same layout. Returns { randomized, seed } (the count of objects changed); scale
/// only varies when scaleMax > scaleMin.
/// </summary>
/// <param name="ids">GUIDs of the GameObjects to randomize.</param>
/// <param name="randomYaw">Randomize Z rotation (default true).</param>
/// <param name="scaleMin">Min uniform scale (default 1).</param>
/// <param name="scaleMax">Max uniform scale (default 1; set >min to vary).</param>
/// <param name="seed">PRNG seed (default 1).</param>
[McpTool( "randomize_transforms" )]
public static Task<object> RandomizeTransforms( string[] ids, bool? randomYaw = null, double? scaleMin = null, double? scaleMax = null, int? seed = null )
=> McpGate.Run( "randomize_transforms", McpGate.Args( ( "ids", ids ), ( "randomYaw", randomYaw ), ( "scaleMin", scaleMin ), ( "scaleMax", scaleMax ), ( "seed", seed ) ) );
/// <summary>
/// Change the display name of a GameObject identified by its GUID (the GUID itself never changes,
/// so existing references stay valid). Returns { renamed, id, oldName, newName }. Name-based
/// lookups (e.g. find_objects) will see the new name immediately.
/// </summary>
/// <param name="id">GUID of the GameObject.</param>
/// <param name="name">New display name.</param>
[McpTool( "rename_gameobject" )]
public static Task<object> RenameGameobject( string id, string name )
=> McpGate.Run( "rename_gameobject", McpGate.Args( ( "id", id ), ( "name", name ) ) );
/// <summary>
/// Swap the model on one object (id) or many (ids) — e.g. retheme a row of props in one call.
/// </summary>
/// <param name="model">New model path, e.g. 'models/dev/sphere.vmdl'.</param>
/// <param name="id">Single GameObject GUID.</param>
/// <param name="ids">Multiple GameObject GUIDs.</param>
[McpTool( "replace_model" )]
public static Task<object> ReplaceModel( string model, string id = null, string[] ids = null )
=> McpGate.Run( "replace_model", McpGate.Args( ( "model", model ), ( "id", id ), ( "ids", ids ) ) );
/// <summary>
/// Scatter seeded model copies inside a radius. Existing calls mutate immediately and keep the
/// legacy { scattered, groupId, seed } result. Use dryRun:true to resolve random transforms and
/// ground traces once, returning per-slot transforms, ground status, warnings, model bounds, and
/// planId; commit_placement_plan creates exactly that preview with rollback on failure.
/// </summary>
/// <param name="model">Model path to scatter, e.g. 'models/dev/box.vmdl'.</param>
/// <param name="center">Centre of the scatter area (default origin). As "x,y,z" (or JSON {x,y,z}).</param>
/// <param name="radius">Scatter radius in units (default 256).</param>
/// <param name="count">How many to place (default 10, max 300).</param>
/// <param name="randomYaw">Randomly rotate each around Z (default true).</param>
/// <param name="snapToGround">Raycast each onto the surface below (default true).</param>
/// <param name="scaleMin">Min uniform scale (default 1).</param>
/// <param name="scaleMax">Max uniform scale (default 1; set >min for size variation).</param>
/// <param name="tint">Tint applied to every copy — object {r,g,b,a} or comma string "r,g,b,a". As "r,g,b[,a]" (0-1 floats).</param>
/// <param name="seed">PRNG seed for a reproducible layout (default 1).</param>
/// <param name="group">Parent all copies under one group object (default true).</param>
/// <param name="name">Base name for the props/group (default 'Prop').</param>
/// <param name="dryRun">Preview only: return deterministic transforms and planId without creating props.</param>
[McpTool( "scatter_props" )]
public static Task<object> ScatterProps( string model, string center = null, double? radius = null, int? count = null, bool? randomYaw = null, bool? snapToGround = null, double? scaleMin = null, double? scaleMax = null, string tint = null, int? seed = null, bool? group = null, string name = null, bool? dryRun = null )
=> McpGate.Run( "scatter_props", McpGate.Args( ( "model", model ), ( "center", center ), ( "radius", radius ), ( "count", count ), ( "randomYaw", randomYaw ), ( "snapToGround", snapToGround ), ( "scaleMin", scaleMin ), ( "scaleMax", scaleMax ), ( "tint", tint ), ( "seed", seed ), ( "group", group ), ( "name", name ), ( "dryRun", dryRun ) ) );
/// <summary>
/// Select a GameObject in the editor (highlights it in the hierarchy and scene view). Replaces the
/// current selection unless addToSelection=true. Returns { selected, id }; confirm the result with
/// get_selected_objects.
/// </summary>
/// <param name="id">GUID of the GameObject to select.</param>
/// <param name="addToSelection">If true, adds to current selection instead of replacing it.</param>
[McpTool( "select_object" )]
public static Task<object> SelectObject( string id, bool? addToSelection = null )
=> McpGate.Run( "select_object", McpGate.Args( ( "id", id ), ( "addToSelection", addToSelection ) ) );
/// <summary>
/// Enable or disable a GameObject (disabled objects are invisible and inactive, including their
/// components and children). Returns { id, enabled } confirming the new state.
/// </summary>
/// <param name="id">GUID of the GameObject.</param>
/// <param name="enabled">true to enable, false to disable.</param>
[McpTool( "set_enabled" )]
public static Task<object> SetEnabled( string id, bool enabled )
=> McpGate.Run( "set_enabled", McpGate.Args( ( "id", id ), ( "enabled", enabled ) ) );
/// <summary>
/// Reparent a GameObject. Set parentId to null or omit to move to scene root.
/// </summary>
/// <param name="id">GUID of the GameObject to reparent.</param>
/// <param name="parentId">GUID of the new parent. Null or omitted = scene root.</param>
[McpTool( "set_parent" )]
public static Task<object> SetParent( string id, string parentId = null )
=> McpGate.Run( "set_parent", McpGate.Args( ( "id", id ), ( "parentId", parentId ) ) );
/// <summary>
/// Add, remove, and/or clear gameplay tags on one object (id) or many (ids). Tags drive collision
/// groups, queries, and triggers.
/// </summary>
/// <param name="id">Single GameObject GUID.</param>
/// <param name="ids">Multiple GameObject GUIDs.</param>
/// <param name="add">Tags to add.</param>
/// <param name="remove">Tags to remove.</param>
/// <param name="clear">Remove all existing tags first.</param>
[McpTool( "set_tags" )]
public static Task<object> SetTags( string id = null, string[] ids = null, string[] add = null, string[] remove = null, bool? clear = null )
=> McpGate.Run( "set_tags", McpGate.Args( ( "id", id ), ( "ids", ids ), ( "add", add ), ( "remove", remove ), ( "clear", clear ) ) );
/// <summary>
/// Set the renderer tint colour on one object (id) or many (ids) at once. Works on any
/// ModelRenderer/SkinnedModelRenderer. Pass the colour as "tint" (or its alias "color"); each
/// accepts an object {r,g,b,a} OR a comma string "r,g,b,a".
/// </summary>
/// <param name="id">Single GameObject GUID.</param>
/// <param name="ids">Multiple GameObject GUIDs.</param>
/// <param name="tint">Tint colour to apply (object or comma string). As "r,g,b[,a]" (0-1 floats).</param>
/// <param name="color">Alias for "tint" (object or comma string). As "r,g,b[,a]" (0-1 floats).</param>
[McpTool( "set_tint" )]
public static Task<object> SetTint( string id = null, string[] ids = null, string tint = null, string color = null )
=> McpGate.Run( "set_tint", McpGate.Args( ( "id", id ), ( "ids", ids ), ( "tint", tint ), ( "color", color ) ) );
/// <summary>
/// Atomically set position, rotation, and/or scale on a GameObject. All supplied values are parsed
/// before mutation; values apply in world space by default. Prefer space='local' or space='world';
/// local remains a legacy alias. Returns legacy { transformed, gameObject } plus before/after
/// transform and bounds receipts.
/// </summary>
/// <param name="id">GUID of the GameObject.</param>
/// <param name="position">New position. As "x,y,z" (or JSON {x,y,z}).</param>
/// <param name="rotation">New rotation. As "pitch,yaw,roll" degrees.</param>
/// <param name="scale">New scale — uniform number, per-axis object {x,y,z}, or comma string "x,y,z". As "x,y,z" (or JSON {x,y,z}).</param>
/// <param name="local">Legacy alias: true selects local space and false selects world space.</param>
/// <param name="space">Explicit transform space. If supplied with local, both values must agree. One of: world | local.</param>
[McpTool( "set_transform" )]
public static Task<object> SetTransform( string id, string position = null, string rotation = null, string scale = null, bool? local = null, string space = null )
=> McpGate.Run( "set_transform", McpGate.Args( ( "id", id ), ( "position", position ), ( "rotation", rotation ), ( "scale", scale ), ( "local", local ), ( "space", space ) ) );
/// <summary>
/// Drop a GameObject straight down onto the surface below it (physics raycast). Works best on
/// collider-less props (an object with its own collider may self-hit). Optional offset lifts it off
/// the surface. Returns { snapped, groundZ, gameObject } with the object's updated transform — or {
/// snapped: false, reason } (not an error) when no ground was hit below.
/// </summary>
/// <param name="id">GUID of the GameObject to snap.</param>
/// <param name="offset">Height above the surface to place it (default 0).</param>
/// <param name="startHeight">How far above the object to start the trace (default 2000).</param>
/// <param name="maxDistance">Max trace distance downward (default 20000).</param>
[McpTool( "snap_to_ground" )]
public static Task<object> SnapToGround( string id, double? offset = null, double? startHeight = null, double? maxDistance = null )
=> McpGate.Run( "snap_to_ground", McpGate.Args( ( "id", id ), ( "offset", offset ), ( "startHeight", startHeight ), ( "maxDistance", maxDistance ) ) );
}