Skip to content

feat(manage_gameobject): add is_static parameter to modify action - #1005

Merged
Scriptwonder merged 3 commits into
CoplayDev:betafrom
Sibirius:feature/manage-gameobject-is-static
Apr 1, 2026
Merged

feat(manage_gameobject): add is_static parameter to modify action#1005
Scriptwonder merged 3 commits into
CoplayDev:betafrom
Sibirius:feature/manage-gameobject-is-static

Conversation

@Sibirius

@Sibirius Sibirius commented Mar 30, 2026

Copy link
Copy Markdown

Summary

manage_gameobject serializes isStatic in read output but the modify action has no parameter to write it. AI clients can see whether a GameObject is static, but can't change it.

This adds is_static (bool) to the modify action, closing the read/write gap.

Motivation

Setting up scenes programmatically requires marking objects as static for lightmap baking, navigation, occlusion culling, and batching. Without this parameter, the only workaround is a custom Editor script invoked via execute_menu_item.

Usage

# Set a ground plane to static
manage_gameobject(action="modify", target="Ground", is_static=True)

# Clear static flags
manage_gameobject(action="modify", target="Ground", is_static=False)

# CLI
unity-mcp gameobject modify "Ground" --static
unity-mcp gameobject modify "Ground" --no-static

Omitting is_static leaves the flag unchanged (fully backwards compatible).

Changes

  • C# (GameObjectModify.cs): isStatic parameter handling after the existing layer block
  • Python MCP tool (manage_gameobject.py): is_static parameter with bool coercion
  • Python CLI (gameobject.py): --static/--no-static flag on modify
  • Tests (test_manage_gameobject_is_static.py): 4 integration tests

Test plan

  • is_static=True / False forwarded correctly
  • String coercion ("true"True)
  • Omission excludes key from params
  • Existing tests pass (no regression)

Documentation Updates

  • I have added/removed/modified tools or resources
    • Adds a parameter to an existing tool. Docs list tools by name only, no changes needed.

Summary by Sourcery

Add support for modifying a GameObject's static flag through the manage_gameobject tool, Unity handler, and CLI.

New Features:

  • Expose an is_static parameter on the manage_gameobject modify action to control a GameObject's static flag.
  • Add --static/--no-static options to the gameobject modify CLI command to toggle static state.

Enhancements:

  • Update the Unity GameObjectModify handler to apply the isStatic parameter by setting all StaticEditorFlags on or off.

Tests:

  • Add integration tests to verify is_static forwarding, string-to-bool coercion, and omission behavior for manage_gameobject.

Summary by CodeRabbit

  • New Features

    • You can now toggle a GameObject's static flag with the gameobject modify command using the --static/--no-static option; when set, the object's static state will be updated along with other modifications.
  • Tests

    • Added integration tests to verify static flag handling, boolean coercion, and omission when the option is not provided.
Sebastian Muehr and others added 2 commits March 30, 2026 22:38
manage_gameobject already serializes isStatic in read output
(GameObjectSerializer, GameObjectResource) but the modify action
had no parameter to write it.

This adds is_static (bool) across all three layers:
- C#: GameObjectModify.cs calls GameObjectUtility.SetStaticEditorFlags()
- Python MCP tool: manage_gameobject.py with coerce_bool normalization
- Python CLI: gameobject.py with --static/--no-static flag

When true, all static flags are set; when false, all are cleared.
Omitting the parameter is a no-op (fully backwards compatible).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Tests cover: is_static=True, is_static=False, string coercion
("true" → True), and omission (isStatic excluded from params).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@sourcery-ai

sourcery-ai Bot commented Mar 30, 2026

Copy link
Copy Markdown
Contributor

Reviewer's Guide

Adds an is_static/isStatic parameter end-to-end (CLI, Python tool, Unity editor handler) to allow the manage_gameobject modify action to set or clear a GameObject’s static flags, plus tests for forwarding and coercion behavior.

