feat(scene): decouple node name from path for animation binding. - #805
feat(scene): decouple node name from path for animation binding.#805qiuguohua wants to merge 3 commits into
Conversation
qiuguohua
left a comment
There was a problem hiding this comment.
Overall this is a well-structured implementation. The UUID-first resolution with name-based path construction is the right pattern, lenient mode for deletions is a good compromise, and the test coverage is thorough. Two minor items below.
| return normalizedNodePath.slice(normalizedRootPath.length + 1); | ||
| } | ||
| return rootNode.getChildByPath(normalizedNodePath) ? normalizedNodePath : null; | ||
| return findRelativeNodePathByUuid(rootNode, targetUuid); |
There was a problem hiding this comment.
resolveOperationRelativeNodePath calls findRelativeNodePathByUuid but does not check hasSameNameSiblings like property-curve.ts does.
If same-name siblings exist, the returned name-based path (e.g. Enemy) is ambiguous — queryAnimationPropertyMetadata would resolve it via getChildByPath which picks the first match, potentially returning the wrong sibling's component metadata. This could lead to incorrect value normalization (e.g. loading the wrong asset type).
Not a data-corruption risk since the downstream curve operation in property-curve.ts still has the ambiguity guard, but the metadata query could silently use the wrong node.
| @@ -91,23 +93,26 @@ function resolveOperationRelativeNodePath( | |||
| operation: { nodeUuid?: string; nodePath?: string }, | |||
| options: { queryNodeByUuid: (uuid: string) => Node | null; queryNodePath: (node: Node) => string }, | |||
There was a problem hiding this comment.
The options parameter (queryNodeByUuid, queryNodePath) is no longer used after the UUID-first rewrite — the old code called options.queryNodeByUuid(operation.nodeUuid) and options.queryNodePath(node), but the new code resolves entirely via getNodeByPath/getChildByPath + findRelativeNodePathByUuid.
This makes options dead code in both resolveOperationRelativeNodePath and its caller normalizeProvidedAnimationPropertyOperationValue. Consider removing it (and updating call sites) to avoid confusing future readers.
knoxHuang
left a comment
There was a problem hiding this comment.
Request changes
[P1] Preserve the display name when creating duplicate nodes
File: src/core/scene/scene-process/service/node.ts:177-182
This writeback still couples the user-facing name to the generated system path. When a second node named Enemy is created, NodeMgr.getNodePath(resultNode) may return Enemy_001, and this assignment changes node.name to Enemy_001. That violates the name/path separation described in the PR. Please remove this writeback and add a regression test verifying that the second node keeps name === 'Enemy' while its system path is Enemy_001.
[P2] Keep new code comments in English
The repository TypeScript style requires non-documentation comments to be written in English. This change adds or modifies Chinese comments in the new tests and schema declaration. Please translate the changed comments to English to keep the diff consistent with the documented coding standard.
| const pathPart = pathParts[i]; | ||
| let nextNode = currentParent.getChildByName(pathPart); | ||
| const accumulatedPath = pathParts.slice(0, i + 1).join('/'); | ||
| let nextNode = NodeMgr.getNodeByPath(accumulatedPath) as Node | null; |
There was a problem hiding this comment.
[P1] Preserve the display name when creating duplicate nodes. Although this change correctly resolves the accumulated system path, the create path still writes the generated path segment back to node.name at lines 177-182. When a second node named Enemy is created, the system path may be Enemy_001 and the display name is consequently changed to Enemy_001. Please remove that writeback and add a regression test verifying name === Enemy while the system path is Enemy_001.
| }); | ||
| }); | ||
|
|
||
| describe('10. name 与 path 解耦 - 允许同名节点', () => { |
There was a problem hiding this comment.
[P2] Please keep the newly added code comments in English. The repository TypeScript style requires non-documentation comments to be written in English, but this new test block adds Chinese comments. The same issue also appears in the changed node-manager tests and schema declaration.
| nodeId: z.string().describe('Node ID'), // 节点的 id | ||
| path: z.string().describe('Parent node path, full node path is parent path + node name; root node path is "/"'), // 父节点路径,完整节点路径为父路径+节点名;根节点路径为 "/" | ||
| name: z.string().describe('Node name'), // 节点名称 | ||
| path: z.string().describe('Node addressing path (unique), may differ from node name when siblings share the same display name; root node path is "/"'), // 节点寻址路径(唯一),同名兄弟节点时可能与 name 不同;根节点路径为 "/" |
There was a problem hiding this comment.
Parent node path 去除后,pink上的 ai 可能会把这个path 当成是该节点的路径,而不是他的父节点路径。或者现在的path意义有变了?
There was a problem hiding this comment.
这个接口是代表获取node的path把?不能返回parentNodePath了把?如果返回的是parentNodePath,那应该就没有path的这个接口了。 这样后续的接口调用就会有问题(因为可能是同名的节点, 无法通过parentNodePath+name的拼接来定义nodepath)。 如果有需求要返回parentNodePath,那可能需要加个当前路径的path返回值
Decouple node.name (display label) from system path (unique address) so that sibling nodes can share the same name while retaining stable, unique paths via NodePathManager. Changes: - Remove _updateNameCount; path segment allocation is now fully managed by NodePathManager - Remove path-segment writeback to node.name after move operations - Fix _ensurePathExists to resolve by accumulated path instead of getChildByName - Fix node-proxy to throw on failed path resolution after rename instead of silently returning stale paths - Rewrite animation resolveRelativeNodePath to UUID-first 3-step flow: resolve UUID, build name-based relative path, detect same-name sibling ambiguity via hasSameNameSiblings - Add lenient mode for delete operations: skip ambiguity rejection but verify UUID match; fall back to string-based path extraction for orphan track cleanup when node no longer exists - Rewrite property-value resolveOperationRelativeNodePath to UUID-first approach, replacing string-slicing that produced _NNN suffixed paths incompatible with engine getChildByPath Tests: - Add 12 animation ambiguity detection tests (same-name siblings blocked, lenient delete allowed, orphan track cleanup) - Add 2 property-value path resolution tests (UUID and nodePath branches produce name-based paths) - Add 4 node-proxy rename path resolution tests (success, uuid missing, path resolution failure, no-rename passthrough) - Expand node-path-manager and node-for-editor test suites for name/path decoupling scenarios
…erty-value resolveOperationRelativeNodePath stopped using the options parameter (queryNodeByUuid, queryNodePath) after the UUID-first rewrite but kept it in the signature. Remove it from the function, its caller, and all call sites. Add hasSameNameSiblings check to match property-curve.ts — without it, same-name siblings could cause queryAnimationPropertyMetadata to resolve the wrong node's component metadata.
…for name/path decoupling
33fb1e1 to
0bfbace
Compare
Background
After node name/path decoupling,
node.namebecomes a user-controlled display label that can duplicate among siblings, while the system path (managed byNodePathManager) remains unique with_001/_002suffixes. This creates two independent path namespaces:Enemy,Enemy_001,Enemy_002— unique, used for node addressingEnemy,Enemy,Enemy— resolved bygetChildByPathusingArray.find(first match only)The animation system builds track paths from
node.nameand resolves them viagetChildByPath. Several code paths still assumedname === path segment, causing:property-curve.tsstring-slicing produced system path segments (e.g.Enemy_001) thatgetChildByPathcannot resolveproperty-value.tsusedqueryNodePathwhich returns system paths, same mismatchnode-proxy.tssilently returned stale paths after rename failurenode.tsusedgetChildByNamefor path resolution, breaking when name differs from path segment_updateNameCountoperated on display names instead of path segments, corrupting the path allocation tableFix
Animation path resolution — Rewrite
resolveRelativeNodePath(property-curve.ts) andresolveOperationRelativeNodePath(property-value.ts) to a UUID-first 3-step flow:nodeUuiddirectly, or viagetNodeByPath/getChildByPathfromnodePath)findRelativeNodePathByUuid(DFS usingchild.name), producing paths compatible with enginegetChildByPathhasSameNameSiblings— reject create/update operations when any path level has duplicate namesLenient delete mode —
removePropertyCurveandremovePropertyKeyskip ambiguity rejection but verify UUID match viagetChildByPath, preventing accidental deletion of another node's track. When the target node no longer exists (orphan tracks), fall back to string-based path extraction so cleanup still works.Node proxy — Throw on failed path resolution after rename instead of silently returning the old (now invalid) path.
Node manager — Remove
_updateNameCountentirely (path segment lifecycle managed byNodePathManager), remove path-segment writeback tonode.nameafter move, fix_ensurePathExiststo resolve by accumulated system path.Test Plan
Enemy_001) whilenode.nameshows the user inputremovePropertyCurve