fix(ui): keep diagnostic stop clear of Logo skip

This commit is contained in:
2026-09-06 00:45:44 +08:00
parent 84fa739ddd
commit f2a948f059
4 changed files with 74 additions and 6 deletions
@@ -6,7 +6,7 @@ import type { NativeHost } from '../../framework/config/sources/native-settings.
import type { PageModel } from '../../framework/presentation/ui-contracts.ts'; import type { PageModel } from '../../framework/presentation/ui-contracts.ts';
import { createLocalLoginHost, type LocalLoginHost } from './local-login-host.ts'; import { createLocalLoginHost, type LocalLoginHost } from './local-login-host.ts';
import type { LocalLoginEvidence } from './local-login-transport.ts'; import type { LocalLoginEvidence } from './local-login-transport.ts';
import { CocosLocalLoginView, CocosLogoCountdownView, createLogoCountdown, createAssetLoadTask, createCocosFrameScheduler, requireNode } from './local-login-view.ts'; import { CocosLocalLoginView, CocosLogoCountdownView, createLogoCountdown, createAssetLoadTask, createCocosFrameScheduler, positionDiagnosticStopButtonBelow, requireNode } from './local-login-view.ts';
const { ccclass, property } = _decorator; const { ccclass, property } = _decorator;
@@ -57,7 +57,9 @@ export class LocalPlatformLogin extends Component {
requireNode(logo, 'group-32').active = false; requireNode(logo, 'group-32').active = false;
const countdownLabels = logo.getComponentsInChildren(Label).filter(label => label.node.name === 'Spirit3104'); const countdownLabels = logo.getComponentsInChildren(Label).filter(label => label.node.name === 'Spirit3104');
if (countdownLabels.length !== 1) throw new Error('Logo requires exactly one Spirit3104 Label'); if (countdownLabels.length !== 1) throw new Error('Logo requires exactly one Spirit3104 Label');
this.countdownView = new CocosLogoCountdownView(requireNode(logo, 'group-1/Spirit3103'), countdownLabels[0].node, const logoButton = requireNode(logo, 'group-1/Spirit3103');
positionDiagnosticStopButtonBelow(stopButton, logoButton);
this.countdownView = new CocosLogoCountdownView(logoButton, countdownLabels[0].node,
() => this.countdown?.skip()); () => this.countdown?.skip());
this.countdown = createLogoCountdown({ now: () => performance.now(), this.countdown = createLogoCountdown({ now: () => performance.now(),
schedule: (callback, ms) => { schedule: (callback, ms) => {
@@ -8,6 +8,31 @@ interface ViewReferences {
export interface LogoCountdownState { readonly visible: boolean; readonly text: string; } export interface LogoCountdownState { readonly visible: boolean; readonly text: string; }
const DIAGNOSTIC_STOP_GAP = 12;
/** Keeps the scene diagnostic control clear of the native Logo click region. */
export function positionDiagnosticStopButtonBelow(stopButton: Node, logoButton: Node): void {
const stopTransform = stopButton.getComponent(UITransform);
const logoTransform = logoButton.getComponent(UITransform);
const stopParentTransform = stopButton.parent?.getComponent(UITransform);
if (!stopTransform || !logoTransform || !stopParentTransform) {
throw new Error('Diagnostic stop layout requires native UITransform bindings');
}
const widget = stopButton.getComponent(Widget);
if (widget) {
widget.updateAlignment();
widget.enabled = false;
}
const logoBottom = logoTransform.convertToWorldSpaceAR(
new Vec3((0.5 - logoTransform.anchorX) * logoTransform.width, -logoTransform.anchorY * logoTransform.height, 0),
);
const bottomInStopParent = stopParentTransform.convertToNodeSpaceAR(logoBottom);
const current = stopButton.position;
stopButton.setPosition(new Vec3(current.x,
bottomInStopParent.y - DIAGNOSTIC_STOP_GAP - (1 - stopTransform.anchorY) * stopTransform.height,
current.z));
}
/** Native input and measured label layout, independent of serialized label parentage. */ /** Native input and measured label layout, independent of serialized label parentage. */
export class CocosLogoCountdownView { export class CocosLogoCountdownView {
private readonly label: Label; private readonly label: Label;
@@ -141,6 +141,30 @@ test('Logo native binding measures label around button center and releases its t
button.emit('touch-end'); assert.equal(clicks, 1); button.emit('touch-end'); assert.equal(clicks, 1);
view.dispose(); assert.equal(button.listenerCount('touch-end'), 0); assert.equal(button.active, false); view.dispose(); assert.equal(button.listenerCount('touch-end'), 0); assert.equal(button.active, false);
}); });
test('diagnostic stop button is placed below Logo across different parent coordinates without changing its right-side x', () => {
const { positionDiagnosticStopButtonBelow } = load();
assert.equal(typeof positionDiagnosticStopButtonBelow, 'function');
const logo = new Node('Spirit3103'), logoParent = new Node('logo-parent');
const stop = new Node('StopButton'), canvas = new Node('Canvas');
logo.parent = logoParent; stop.parent = canvas; stop.position = new Vec3(665, 310, 7);
const logoTransform = new UITransform();
Object.assign(logoTransform, { width: 208, height: 59, anchorX: 0.5, anchorY: 0.5 });
logoTransform.convertToWorldSpaceAR = value => new Vec3(value.x + 671.37, value.y + 311.5, value.z);
const stopTransform = new UITransform();
Object.assign(stopTransform, { width: 220, height: 64, anchorX: 0.5, anchorY: 0.5 });
const canvasTransform = new UITransform();
canvasTransform.convertToNodeSpaceAR = value => new Vec3(value.x - 100, value.y - 40, value.z);
logo.components.set(UITransform, logoTransform); stop.components.set(UITransform, stopTransform);
canvas.components.set(UITransform, canvasTransform);
const widget = new Widget(); stop.components.set(Widget, widget);
positionDiagnosticStopButtonBelow(stop, logo);
assert.equal(widget.enabled, false, 'runtime position must not be overwritten by the native Widget');
assert.equal(stop.position.x, 665); assert.equal(stop.position.z, 7);
assert.equal(stop.position.y, 198, 'button top is 12 px below the logo bottom in Canvas coordinates');
});
function fixture() { function fixture() {
const refs = { loadingRoot: new Node(), loginRoot: new Node(), resultRoot: new Node(), const refs = { loadingRoot: new Node(), loginRoot: new Node(), resultRoot: new Node(),
statusOverlay: new Node(), statusLabel: new Label(), resultLabel: new Label() }; statusOverlay: new Node(), statusLabel: new Label(), resultLabel: new Label() };
@@ -321,7 +345,10 @@ test('minimum display ignores an early timer wake and cancellation clears its re
} }); } });
async function started(emitDraw = true) { async function started(emitDraw = true) {
const component = new exports.LocalPlatformLogin(); const f = fixture(); const component = new exports.LocalPlatformLogin(); const f = fixture();
Object.assign(component, f.refs, { stopButton: new Node(), loadingPrefab: {}, loginPrefab: {} }); const stopButton = new Node('StopButton'), canvas = new Node('Canvas');
stopButton.parent = canvas; stopButton.components.set(UITransform, new UITransform());
canvas.components.set(UITransform, new UITransform());
Object.assign(component, f.refs, { stopButton, loadingPrefab: {}, loginPrefab: {} });
const logo = new Node('Layer1_Logo'); const group = new Node('group-1'); const logo = new Node('Layer1_Logo'); const group = new Node('group-1');
const bar = new Node('Spirit254'); bar.components.set(ProgressBar, new ProgressBar()); const bar = new Node('Spirit254'); bar.components.set(ProgressBar, new ProgressBar());
const button = new Node('Spirit3103'), text = new Node('Spirit3104'); const button = new Node('Spirit3103'), text = new Node('Spirit3104');
@@ -1,6 +1,6 @@
# Logo 倒计时与跳过验收 # Logo 倒计时与跳过验收
日期:2026-09-06。基线09e80e5,主checkout分支codex/local-platform-login。用户批准恢复Spirit3103/Spirit3104的原工程行为。 状态:网页补验已完成,含实际鼠标点击与清理。日期:2026-09-06。基线09e80e5,主checkout分支codex/local-platform-login。用户批准恢复Spirit3103/Spirit3104的原工程行为。
## 原工程依据与实现边界 ## 原工程依据与实现边界
@@ -19,11 +19,25 @@
- 五个既有TS经MCP刷新,编辑器主checkout/currentLocalPlatformLogin,无资源写入。创建独立sandbox Chromium窗口12(fp_ad50e68505262f18),未点击登录。 - 五个既有TS经MCP刷新,编辑器主checkout/currentLocalPlatformLogin,无资源写入。创建独立sandbox Chromium窗口12(fp_ad50e68505262f18),未点击登录。
- 实际无参数网页fp_ce914709f5aedc1e:ready=true、stopped=false、pending=0、资源progress=1。3104父节点为Spirit3103,文字倒计时1s但控件已隐藏。firstDraw1078.7ms、展示门结束1239.5ms、资源就绪1248ms、登录页1249.4ms;配置默认短等待未绕过资源门。无component-failure。 - 实际无参数网页fp_ce914709f5aedc1e:ready=true、stopped=false、pending=0、资源progress=1。3104父节点为Spirit3103,文字倒计时1s但控件已隐藏。firstDraw1078.7ms、展示门结束1239.5ms、资源就绪1248ms、登录页1249.4ms;配置默认短等待未绕过资源门。无component-failure。
- 长倒计时视觉夹具尝试仅在独立窗口内装饰HttpConfigFetcher返回数据并重载同一场景,未写生产配置,未记录成功结果。该MCP调用没有返回,后续只读编辑器查询也挂起;已停止工具等待。HTTP8765/health仍返回ok,不能据此认定编辑器调用可用。已请求用户关闭独立验证窗口/恢复Funplay扩展。 - 长倒计时视觉夹具尝试仅在独立窗口内装饰HttpConfigFetcher返回数据并重载同一场景,未写生产配置,未记录成功结果。该MCP调用没有返回,后续只读编辑器查询也挂起;已停止工具等待。HTTP8765/health仍返回ok,不能据此认定编辑器调用可用。已请求用户关闭独立验证窗口/恢复Funplay扩展。
- 待恢复MCP后完成:长倒计时文字逐秒变化、实际点击跳过与到期隐藏的网页验收;恢复临时fetcher装饰(若安装成功)并停止/关闭独立窗口。此项未完成,不以50项模拟测试冒充网页验收。 - 首次验收时待恢复MCP后完成(已由下方补验完成):长倒计时文字逐秒变化、实际点击跳过与到期隐藏的网页验收;恢复临时fetcher装饰(若安装成功)并停止/关闭独立窗口。当时未完成,未以50项模拟测试冒充网页验收。
## 用户资源改动保护 ## 用户资源改动保护
实施期间只读检查发现Logo.prefab新增未提交差异:Spirit3104已移为Spirit3103子节点,局部位置为0。该差异不是本批工具产生,单独记录SHA256并保留,不随代码提交。代码应唯一定位目标Label并按实际父节点布局,避免绑定旧的同级路径;支持这一现有用户布局不需要修改序列化资源。 实施期间只读检查发现Logo.prefab新增未提交差异:Spirit3104已移为Spirit3103子节点,局部位置为0。该差异不是本批工具产生,单独记录SHA256并保留,不随代码提交。代码应唯一定位目标Label并按实际父节点布局,避免绑定旧的同级路径;支持这一现有用户布局不需要修改序列化资源。
整体独立代码审查通过,无可操作问题;结论附带上述网页长倒计时验收未完成的限定。原有50个未跟踪文件与外部Logo.prefab快照SHA256均不变,两项历史meta删除保留。 整体独立代码审查通过,无可操作问题;首次审查时附带网页长倒计时待验收的限定,现已完成下列补验。原有50个未跟踪文件与外部Logo.prefab快照SHA256均不变,两项历史meta删除保留。
## MCP恢复后的最终补验
- MCP恢复,旧窗口12已关闭;新独立窗口13,主checkout和Creator3.8.8不变。避免再次重载场景,使用当前实际编译LocalPlatformLogin类创建临时运行时实例,复用场景引用。只在该浏览器内装饰fetcher返回内存配置,验证有效launchWaitTime等于夹具指定值;不改发布配置、资源、远程服务或持久化数据。
- 实际默认配置仍为10ms,正常页面ready=true、无错误(fp_e983ffe0d6c28f91);修复后再次正常启动通过(fp_cf9a986deb3363ee)。
- 15秒夹具:文字从倒计时15s 跳过变为倒计时14s 跳过;资源progress=1但ready=false,Label在父背景中心(fp_aab5629e8b3f7d8a)。
- 实际鼠标验收发现诊断StopButton与3103重叠,点击被停止按钮接收(fp_4e244b818e107608)。修复只在运行时将StopButton放到Logo背景底边下12单位,保持原x/z;应用Widget布局后关闭其运行时覆盖。两处TS与一个测试变更,无序列化资源修改。独立修复复审通过。
- 修复后实鼠点击屏幕(1467,98):30秒倒计时提前约0.55秒完成展示门并进入login,ready=true、stopped=false、控件隐藏、pending=0(fp_0f0778181f3dc1cb)。截图已检查:两个按钮不再重叠,倒计时文字居中。临时截图temp/mcp-captures/logo-countdown-ready.png未提交。
- 2.2秒自然到期夹具:ready=false/控件可见变为ready=true/控件隐藏(fp_991219d94f45c3c1)。
- 暂缓真实资源加载任务完成的夹具:点击后ready=false、stopped=false,显示倒计时10s;释放资源任务后显示倒计时10s 跳过,仍未提前进入login,证明早点击不排队(fp_7a2ec06865f205b3)。
- 提前停止后文字不变、控件隐藏、ready=false、pending=0(fp_544552041e1a4dce)。诊断StopButton实际鼠标点击仍有效。最终恢复fetcher和临时资源方法,stopped=true、ready=false、pending=0,然后关闭窗口13;编辑器dirty=false(fp_be8fcfffbf985067)。
- 修复TDD先16通过/1失败,后17/17通过;最终完整显式枚举TS637/637。框架及现代Creator严格类型检查通过;此前指定架构49/49通过,本次未改变架构边界。没有重复生成资源或测试其他RPC。
本批启动倒计时、资源完成显示跳过、就绪后跳过、到期隐藏、停止清理网页验收完成。原生广告图片替换、其他平台RPC不在本批范围。