Skip to content

fix(camera): mark replacement shader fields as assignment clone#2988

Open
cptbtptpbcptdtptp wants to merge 2 commits into
galacean:dev/2.0from
cptbtptpbcptdtptp:pr/camera-replacement-clone-mode
Open

fix(camera): mark replacement shader fields as assignment clone#2988
cptbtptpbcptdtptp wants to merge 2 commits into
galacean:dev/2.0from
cptbtptpbcptdtptp:pr/camera-replacement-clone-mode

Conversation

@cptbtptpbcptdtptp
Copy link
Copy Markdown
Collaborator

@cptbtptpbcptdtptp cptbtptpbcptdtptp commented May 11, 2026

Summary

  • Add @assignmentClone to _replacementShader and _replacementSubShaderTag so cloned cameras share the same shader/tag reference instead of deep cloning them.

Background

Extracted from ca5252a9a on fix/shaderlab. Without this, cloning a camera that has a replacement shader set would deep-clone the Shader object, creating an unnecessary duplicate.

Test plan

  • New test case: clone preserves replacement shader by reference
  • CI green

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Fixed camera component duplication to properly maintain shader state during cloning, ensuring consistent behavior when duplicating camera instances.

Review Change Stack

cptbtptpbcptdtptp and others added 2 commits May 11, 2026 18:22
Add @assignmentClone to _replacementShader and _replacementSubShaderTag
so cloned cameras share the same shader/tag reference instead of deep
cloning them (which would create unnecessary duplicates).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 11, 2026

Walkthrough

Camera's internal replacement-shader state (_replacementShader and _replacementSubShaderTag) is now decorated with @assignmentClone, ensuring these fields preserve their object references during component cloning. Import statements and test coverage are updated accordingly.

Changes

Replacement Shader Clone Preservation

Layer / File(s) Summary
Import decorator
packages/core/src/Camera.ts
CloneManager imports include assignmentClone function alongside existing clone utilities.
Apply decorator to fields
packages/core/src/Camera.ts
@assignmentClone decorator applied to _replacementShader and _replacementSubShaderTag, changing clone semantics for these internal fields.
Test coverage
tests/src/core/Camera.test.ts
Existing clone test assertions reformatted for consistency; new test validates cloned camera retains shader object reference and tag value when replacement shaders are set.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Poem