Sequence diagram for manage_gameobject modify with is_static propagation

sequenceDiagram
    actor AIClient
    participant ManageGameobjectTool as ManageGameobjectTool_Python
    participant UnityMCP as UnityMCP_Server
    participant GameObjectModify as GameObjectModify_CSharp

    AIClient->>ManageGameobjectTool: manage_gameobject(action=modify, target, is_static)
    ManageGameobjectTool->>ManageGameobjectTool: coerce_bool(is_static)
    ManageGameobjectTool->>UnityMCP: POST manage_gameobject params including isStatic
    UnityMCP->>GameObjectModify: Handle(params)
    GameObjectModify->>GameObjectModify: read isStatic from params
    GameObjectModify->>GameObjectModify: SetStaticEditorFlags(targetGo, flags)
    GameObjectModify-->>UnityMCP: modified GameObject
    UnityMCP-->>ManageGameobjectTool: response
    ManageGameobjectTool-->>AIClient: updated GameObject data including isStatic
Loading

Class diagram for manage_gameobject and GameObjectModify is_static handling

classDiagram
    class GameObjectCLICommand {
        +modify(target str, search_method str, tag str, layer str, active bool, static bool, add_components str, remove_components str)
    }

    class ManageGameobjectTool {
        +manage_gameobject(action str, target str, search_method str, prefab_name str, prefab_folder str, save_as_prefab bool, set_active bool, layer str, is_static bool, components_to_remove list~str~, component_properties dict~str, dict~str, any~~, world_space bool, position any, rotation any, scale any)
        -coerce_bool(value any, default bool)
    }

    class GameObjectModify {
        +Handle(params JObject, targetToken JToken, searchMethod string) object
        -ApplyLayer(targetGo GameObject, layer string)
        -ApplyActive(targetGo GameObject, setActive bool)
        -ApplyStatic(targetGo GameObject, isStatic bool)
    }

    GameObjectCLICommand --> ManageGameobjectTool : builds params
    ManageGameobjectTool --> GameObjectModify : passes isStatic in params
    GameObjectModify ..> GameObject : modifies isStatic and StaticEditorFlags
    GameObjectModify ..> StaticEditorFlags : uses for SetStaticEditorFlags
    GameObjectModify ..> GameObjectUtility : calls SetStaticEditorFlags
Loading

File-Level Changes

Change Details Files
Expose a --static/--no-static flag on the gameobject CLI modify command and forward it into the params payload as isStatic.
  • Add a Click option pair --static/--no-static to the gameobject modify command with a nullable bool default.
  • Extend the modify() function signature to accept a static: Optional[bool] argument.
  • When static is not None, add an isStatic entry to the outgoing params dict.
  • Update the modify() docstring examples to show usage of the new --static flag.
Server/src/cli/commands/gameobject.py
Add is_static support to the manage_gameobject Python MCP tool and forward it to Unity with proper boolean/string coercion.
  • Extend manage_gameobject() signature with an is_static parameter that accepts bool or str and documents its semantics.
  • Normalize is_static with the existing coerce_bool helper alongside other boolean params.
  • Include isStatic in the params payload for modify actions when is_static is not None.
Server/src/services/tools/manage_gameobject.py
Handle incoming isStatic in the Unity GameObjectModify editor tool by toggling all StaticEditorFlags when requested.
  • Read an optional bool? isStatic from the params JObject.
  • If a value is provided and differs from targetGo.isStatic, compute full static flags (~0) when true or 0 when false.
  • Apply the flags using GameObjectUtility.SetStaticEditorFlags and mark the object as modified.
MCPForUnity/Editor/Tools/GameObjects/GameObjectModify.cs
Add integration tests to verify is_static forwarding, coercion, and omission behavior in the manage_gameobject tool.
  • Test that is_static=True results in params["isStatic"] is True for modify.
  • Test that is_static=False results in params["isStatic"] is False for modify.
  • Test that string "true" is coerced to True for is_static and forwarded as such.
  • Test that omitting is_static results in no isStatic key in the sent params.
Server/tests/integration/test_manage_gameobject_is_static.py

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai

coderabbitai Bot commented Mar 30, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 500cdb71-c92f-4e0c-82dd-86536739b846

📥 Commits

Reviewing files that changed from the base of the PR and between 2d3c71e and 632488c.

📒 Files selected for processing (2)
  • MCPForUnity/Editor/Tools/GameObjects/GameObjectModify.cs
  • Server/tests/integration/test_manage_gameobject_is_static.py
✅ Files skipped from review due to trivial changes (1)
  • Server/tests/integration/test_manage_gameobject_is_static.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • MCPForUnity/Editor/Tools/GameObjects/GameObjectModify.cs

📝 Walkthrough

Walkthrough

Adds optional static-flag support end-to-end: a CLI --static/--no-static option, service-layer is_static parameter forwarding (coerced to boolean), Unity Editor handling of isStatic to set or clear StaticEditorFlags, and integration tests validating parameter propagation and coercion.

Changes

Cohort / File(s) Summary
Unity Editor
MCPForUnity/Editor/Tools/GameObjects/GameObjectModify.cs
Parses optional @params["isStatic"] as bool?; computes desired StaticEditorFlags (all flags vs none) and calls GameObjectUtility.SetStaticEditorFlags when different, setting modified = true.
CLI Layer
Server/src/cli/commands/gameobject.py
Adds --static/--no-static option to gameobject modify (adds static: Optional[bool] arg) and conditionally includes params["isStatic"] = static in the request payload.
Service Layer
Server/src/services/tools/manage_gameobject.py
Adds is_static parameter (accepts bool/str), coerces via coerce_bool, and forwards as isStatic in the Unity command params; retains existing validation/filtering/dispatch flow.
Integration Tests
Server/tests/integration/test_manage_gameobject_is_static.py
New async tests that monkeypatch the command sender to assert isStatic is present/coerced for True/False and string values, and omitted when is_static is not provided.

Sequence Diagram(s)

sequenceDiagram
    participant CLI
    participant Service
    participant Unity

    CLI->>Service: modify command with params (including isStatic)
    Service->>Service: coerce is_static -> boolean or remove if None
    Service->>Unity: send command params (action, target, isStatic?)
    Unity->>Unity: GameObjectModify.Handle parses params
    Unity->>Unity: compute desired StaticEditorFlags
    Unity->>Unity: if changed -> SetStaticEditorFlags(target, desiredFlags)
    Unity-->>Service: response (success/data)
    Service-->>CLI: return result
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I hopped from CLI to service lane,

whispering "static" across the plain.
Unity paused, set flags with care,
Tests nodded true — the change was fair.
A tiny hop, a steady stand, hooray!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 46.15% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: adding an is_static parameter to the manage_gameobject modify action.
Description check ✅ Passed The description includes all required sections: summary, motivation, changes made, test plan, and documentation updates checkbox, providing comprehensive context.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="Server/src/services/tools/manage_gameobject.py" line_range="186-188" />
<code_context>
             "prefabFolder": prefab_folder,
             "setActive": set_active,
             "layer": layer,
+            "isStatic": is_static,
             "componentsToRemove": components_to_remove,
             "componentProperties": component_properties,
</code_context>
<issue_to_address>
**suggestion:** Avoid sending `"isStatic": None` in the payload when no static change was requested.

`is_static` is currently coerced and left as `None` when unspecified, but the payload always includes:

```python
"isStatic": is_static,
```

so the receiver gets `"isStatic": null`. Even though the C# side handles nullable values, it’s clearer and safer to omit the key when no change is requested. Consider only adding it when `is_static is not None`:

```python
payload = {
    "prefabFolder": prefab_folder,
    "setActive": set_active,
    "layer": layer,
    # ...
}

if is_static is not None:
    payload["isStatic"] = is_static
```

This matches how other optional fields are handled and avoids relying on `null` semantics.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
Comment thread Server/src/services/tools/manage_gameobject.py

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
Server/tests/integration/test_manage_gameobject_is_static.py (1)

61-85: Add one more coercion test for "false"

You already cover "true" string coercion; adding "false" would lock in the symmetric parse path and prevent regressions in false-value serialization.

🧪 Suggested additional test
+@pytest.mark.asyncio
+async def test_manage_gameobject_is_static_string_false_coercion(monkeypatch):
+    captured = {}
+
+    async def fake_send(cmd, params, **kwargs):
+        captured["params"] = params
+        return {"success": True, "data": {}}
+
+    monkeypatch.setattr(
+        manage_go_mod,
+        "async_send_command_with_retry",
+        fake_send,
+    )
+
+    resp = await manage_go_mod.manage_gameobject(
+        ctx=DummyContext(),
+        action="modify",
+        target="Ground",
+        is_static="false",
+    )
+
+    assert resp.get("success") is True
+    assert captured["params"]["isStatic"] is False

Also applies to: 87-109

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Server/tests/integration/test_manage_gameobject_is_static.py` around lines 61
- 85, Add a mirrored test to assert string "false" is coerced to boolean False:
duplicate the existing test_manage_gameobject_is_static_string_coercion pattern
but call manage_go_mod.manage_gameobject with is_static="false", patch
manage_go_mod.async_send_command_with_retry (the fake_send that captures
params), await the response and assert resp.get("success") is True and
captured["params"]["isStatic"] is False to ensure the false-value serialization
path is covered.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@MCPForUnity/Editor/Tools/GameObjects/GameObjectModify.cs`:
- Around line 154-160: The comparison using targetGo.isStatic is wrong for
partial static objects; instead obtain the current flags via
GameObjectUtility.GetStaticEditorFlags(targetGo) and compare to the desired
flags (use desired = isStatic.Value ? (StaticEditorFlags)~0 : 0) and only call
GameObjectUtility.SetStaticEditorFlags(targetGo, desired) if currentFlags !=
desired; update the block referencing isStatic, targetGo.isStatic,
StaticEditorFlags and GameObjectUtility.SetStaticEditorFlags to use
GetStaticEditorFlags for the comparison.

---

Nitpick comments:
In `@Server/tests/integration/test_manage_gameobject_is_static.py`:
- Around line 61-85: Add a mirrored test to assert string "false" is coerced to
boolean False: duplicate the existing
test_manage_gameobject_is_static_string_coercion pattern but call
manage_go_mod.manage_gameobject with is_static="false", patch
manage_go_mod.async_send_command_with_retry (the fake_send that captures
params), await the response and assert resp.get("success") is True and
captured["params"]["isStatic"] is False to ensure the false-value serialization
path is covered.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3e496cd9-1751-44da-9f2e-f80103e3679d

📥 Commits

Reviewing files that changed from the base of the PR and between 6907bad and 2d3c71e.

📒 Files selected for processing (4)
  • MCPForUnity/Editor/Tools/GameObjects/GameObjectModify.cs
  • Server/src/cli/commands/gameobject.py
  • Server/src/services/tools/manage_gameobject.py
  • Server/tests/integration/test_manage_gameobject_is_static.py
Comment thread MCPForUnity/Editor/Tools/GameObjects/GameObjectModify.cs
…ects

targetGo.isStatic returns true when *any* flag is set, so a partially
static object (e.g. only Navigation) would skip the update when
is_static=true was requested. Compare GetStaticEditorFlags() against
the desired flags instead.

Also adds a "false" string coercion test per review feedback.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@Scriptwonder

Copy link
Copy Markdown
Collaborator

Thanks for this PR, very helpful!

@Scriptwonder
Scriptwonder merged commit 2e3e65e into CoplayDev:beta Apr 1, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

2 participants