miaoda-game-devkit 0.2.6 → 0.2.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -18,7 +18,9 @@ interface HeadlessGameHost<TScene extends Phaser.Scene> {
18
18
  /** 推进完整 Phaser 帧并等待异步 update 或生命周期完成。 */
19
19
  stepFramesAsync(count?: number): Promise<void>;
20
20
  /** 在限定帧数内推进游戏,直到条件成立。 */
21
- stepUntil(condition: () => boolean, maxFrames?: number): number;
21
+ stepUntil(condition: () => boolean, maxFrames?: number | {
22
+ maxFrames?: number;
23
+ }): number;
22
24
  /** 精确推进指定次数的 Arcade Physics 单步。 */
23
25
  stepPhysics(steps?: number): void;
24
26
  /** 记录由测试定义的可序列化玩法检查点。 */
@@ -18,7 +18,9 @@ interface HeadlessGameHost<TScene extends Phaser.Scene> {
18
18
  /** 推进完整 Phaser 帧并等待异步 update 或生命周期完成。 */
19
19
  stepFramesAsync(count?: number): Promise<void>;
20
20
  /** 在限定帧数内推进游戏,直到条件成立。 */
21
- stepUntil(condition: () => boolean, maxFrames?: number): number;
21
+ stepUntil(condition: () => boolean, maxFrames?: number | {
22
+ maxFrames?: number;
23
+ }): number;
22
24
  /** 精确推进指定次数的 Arcade Physics 单步。 */
23
25
  stepPhysics(steps?: number): void;
24
26
  /** 记录由测试定义的可序列化玩法检查点。 */
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { G as GameplayContractMetadata, H as HeadlessGameHost, a as HeadlessGameplayEvidenceRequirements } from './gameplay-audit-XBGq_jIV.mjs';
2
- export { b as GameplayAuditContract, c as GameplayAuditOptions, d as HeadlessCanvasBounds, e as HeadlessGameOptions, f as HeadlessGameplayEvidence, g as HeadlessInputDriver, h as HeadlessInputPoint, i as HeadlessKeyboardEventOptions, j as HeadlessKeyboardInput, k as HeadlessMouseInput, l as HeadlessTouchInput, m as createHeadlessGame } from './gameplay-audit-XBGq_jIV.mjs';
1
+ import { G as GameplayContractMetadata, H as HeadlessGameHost, a as HeadlessGameplayEvidenceRequirements } from './gameplay-audit-CusQfLYQ.mjs';
2
+ export { b as GameplayAuditContract, c as GameplayAuditOptions, d as HeadlessCanvasBounds, e as HeadlessGameOptions, f as HeadlessGameplayEvidence, g as HeadlessInputDriver, h as HeadlessInputPoint, i as HeadlessKeyboardEventOptions, j as HeadlessKeyboardInput, k as HeadlessMouseInput, l as HeadlessTouchInput, m as createHeadlessGame } from './gameplay-audit-CusQfLYQ.mjs';
3
3
  import * as Phaser from 'phaser';
4
4
  import { TestContext, TestOptions } from 'vitest';
5
5
 
@@ -23,6 +23,8 @@ interface GameplayTestOptions extends GameplayContractOptions {
23
23
  interface GameplayContractHandle<TScene extends Phaser.Scene> {
24
24
  /** 将当前 contract 绑定到实际创建的 HEADLESS host。 */
25
25
  attachHost(host: HeadlessGameHost<TScene>): void;
26
+ /** 记录一个由测试先断言、再声明的玩法检查点。 */
27
+ checkpoint(id: string): void;
26
28
  /** 立即验证证据;通常由 onTestFinished 自动执行。 */
27
29
  verify(): void;
28
30
  }
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { G as GameplayContractMetadata, H as HeadlessGameHost, a as HeadlessGameplayEvidenceRequirements } from './gameplay-audit-XBGq_jIV.js';
2
- export { b as GameplayAuditContract, c as GameplayAuditOptions, d as HeadlessCanvasBounds, e as HeadlessGameOptions, f as HeadlessGameplayEvidence, g as HeadlessInputDriver, h as HeadlessInputPoint, i as HeadlessKeyboardEventOptions, j as HeadlessKeyboardInput, k as HeadlessMouseInput, l as HeadlessTouchInput, m as createHeadlessGame } from './gameplay-audit-XBGq_jIV.js';
1
+ import { G as GameplayContractMetadata, H as HeadlessGameHost, a as HeadlessGameplayEvidenceRequirements } from './gameplay-audit-CusQfLYQ.js';
2
+ export { b as GameplayAuditContract, c as GameplayAuditOptions, d as HeadlessCanvasBounds, e as HeadlessGameOptions, f as HeadlessGameplayEvidence, g as HeadlessInputDriver, h as HeadlessInputPoint, i as HeadlessKeyboardEventOptions, j as HeadlessKeyboardInput, k as HeadlessMouseInput, l as HeadlessTouchInput, m as createHeadlessGame } from './gameplay-audit-CusQfLYQ.js';
3
3
  import * as Phaser from 'phaser';
4
4
  import { TestContext, TestOptions } from 'vitest';
5
5
 
@@ -23,6 +23,8 @@ interface GameplayTestOptions extends GameplayContractOptions {
23
23
  interface GameplayContractHandle<TScene extends Phaser.Scene> {
24
24
  /** 将当前 contract 绑定到实际创建的 HEADLESS host。 */
25
25
  attachHost(host: HeadlessGameHost<TScene>): void;
26
+ /** 记录一个由测试先断言、再声明的玩法检查点。 */
27
+ checkpoint(id: string): void;
26
28
  /** 立即验证证据;通常由 onTestFinished 自动执行。 */
27
29
  verify(): void;
28
30
  }
package/dist/index.js CHANGED
@@ -1021,7 +1021,8 @@ async function createHeadlessGame(scene, options = {}) {
1021
1021
  stepFrames(count);
1022
1022
  await settleRuntime();
1023
1023
  },
1024
- stepUntil(condition, maxFrames = 120) {
1024
+ stepUntil(condition, maxFramesOrOptions = 120) {
1025
+ const maxFrames = typeof maxFramesOrOptions === "number" ? maxFramesOrOptions : maxFramesOrOptions.maxFrames ?? 120;
1025
1026
  assertStepCount(maxFrames, "stepUntil maxFrames");
1026
1027
  throwRuntimeError();
1027
1028
  for (let frame = 0; frame <= maxFrames; frame += 1) {
@@ -1193,6 +1194,14 @@ function registerGameplayContract(context, options) {
1193
1194
  }
1194
1195
  host = currentHost;
1195
1196
  },
1197
+ checkpoint(id) {
1198
+ if (!host) {
1199
+ throw new Error(
1200
+ `Gameplay contract "${options.id}" must attach a HEADLESS host before recording a checkpoint.`
1201
+ );
1202
+ }
1203
+ host.checkpoint(id);
1204
+ },
1196
1205
  verify
1197
1206
  };
1198
1207
  }
package/dist/index.mjs CHANGED
@@ -979,7 +979,8 @@ async function createHeadlessGame(scene, options = {}) {
979
979
  stepFrames(count);
980
980
  await settleRuntime();
981
981
  },
982
- stepUntil(condition, maxFrames = 120) {
982
+ stepUntil(condition, maxFramesOrOptions = 120) {
983
+ const maxFrames = typeof maxFramesOrOptions === "number" ? maxFramesOrOptions : maxFramesOrOptions.maxFrames ?? 120;
983
984
  assertStepCount(maxFrames, "stepUntil maxFrames");
984
985
  throwRuntimeError();
985
986
  for (let frame = 0; frame <= maxFrames; frame += 1) {
@@ -1151,6 +1152,14 @@ function registerGameplayContract(context, options) {
1151
1152
  }
1152
1153
  host = currentHost;
1153
1154
  },
1155
+ checkpoint(id) {
1156
+ if (!host) {
1157
+ throw new Error(
1158
+ `Gameplay contract "${options.id}" must attach a HEADLESS host before recording a checkpoint.`
1159
+ );
1160
+ }
1161
+ host.checkpoint(id);
1162
+ },
1154
1163
  verify
1155
1164
  };
1156
1165
  }
@@ -983,7 +983,8 @@ async function createHeadlessGame(scene, options = {}) {
983
983
  stepFrames(count);
984
984
  await settleRuntime();
985
985
  },
986
- stepUntil(condition, maxFrames = 120) {
986
+ stepUntil(condition, maxFramesOrOptions = 120) {
987
+ const maxFrames = typeof maxFramesOrOptions === "number" ? maxFramesOrOptions : maxFramesOrOptions.maxFrames ?? 120;
987
988
  assertStepCount(maxFrames, "stepUntil maxFrames");
988
989
  throwRuntimeError();
989
990
  for (let frame = 0; frame <= maxFrames; frame += 1) {
@@ -1155,6 +1156,14 @@ function registerGameplayContract(context, options) {
1155
1156
  }
1156
1157
  host = currentHost;
1157
1158
  },
1159
+ checkpoint(id) {
1160
+ if (!host) {
1161
+ throw new Error(
1162
+ `Gameplay contract "${options.id}" must attach a HEADLESS host before recording a checkpoint.`
1163
+ );
1164
+ }
1165
+ host.checkpoint(id);
1166
+ },
1158
1167
  verify
1159
1168
  };
1160
1169
  }
@@ -1190,7 +1199,8 @@ describe("gameplay contract lifecycle integration", () => {
1190
1199
  id: "InputScene.hit",
1191
1200
  kind: "playthrough",
1192
1201
  requireInput: true,
1193
- requireFrameAdvance: true
1202
+ requireFrameAdvance: true,
1203
+ requireCheckpoint: "hit-recorded"
1194
1204
  });
1195
1205
  let host;
1196
1206
  try {
@@ -1199,12 +1209,14 @@ describe("gameplay contract lifecycle integration", () => {
1199
1209
  host.stepFrames();
1200
1210
  await host.input.mouse.click(40, 40);
1201
1211
  expect(host.scene.hits).toBe(1);
1212
+ contract.checkpoint("hit-recorded");
1202
1213
  host.destroy();
1203
1214
  await callbacks[0]?.();
1204
1215
  expect(context.task.meta.gameplayContract).toMatchObject({
1205
1216
  id: "InputScene.hit",
1206
1217
  evidence: {
1207
1218
  clicks: 1,
1219
+ checkpoints: ["hit-recorded"],
1208
1220
  frames: 1,
1209
1221
  mouseEvents: 3
1210
1222
  }
@@ -983,7 +983,8 @@ async function createHeadlessGame(scene, options = {}) {
983
983
  stepFrames(count);
984
984
  await settleRuntime();
985
985
  },
986
- stepUntil(condition, maxFrames = 120) {
986
+ stepUntil(condition, maxFramesOrOptions = 120) {
987
+ const maxFrames = typeof maxFramesOrOptions === "number" ? maxFramesOrOptions : maxFramesOrOptions.maxFrames ?? 120;
987
988
  assertStepCount(maxFrames, "stepUntil maxFrames");
988
989
  throwRuntimeError();
989
990
  for (let frame = 0; frame <= maxFrames; frame += 1) {
@@ -1149,6 +1150,9 @@ describe("Phaser HEADLESS host", () => {
1149
1150
  expect(() => boundedHost.stepUntil(() => false, 1.5)).toThrow(
1150
1151
  "stepUntil maxFrames must be a non-negative safe integer"
1151
1152
  );
1153
+ expect(() => boundedHost.stepUntil(() => false, { maxFrames: 0 })).toThrow(
1154
+ "Condition was not met within 0 complete Phaser frames"
1155
+ );
1152
1156
  expect(() => boundedHost.stepPhysics(-1)).toThrow(
1153
1157
  "stepPhysics steps must be a non-negative safe integer"
1154
1158
  );
@@ -1,5 +1,5 @@
1
1
  import { ViteUserConfig } from 'vitest/config';
2
- import { c as GameplayAuditOptions } from './gameplay-audit-XBGq_jIV.mjs';
2
+ import { c as GameplayAuditOptions } from './gameplay-audit-CusQfLYQ.mjs';
3
3
  import 'phaser';
4
4
 
5
5
  interface GameVitestConfigOptions {
@@ -1,5 +1,5 @@
1
1
  import { ViteUserConfig } from 'vitest/config';
2
- import { c as GameplayAuditOptions } from './gameplay-audit-XBGq_jIV.js';
2
+ import { c as GameplayAuditOptions } from './gameplay-audit-CusQfLYQ.js';
3
3
  import 'phaser';
4
4
 
5
5
  interface GameVitestConfigOptions {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "miaoda-game-devkit",
3
- "version": "0.2.6",
3
+ "version": "0.2.7",
4
4
  "description": "Shared lint and deterministic Phaser HEADLESS testing tools for Miaoda games",
5
5
  "license": "MIT",
6
6
  "main": "./dist/index.js",