🐰 A shader shines so bright,
Clone it right, preserve the light!
With decorators, references stay true,
Two fields now know just what to do. ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: adding @assignmentClone decorator to camera replacement shader fields to fix cloning behavior.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ 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.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/src/core/Camera.test.ts`:
- Around line 432-453: Replace the string assignment and string comparison with
a proper ShaderTagKey: create a ShaderTagKey via
ShaderTagKey.getByName("TestTag"), assign that to
camera._replacementSubShaderTag (instead of the raw string), and update the
assertion to compare the cloned camera's _replacementSubShaderTag to the same
ShaderTagKey (or compare their names via .getName()) so types and semantics
match; references: camera._replacementSubShaderTag, ShaderTagKey.getByName,
cloneCamera.
🪄 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: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 1688ce5f-7744-4d70-9cf9-41db4bc2fbf8

📥 Commits

Reviewing files that changed from the base of the PR and between 1bc2b10 and 9845234.

📒 Files selected for processing (2)
  • packages/core/src/Camera.ts
  • tests/src/core/Camera.test.ts

Comment on lines +432 to +453
it("clone preserves replacement shader by reference (assignmentClone)", () => {
const shader = Shader.create("TestCloneReplaceShader", [
new SubShader("Default", [new ShaderPass("Default", [], [], ShaderLanguage.GLSLES100)])
]);

// @ts-ignore
camera._replacementShader = shader;
// @ts-ignore
camera._replacementSubShaderTag = "TestTag";

const cloneCamera = camera.entity.clone().getComponent(Camera);

// @ts-ignore - assignmentClone copies reference, not deep clone
expect(cloneCamera._replacementShader).to.eq(shader);
// @ts-ignore
expect(cloneCamera._replacementSubShaderTag).to.eq("TestTag");

// @ts-ignore - cleanup
camera._replacementShader = null;
// @ts-ignore
camera._replacementSubShaderTag = null;
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Fix type violations in replacement shader tag assignment and assertion.

The test has two critical correctness issues:

  1. Line 440: Assigns a string "TestTag" directly to _replacementSubShaderTag, but this field is typed as ShaderTagKey, not string. While @ts-ignore suppresses the type error, this violates the actual type contract.

  2. Line 447: Compares _replacementSubShaderTag to the string "TestTag". If line 440 is corrected to use a proper ShaderTagKey object, this assertion will fail since you'd be comparing an object to a string.

The proper usage pattern is shown in Camera.ts line 719: ShaderTagKey.getByName(replacementTag).

🔧 Proposed fix using ShaderTagKey.getByName()
+  const testTag = ShaderTagKey.getByName("TestTag");
+
   // `@ts-ignore`
   camera._replacementShader = shader;
   // `@ts-ignore`
-  camera._replacementSubShaderTag = "TestTag";
+  camera._replacementSubShaderTag = testTag;

   const cloneCamera = camera.entity.clone().getComponent(Camera);

   // `@ts-ignore` - assignmentClone copies reference, not deep clone
   expect(cloneCamera._replacementShader).to.eq(shader);
   // `@ts-ignore`
-  expect(cloneCamera._replacementSubShaderTag).to.eq("TestTag");
+  expect(cloneCamera._replacementSubShaderTag).to.eq(testTag);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
it("clone preserves replacement shader by reference (assignmentClone)", () => {
const shader = Shader.create("TestCloneReplaceShader", [
new SubShader("Default", [new ShaderPass("Default", [], [], ShaderLanguage.GLSLES100)])
]);
// @ts-ignore
camera._replacementShader = shader;
// @ts-ignore
camera._replacementSubShaderTag = "TestTag";
const cloneCamera = camera.entity.clone().getComponent(Camera);
// @ts-ignore - assignmentClone copies reference, not deep clone
expect(cloneCamera._replacementShader).to.eq(shader);
// @ts-ignore
expect(cloneCamera._replacementSubShaderTag).to.eq("TestTag");
// @ts-ignore - cleanup
camera._replacementShader = null;
// @ts-ignore
camera._replacementSubShaderTag = null;
});
it("clone preserves replacement shader by reference (assignmentClone)", () => {
const shader = Shader.create("TestCloneReplaceShader", [
new SubShader("Default", [new ShaderPass("Default", [], [], ShaderLanguage.GLSLES100)])
]);
const testTag = ShaderTagKey.getByName("TestTag");
// `@ts-ignore`
camera._replacementShader = shader;
// `@ts-ignore`
camera._replacementSubShaderTag = testTag;
const cloneCamera = camera.entity.clone().getComponent(Camera);
// `@ts-ignore` - assignmentClone copies reference, not deep clone
expect(cloneCamera._replacementShader).to.eq(shader);
// `@ts-ignore`
expect(cloneCamera._replacementSubShaderTag).to.eq(testTag);
// `@ts-ignore` - cleanup
camera._replacementShader = null;
// `@ts-ignore`
camera._replacementSubShaderTag = null;
});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/src/core/Camera.test.ts` around lines 432 - 453, Replace the string
assignment and string comparison with a proper ShaderTagKey: create a
ShaderTagKey via ShaderTagKey.getByName("TestTag"), assign that to
camera._replacementSubShaderTag (instead of the raw string), and update the
assertion to compare the cloned camera's _replacementSubShaderTag to the same
ShaderTagKey (or compare their names via .getName()) so types and semantics
match; references: camera._replacementSubShaderTag, ShaderTagKey.getByName,
cloneCamera.

@codecov
Copy link
Copy Markdown

codecov Bot commented May 11, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 78.30%. Comparing base (1bc2b10) to head (9845234).

Additional details and impacted files
@@             Coverage Diff             @@
##           dev/2.0    #2988      +/-   ##
===========================================
+ Coverage    78.25%   78.30%   +0.04%     
===========================================
  Files          900      900              
  Lines        99234    99236       +2     
  Branches     10172    10192      +20     
===========================================
+ Hits         77657    77705      +48     
+ Misses       21406    21360      -46     
  Partials       171      171              
Flag Coverage Δ
unittests 78.30% <100.00%> (+0.04%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

GuoLei1990

This comment was marked as outdated.

GuoLei1990

This comment was marked as outdated.

GuoLei1990

This comment was marked as outdated.

@GuoLei1990 GuoLei1990 mentioned this pull request May 11, 2026
3 tasks
GuoLei1990

This comment was marked as outdated.

GuoLei1990

This comment was marked as outdated.

GuoLei1990

This comment was marked as outdated.

GuoLei1990

This comment was marked as outdated.

GuoLei1990

This comment was marked as outdated.

GuoLei1990

This comment was marked as outdated.

GuoLei1990

This comment was marked as outdated.

GuoLei1990

This comment was marked as outdated.

GuoLei1990

This comment was marked as outdated.

GuoLei1990

This comment was marked as outdated.

GuoLei1990

This comment was marked as outdated.

GuoLei1990

This comment was marked as outdated.

GuoLei1990

This comment was marked as outdated.

GuoLei1990

This comment was marked as outdated.

GuoLei1990

This comment was marked as outdated.

GuoLei1990

This comment was marked as outdated.

Copy link
Copy Markdown
Member

@GuoLei1990 GuoLei1990 left a comment

Choose a reason for hiding this comment

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

总结

_replacementShader(Shader 资源)和 _replacementSubShaderTag(ShaderTagKey 值)都是应按引用拷贝的共享对象,缺少装饰器时 CloneManager 会对其执行深克隆(错误)。补上 @assignmentClone 后行为正确。测试通过 eq() 断言引用相同,验证逻辑准确。

LGTM,可合入。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants