feat: add component reference wiring — get_referenceable, set_reference, batch_wire#1043
feat: add component reference wiring — get_referenceable, set_reference, batch_wire#1043zaferdace wants to merge 2 commits intoCoplayDev:mainfrom
Conversation
…ce, batch_wire Extends manage_components with 3 new actions for object reference fields: - get_referenceable: list assignable scene objects and project assets for a component's reference field, with type filtering - set_reference: assign an object reference via path, asset path, or instance ID, with SerializedProperty + Undo support - batch_wire: wire multiple references atomically in one call, with validation-first approach and grouped Undo C# uses SerializedObject/SerializedProperty for correct prefab override tracking, dirty state, and Undo. Reference resolution supports scene objects, project assets, and component auto-resolution from GameObjects.
Reviewer's GuideExtends the existing manage_components tool with three new actions (get_referenceable, set_reference, batch_wire) to support type-safe Unity object reference discovery and assignment from both Python and the Unity editor, including batch atomic wiring, Undo/prefab override correctness, and flexible reference selectors (scene path, asset path, instance ID). Sequence diagram for set_reference action in manage_componentssequenceDiagram
actor PythonClient
participant PythonTool as manage_components_py
participant UnityBridge as send_with_unity_instance
participant UnityEditor as ManageComponents_HandleCommand
participant RefHelper as SetReference
participant Validator as ValidateReferenceAssignment
PythonClient->>PythonTool: manage_components(action=set_reference, target, component_type, property, reference_path/reference_asset_path/reference_instance_id/clear)
PythonTool->>PythonTool: Build params dict
PythonTool->>UnityBridge: send_with_unity_instance("manage_components", params)
UnityBridge->>UnityEditor: HandleCommand(params)
UnityEditor->>UnityEditor: Parse action and target
UnityEditor->>RefHelper: SetReference(params, targetToken, searchMethod)
RefHelper->>RefHelper: TryGetComponentAndObjectReferenceProperty
RefHelper-->>UnityEditor: ErrorResponse? (if failure)
RefHelper->>Validator: ValidateReferenceAssignment(component, propertyName, expectedType, params)
Validator->>Validator: HasReferenceSelector / ResolveReference
Validator->>Validator: ConvertResolvedObject
Validator-->>RefHelper: ReferenceAssignmentValidation
alt validation fails
RefHelper-->>UnityEditor: ErrorResponse(validation.Error)
UnityEditor-->>UnityBridge: error payload
UnityBridge-->>PythonTool: error dict
PythonTool-->>PythonClient: error result
else validation succeeds
RefHelper->>UnityEditor: Undo.RecordObject(component)
RefHelper->>RefHelper: property.objectReferenceValue = ResolvedObject
RefHelper->>RefHelper: serializedObject.ApplyModifiedProperties
RefHelper->>UnityEditor: EditorUtility.SetDirty(component)
RefHelper->>UnityEditor: MarkOwningSceneDirty(targetGo)
RefHelper-->>UnityEditor: success payload with previous_value and new_value
UnityEditor-->>UnityBridge: success payload
UnityBridge-->>PythonTool: success dict
PythonTool-->>PythonClient: success result
end
Updated class diagram for ManageComponents reference wiringclassDiagram
class ManageComponents {
+HandleCommand(@params : JObject) object
-GetReferenceable(@params : JObject, targetToken : JToken, searchMethod : string) object
-SetReference(@params : JObject, targetToken : JToken, searchMethod : string) object
-BatchWire(@params : JObject, targetToken : JToken, searchMethod : string) object
-TryGetComponentAndObjectReferenceProperty(@params : JObject, targetToken : JToken, searchMethod : string, actionName : string, targetGo : GameObject, component : Component, serializedObject : SerializedObject, property : SerializedProperty, expectedType : Type, error : ErrorResponse) bool
-GetFieldType(component : Component, propertyName : string) Type
-ResolveReference(refParams : JObject) UnityEngine.Object
-FindReferenceableSceneObjects(expectedType : Type, limit : int) IEnumerable~object~
-FindReferenceableAssets(expectedType : Type, limit : int) IEnumerable~object~
-BuildAssetSearchFilter(expectedType : Type) string
-LoadReferenceableAssetsAtPath(assetPath : string, expectedType : Type) IEnumerable~UnityEngine.Object~
-ValidateReferenceAssignment(component : Component, propertyName : string, expectedType : Type, refParams : JObject) ReferenceAssignmentValidation
-HasReferenceSelector(refParams : JObject) bool
-ConvertResolvedObject(resolved : UnityEngine.Object, expectedType : Type) UnityEngine.Object
-DescribeObjectReference(obj : UnityEngine.Object) object
}
class ReferenceAssignmentValidation {
-PropertyName : string
-Success : bool
-Error : string
-ResolvedObject : UnityEngine.Object
+Ok(propertyName : string, resolvedObject : UnityEngine.Object) ReferenceAssignmentValidation
+Fail(propertyName : string, error : string) ReferenceAssignmentValidation
}
class BatchWireResult {
+Property : string
+Success : bool
+Error : string
+NewValue : object
+ToResponse() object
}
class GameObjectLookup {
+ResolveInstanceID(instanceId : int) UnityEngine.Object
+FindByTarget(target : JToken, searchMethod : string, includeInactive : bool) GameObject
+GetAllSceneObjects(includeInactive : bool) IEnumerable~GameObject~
+GetGameObjectPath(gameObject : GameObject) string
}
class UnityTypeResolver {
+ResolveComponent(componentType : string) Type
}
class ErrorResponse {
+ErrorResponse(message : string)
+message : string
}
class SerializedObject
class SerializedProperty {
+propertyType : SerializedPropertyType
+propertyPath : string
+objectReferenceValue : UnityEngine.Object
}
class UnityEngine.Object {
+GetInstanceID() int
+name : string
+GetType() Type
}
class Component {
+gameObject : GameObject
+GetComponent(type : Type) Component
}
class GameObject {
+name : string
+GetComponent(type : Type) Component
}
class Undo {
+RecordObject(target : UnityEngine.Object, name : string) void
+GetCurrentGroup() int
+SetCurrentGroupName(name : string) void
+CollapseUndoOperations(group : int) void
}
class AssetDatabase {
+FindAssets(filter : string) string[]
+GUIDToAssetPath(guid : string) string
+LoadAssetAtPath~T~(assetPath : string) T
+LoadAllAssetsAtPath(assetPath : string) UnityEngine.Object[]
+GetAssetPath(obj : UnityEngine.Object) string
}
class EditorUtility {
+SetDirty(obj : UnityEngine.Object) void
}
class SerializedPropertyType {
}
ManageComponents --> ReferenceAssignmentValidation : uses
ManageComponents --> BatchWireResult : uses
ManageComponents --> GameObjectLookup : uses
ManageComponents --> UnityTypeResolver : uses
ManageComponents --> ErrorResponse : returns
ManageComponents --> SerializedObject : uses
ManageComponents --> SerializedProperty : uses
ManageComponents --> Undo : uses
ManageComponents --> AssetDatabase : uses
ManageComponents --> EditorUtility : uses
ManageComponents --> Component : manipulates
ManageComponents --> GameObject : manipulates
ReferenceAssignmentValidation --> UnityEngine.Object : holds
BatchWireResult --> UnityEngine.Object : via NewValue description
File-Level Changes
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Hey - I've found 1 issue, and left some high level feedback:
- In
BatchWire, you recreate a newSerializedObjectfor the same component on everyvalidationduring apply; consider constructing it once and reusing it (or using the one fromTryGetComponentAndObjectReferenceProperty-like helper) to avoid unnecessary allocations and simplify the write path. GetFieldTypecurrently only resolves backing fields and will return null for array/list element paths or more complexSerializedPropertypaths; if you intend to support wiring into collection elements, you may want to extend this logic to derive the element type from the property path rather than simple field reflection.- There is some duplication between
SetReferenceand the apply loop inBatchWire(Undo recording,SerializedObject/SerializedPropertyhandling, marking dirty); extracting a shared helper for "apply validated reference to property" would reduce repetition and make future changes to the write semantics less error-prone.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `BatchWire`, you recreate a new `SerializedObject` for the same component on every `validation` during apply; consider constructing it once and reusing it (or using the one from `TryGetComponentAndObjectReferenceProperty`-like helper) to avoid unnecessary allocations and simplify the write path.
- `GetFieldType` currently only resolves backing fields and will return null for array/list element paths or more complex `SerializedProperty` paths; if you intend to support wiring into collection elements, you may want to extend this logic to derive the element type from the property path rather than simple field reflection.
- There is some duplication between `SetReference` and the apply loop in `BatchWire` (Undo recording, `SerializedObject`/`SerializedProperty` handling, marking dirty); extracting a shared helper for "apply validated reference to property" would reduce repetition and make future changes to the write semantics less error-prone.
## Individual Comments
### Comment 1
<location path="MCPForUnity/Editor/Tools/ManageComponents.cs" line_range="719" />
<code_context>
+
+ private static UnityEngine.Object ResolveReference(JObject refParams)
+ {
+ var instanceId = refParams["reference_instance_id"]?.Value<int>();
+ if (instanceId.HasValue)
+ return GameObjectLookup.ResolveInstanceID(instanceId.Value);
</code_context>
<issue_to_address>
**issue (bug_risk):** Use safer coercion for `reference_instance_id` to avoid exceptions on malformed input.
`JToken.Value<int>()` will throw if `reference_instance_id` is present but not a valid int (e.g., string, float, null), and this input comes from an external tool. That means a malformed payload can cause an exception before you can surface a structured validation error. Prefer using `ParamCoercion.CoerceInt(refParams[
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
- Extract ApplyReferenceToProperty shared helper to deduplicate SetReference and BatchWire write logic - BatchWire now reuses single SerializedObject instead of recreating per validation entry - ResolveReference uses ParamCoercion.CoerceInt instead of unsafe JToken.Value<int>() to prevent exceptions on malformed input - GetFieldType now handles array/list element paths (e.g., "targets.Array.data[0]") by extracting element type
Summary
Extends
manage_componentswith 3 new actions for automating object reference field assignment — the programmatic equivalent of drag-and-drop in the Inspector.New Actions
get_referenceableset_referencebatch_wireExample Usage
Implementation Details
Python (
Server/src/services/tools/manage_components.py):reference_path,reference_asset_path,reference_instance_id,references,clear,atomic,include_scene,include_assets,limitsend_with_unity_instancesame as existing actionsC# (
MCPForUnity/Editor/Tools/ManageComponents.cs):get_referenceable: resolves field type via reflection, searches scene (FindObjectsOfType) and assets (AssetDatabase.FindAssets) for matching typesset_reference: usesSerializedObject+SerializedProperty.objectReferenceValuefor correct prefab override tracking and Undo supportbatch_wire: atomic mode (default) validates all entries first, then applies all writes in a single Undo groupTryGetComponentAndObjectReferenceProperty,ResolveReference,ValidateReferenceAssignmentDesign Decisions
manage_*multi-action patternUndo.RecordObject+ grouped operations for batchGetComponentReference Selectors
reference_pathreference_asset_pathreference_instance_idclear=trueTest plan
get_referenceablereturns correct types for Transform, AudioClip, Material fieldsset_referencewith scene object pathset_referencewith project asset pathset_referencewith instance IDset_referencewithclear=trueset_referencetype mismatch returns errorbatch_wireatomic success (all valid)batch_wireatomic failure (one invalid, none applied)batch_wirenon-atomic partial successSummary by Sourcery
Extend the manage_components tool to support querying and assigning Unity object reference fields, including batch wiring of multiple references.
New Features:
Enhancements: