Skip to content

Commit dfd53d9

Browse files
committed
优化表达式性能,帧率显示
1 parent 6b73cd2 commit dfd53d9

7 files changed

Lines changed: 1251 additions & 295 deletions

File tree

‎AI完成代办.md‎

Lines changed: 0 additions & 14 deletions
This file was deleted.
Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
export function installCodeCompileMethods(CompositionBuilderApp, deps = {}) {
2+
const int = (typeof deps.int === "function")
3+
? deps.int
4+
: ((v) => {
5+
const n = Number(v);
6+
if (!Number.isFinite(n)) return 0;
7+
return n < 0 ? Math.ceil(n) : Math.floor(n);
8+
});
9+
10+
CompositionBuilderApp.prototype.isCodeEditorSourceFieldTarget = function isCodeEditorSourceFieldTarget(target) {
11+
if (!(target instanceof HTMLTextAreaElement)) return false;
12+
if (!target.dataset.codeEditor) return false;
13+
if (target.dataset.displayField === "expression") return true;
14+
if (target.dataset.cardShapeDisplayField === "expression") return true;
15+
if (target.dataset.cardShapeChildDisplayField === "expression") return true;
16+
if (target.dataset.shapeLevelDisplayField === "expression") return true;
17+
if (target.dataset.cactField === "script") return true;
18+
return false;
19+
};
20+
21+
CompositionBuilderApp.prototype.resolveCodeEditorCompileBinding = function resolveCodeEditorCompileBinding(target) {
22+
if (!this.isCodeEditorSourceFieldTarget(target)) return null;
23+
const parseIndex = (raw) => {
24+
const n = Number(raw);
25+
return Number.isFinite(n) ? int(n) : -1;
26+
};
27+
if (target.dataset.displayField === "expression") {
28+
const actionIdx = parseIndex(target.dataset.displayIdx);
29+
if (actionIdx < 0) return null;
30+
const list = Array.isArray(this.state.displayActions) ? this.state.displayActions : [];
31+
const action = list[actionIdx];
32+
if (!action) return null;
33+
return {
34+
kind: "display_expression",
35+
compileKey: this.makePreviewDisplayActionCompileKey("display", "", -1, actionIdx),
36+
source: String(action.expression || "")
37+
};
38+
}
39+
const cardId = String(target.dataset.cardId || "");
40+
const card = cardId ? this.getCardById(cardId) : null;
41+
if (!card) return null;
42+
if (target.dataset.cardShapeDisplayField === "expression") {
43+
const actionIdx = parseIndex(target.dataset.cardShapeDisplayIdx);
44+
if (actionIdx < 0) return null;
45+
const list = Array.isArray(card.shapeDisplayActions) ? card.shapeDisplayActions : [];
46+
const action = list[actionIdx];
47+
if (!action) return null;
48+
return {
49+
kind: "display_expression",
50+
compileKey: this.makePreviewDisplayActionCompileKey("shape_display", card.id, 0, actionIdx),
51+
source: String(action.expression || "")
52+
};
53+
}
54+
if (target.dataset.cardShapeChildDisplayField === "expression") {
55+
const actionIdx = parseIndex(target.dataset.cardShapeChildDisplayIdx);
56+
if (actionIdx < 0) return null;
57+
const list = Array.isArray(card.shapeChildDisplayActions) ? card.shapeChildDisplayActions : [];
58+
const action = list[actionIdx];
59+
if (!action) return null;
60+
return {
61+
kind: "display_expression",
62+
compileKey: this.makePreviewDisplayActionCompileKey("shape_level_display", card.id, 1, actionIdx),
63+
source: String(action.expression || "")
64+
};
65+
}
66+
if (target.dataset.shapeLevelDisplayField === "expression") {
67+
const levelFromRow = target.closest?.("[data-shape-level]")?.dataset?.shapeLevel;
68+
const rawLevelIdx = target.dataset.shapeLevelIdx ?? levelFromRow;
69+
const levelIdx = parseIndex(rawLevelIdx);
70+
const actionIdx = parseIndex(target.dataset.shapeLevelDisplayIdx);
71+
if (levelIdx <= 0 || actionIdx < 0) return null;
72+
const level = this.getNestedShapeLevel(card, levelIdx, false);
73+
if (!level) return null;
74+
const list = Array.isArray(level.displayActions) ? level.displayActions : [];
75+
const action = list[actionIdx];
76+
if (!action) return null;
77+
return {
78+
kind: "display_expression",
79+
compileKey: this.makePreviewDisplayActionCompileKey("shape_level_display", card.id, levelIdx + 1, actionIdx),
80+
source: String(action.expression || "")
81+
};
82+
}
83+
if (target.dataset.cactField === "script") {
84+
const actionIdx = parseIndex(target.dataset.cactIdx);
85+
if (actionIdx < 0) return null;
86+
const list = Array.isArray(card.controllerActions) ? card.controllerActions : [];
87+
const action = list[actionIdx];
88+
if (!action) return null;
89+
return {
90+
kind: "controller_script",
91+
compileKey: this.makePreviewControllerScriptCompileKey(card.id, actionIdx),
92+
source: String(action.script || "")
93+
};
94+
}
95+
return null;
96+
};
97+
98+
CompositionBuilderApp.prototype.compileCodeEditorTarget = function compileCodeEditorTarget(target, opts = {}) {
99+
const binding = this.resolveCodeEditorCompileBinding(target);
100+
if (!binding) return { handled: false, ok: true, usedFallback: false, message: "" };
101+
const source = String(binding.source || "");
102+
const force = opts.force === true;
103+
const check = this.validateCodeEditorSource(target, source);
104+
if (!check.valid) {
105+
const message = String(check.message || "表达式存在问题,此表达式不生效。");
106+
let marked = null;
107+
if (binding.kind === "controller_script") {
108+
if (typeof this.markPreviewControllerCompileFailure === "function") {
109+
marked = this.markPreviewControllerCompileFailure(binding.compileKey, source, message);
110+
}
111+
} else if (typeof this.markPreviewDisplayExpressionCompileFailure === "function") {
112+
marked = this.markPreviewDisplayExpressionCompileFailure(binding.compileKey, source, message);
113+
}
114+
return {
115+
handled: true,
116+
ok: false,
117+
usedFallback: marked?.usedFallback === true,
118+
message
119+
};
120+
}
121+
let result = null;
122+
if (binding.kind === "controller_script") {
123+
if (typeof this.compilePreviewControllerScript === "function") {
124+
result = this.compilePreviewControllerScript(binding.compileKey, source, { force });
125+
}
126+
} else if (typeof this.compilePreviewDisplayExpression === "function") {
127+
result = this.compilePreviewDisplayExpression(binding.compileKey, source, { force });
128+
}
129+
if (!result) return { handled: true, ok: true, usedFallback: false, message: "" };
130+
const ok = result.ok === true;
131+
const usedFallback = result.usedFallback === true;
132+
const message = String(result.message || "");
133+
if (ok) return { handled: true, ok: true, usedFallback: false, message: "" };
134+
const fallbackPrefix = usedFallback ? "编译失败,已回退到上一次成功结果。" : "编译失败。";
135+
return {
136+
handled: true,
137+
ok: false,
138+
usedFallback,
139+
message: message ? `${fallbackPrefix} ${message}` : fallbackPrefix
140+
};
141+
};
142+
143+
CompositionBuilderApp.prototype.compileAllCodeEditorSources = function compileAllCodeEditorSources(opts = {}) {
144+
const force = opts.force === true;
145+
const showToast = opts.showToast === true;
146+
let summary = { total: 0, compiled: 0, failed: 0, fallback: 0 };
147+
if (typeof this.compilePreviewScriptsFromState === "function") {
148+
const result = this.compilePreviewScriptsFromState({ force });
149+
if (result && typeof result === "object") summary = result;
150+
}
151+
let applyOpts = { rebuildPreview: true };
152+
if (this.pendingCodeApplyOpts instanceof Map && this.pendingCodeApplyOpts.size) {
153+
for (const pending of this.pendingCodeApplyOpts.values()) {
154+
applyOpts = this.mergeMutateOptions(applyOpts, pending || {});
155+
}
156+
this.pendingCodeApplyOpts.clear();
157+
}
158+
this.afterValueMutate(applyOpts);
159+
if (showToast) {
160+
const total = Math.max(0, int(summary.total || 0));
161+
const compiled = Math.max(0, int(summary.compiled || 0));
162+
const failed = Math.max(0, int(summary.failed || 0));
163+
const fallback = Math.max(0, int(summary.fallback || 0));
164+
if (total <= 0) {
165+
this.showToast("没有可编译的表达式脚本。", "info");
166+
} else if (failed > 0 && fallback > 0) {
167+
this.showToast(`编译完成:${compiled} 成功,${failed} 失败(${fallback} 已回退上次成功结果)`, "info");
168+
} else if (failed > 0) {
169+
this.showToast(`编译失败:${failed} 处表达式脚本有问题。`, "error");
170+
} else {
171+
this.showToast(`编译成功:${compiled}/${total}`, "success");
172+
}
173+
}
174+
return summary;
175+
};
176+
177+
CompositionBuilderApp.prototype.queueCodeEditorRefresh = function queueCodeEditorRefresh(target, opts = {}) {
178+
if (!this.isCodeEditorSourceFieldTarget(target)) return false;
179+
if (!(this.pendingCodeApplyOpts instanceof Map)) this.pendingCodeApplyOpts = new Map();
180+
const merged = this.mergeMutateOptions(
181+
this.pendingCodeApplyOpts.get(target) || null,
182+
Object.assign({ rebuildPreview: true }, opts || {})
183+
);
184+
this.pendingCodeApplyOpts.set(target, merged);
185+
this.scheduleSave();
186+
return true;
187+
};
188+
189+
CompositionBuilderApp.prototype.flushCodeEditorRefresh = function flushCodeEditorRefresh(target, opts = {}) {
190+
if (!this.isCodeEditorSourceFieldTarget(target)) return false;
191+
const force = opts.force === true;
192+
const showToast = opts.showToast === true;
193+
const pendingMap = (this.pendingCodeApplyOpts instanceof Map) ? this.pendingCodeApplyOpts : new Map();
194+
const applyOpts = pendingMap.get(target) || null;
195+
if (!applyOpts && !force) return false;
196+
if (applyOpts) pendingMap.delete(target);
197+
this.pendingCodeApplyOpts = pendingMap;
198+
const compileResult = this.compileCodeEditorTarget(target, { force });
199+
if (compileResult.handled && !compileResult.ok && !compileResult.usedFallback) {
200+
if (showToast) this.showToast(compileResult.message || "编译失败。", "error");
201+
this.scheduleSave();
202+
return true;
203+
}
204+
if (showToast && compileResult.handled && !compileResult.ok && compileResult.usedFallback) {
205+
this.showToast(compileResult.message || "编译失败,已回退到上一次成功结果。", "info");
206+
} else if (showToast && compileResult.handled && compileResult.ok) {
207+
this.showToast("编译成功。", "success");
208+
}
209+
this.afterValueMutate(applyOpts || { rebuildPreview: true });
210+
return true;
211+
};
212+
213+
CompositionBuilderApp.prototype.onCodeEditorFocusOut = function onCodeEditorFocusOut(e) {
214+
const target = e?.target;
215+
if (!(target instanceof HTMLTextAreaElement)) return;
216+
this.flushCodeEditorRefresh(target);
217+
};
218+
}

‎assets/composition_builder/js/expression_editor_mixin.js‎

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,6 @@ export function installExpressionEditorMethods(CompositionBuilderApp, deps = {})
206206
const base = [
207207
"age",
208208
"tick",
209-
"tickCount",
210209
"PI",
211210
"status.displayStatus",
212211
"status.isDisable()",
@@ -432,7 +431,6 @@ export function installExpressionEditorMethods(CompositionBuilderApp, deps = {})
432431
{ label: `this@${projectClass}.status.disable()`, insertText: `this@${projectClass}.status.disable()`, detail: "Composition lifecycle", priority: 257 },
433432
{ label: `this@${projectClass}.status.isEnable()`, insertText: `this@${projectClass}.status.isEnable()`, detail: "Composition lifecycle", priority: 257 },
434433
{ label: `this@${projectClass}.status.enable()`, insertText: `this@${projectClass}.status.enable()`, detail: "Composition lifecycle", priority: 257 },
435-
{ label: "tickCount", detail: "预览 tick(不是粒子 tick)", priority: 250 },
436434
{ label: "RelativeLocation(x, y, z)", insertText: "RelativeLocation($0)", detail: "向量构造", priority: 220 },
437435
{ label: "Vec3(x, y, z)", insertText: "Vec3($0)", detail: "向量构造", priority: 220 },
438436
{ label: "Vector3f(x, y, z)", insertText: "Vector3f($0)", detail: "向量构造", priority: 220 },
@@ -461,7 +459,6 @@ export function installExpressionEditorMethods(CompositionBuilderApp, deps = {})
461459
{ label: "particle.particleSize", detail: "粒子属性", priority: 240 },
462460
{ label: "age", detail: "当前 age", priority: 250 },
463461
{ label: "tick", detail: "当前 tick", priority: 250 },
464-
{ label: "tickCount", detail: "当前 tick(同 tick)", priority: 250 },
465462
{ label: "index", detail: "点索引", priority: 250 },
466463
{ label: "status.displayStatus", detail: "当前 Composition 状态", priority: 252 },
467464
{ label: "status.isDisable()", insertText: "status.isDisable()", detail: "Composition state", priority: 252 },

‎assets/composition_builder/js/expression_runtime.js‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,6 @@ export function createExpressionRuntime(options = {}) {
203203
const tickValue = Number.isFinite(Number(elapsedTick)) ? Number(elapsedTick) : 0;
204204
defineLocal("age", Number.isFinite(Number(ageTick)) ? Number(ageTick) : 0);
205205
defineLocal("tick", tickValue);
206-
defineLocal("tickCount", tickValue);
207206
defineLocal("index", Number.isFinite(Number(pointIndex)) ? Number(pointIndex) : 0);
208207
return vars;
209208
}

0 commit comments

Comments
 (0)