miaoda-game-devkit 0.2.8 → 0.2.9
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.
- package/README.md +18 -12
- package/dist/{gameplay-audit-CusQfLYQ.d.mts → gameplay-audit-CCJo4Qhk.d.mts} +2 -2
- package/dist/{gameplay-audit-CusQfLYQ.d.ts → gameplay-audit-CCJo4Qhk.d.ts} +2 -2
- package/dist/index.d.mts +26 -3
- package/dist/index.d.ts +26 -3
- package/dist/index.js +52 -0
- package/dist/index.mjs +49 -0
- package/dist/lint/game-telemetry.contract.mjs +1241 -0
- package/dist/lint/gameplay-audit.contract.mjs +111 -46
- package/dist/lint/gameplay-contract.contract.mjs +5 -2
- package/dist/lint/vitest-config.contract.mjs +49 -29
- package/dist/vitest-config.d.mts +2 -2
- package/dist/vitest-config.d.ts +2 -2
- package/dist/vitest-config.js +49 -29
- package/dist/vitest-config.mjs +49 -29
- package/package.json +1 -1
package/dist/vitest-config.mjs
CHANGED
|
@@ -46,6 +46,7 @@ function createGameplayContractMetadata(contract) {
|
|
|
46
46
|
}
|
|
47
47
|
function validateGameplayAuditOptions(options, projectRoot) {
|
|
48
48
|
const issues = [];
|
|
49
|
+
const contracts = options.contracts;
|
|
49
50
|
const scenes = [...new Set(options.scenes.map((scene) => scene.trim()).filter(Boolean))];
|
|
50
51
|
const mode = options.mode ?? "interactive";
|
|
51
52
|
if (mode === "non-interactive") {
|
|
@@ -67,7 +68,7 @@ function validateGameplayAuditOptions(options, projectRoot) {
|
|
|
67
68
|
const coveredScenes = /* @__PURE__ */ new Set();
|
|
68
69
|
const kinds = /* @__PURE__ */ new Map();
|
|
69
70
|
const invalidKindContracts = [];
|
|
70
|
-
for (const contract of
|
|
71
|
+
for (const contract of contracts ?? []) {
|
|
71
72
|
const id = contract.id.trim();
|
|
72
73
|
if (!id) {
|
|
73
74
|
issues.push("gameplayAudit.contracts \u4E2D\u5B58\u5728\u7A7A contract id\u3002");
|
|
@@ -93,7 +94,6 @@ function validateGameplayAuditOptions(options, projectRoot) {
|
|
|
93
94
|
kinds.set(contract.kind, list);
|
|
94
95
|
}
|
|
95
96
|
if (contract.kind === "playthrough") {
|
|
96
|
-
if (!contract.requireInput) issues.push(`playthrough contract "${id}" \u5FC5\u987B requireInput: true\u3002`);
|
|
97
97
|
if (!contract.requireFrameAdvance) issues.push(`playthrough contract "${id}" \u5FC5\u987B requireFrameAdvance: true\u3002`);
|
|
98
98
|
if (normalizeList(contract.requireCheckpoint).length === 0) issues.push(`playthrough contract "${id}" \u5FC5\u987B\u58F0\u660E requireCheckpoint\u3002`);
|
|
99
99
|
}
|
|
@@ -101,7 +101,6 @@ function validateGameplayAuditOptions(options, projectRoot) {
|
|
|
101
101
|
issues.push(`transition contract "${id}" \u5FC5\u987B\u58F0\u660E requireTransition\u3002`);
|
|
102
102
|
}
|
|
103
103
|
if (contract.kind === "recovery") {
|
|
104
|
-
if (!contract.requireInput) issues.push(`recovery contract "${id}" \u5FC5\u987B requireInput: true\u3002`);
|
|
105
104
|
if (!contract.requireFrameAdvance) issues.push(`recovery contract "${id}" \u5FC5\u987B requireFrameAdvance: true\u3002`);
|
|
106
105
|
if (normalizeList(contract.requireRestart).length === 0) issues.push(`recovery contract "${id}" \u5FC5\u987B\u58F0\u660E requireRestart\u3002`);
|
|
107
106
|
if (normalizeList(contract.requireCheckpoint).length < 2) issues.push(`recovery contract "${id}" \u81F3\u5C11\u9700\u8981\u4E24\u4E2A checkpoint\uFF08\u91CD\u7F6E\u524D\u540E\uFF09\u3002`);
|
|
@@ -123,32 +122,25 @@ function validateGameplayAuditOptions(options, projectRoot) {
|
|
|
123
122
|
`\u4EE5\u4E0B contract \u7F3A\u5C11\u6709\u6548 kind\uFF1A${invalidKindContracts.map((id) => `"${id}"`).join("\u3001")}\u3002\u8BF7\u4E3A\u6BCF\u4E2A contract \u8BBE\u7F6E kind: "boot"\u3001"playthrough"\u3001"transition" \u6216 "recovery"\u3002`
|
|
124
123
|
);
|
|
125
124
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
125
|
+
if (contracts) {
|
|
126
|
+
for (const scene of scenes) {
|
|
127
|
+
if (!coveredScenes.has(scene)) {
|
|
128
|
+
issues.push(`Scene "${scene}" \u6CA1\u6709\u4EFB\u4F55 gameplay contract \u8D1F\u8D23\u9A8C\u8BC1\u3002`);
|
|
129
|
+
}
|
|
129
130
|
}
|
|
131
|
+
if (contracts.length === 0)
|
|
132
|
+
issues.push("gameplayAudit.contracts \u5B58\u5728\u65F6\u4E0D\u80FD\u4E3A\u7A7A\uFF1B\u4E0D\u4F7F\u7528\u663E\u5F0F\u6E05\u5355\u8BF7\u7701\u7565\u8BE5\u5B57\u6BB5\u3002");
|
|
130
133
|
}
|
|
131
|
-
if (
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
const hasInput =
|
|
136
|
-
|
|
137
|
-
if (!hasPlaythrough || !hasInput || !hasCheckpoint) {
|
|
134
|
+
if (mode === "interactive" && contracts) {
|
|
135
|
+
const hasPlaythrough = (kinds.get("playthrough") ?? []).some(
|
|
136
|
+
(contract) => Boolean(contract.requireFrameAdvance) && normalizeList(contract.requireCheckpoint).length > 0
|
|
137
|
+
);
|
|
138
|
+
const hasInput = contracts.some((contract) => contract.requireInput);
|
|
139
|
+
if (!hasPlaythrough || !hasInput) {
|
|
138
140
|
issues.push(
|
|
139
|
-
|
|
141
|
+
"\u4EA4\u4E92\u9879\u76EE\u7F3A\u5C11\u6700\u4F4E\u73A9\u6CD5\u57FA\u7EBF\uFF1A\u81F3\u5C11\u4E00\u4E2A playthrough contract \u5FC5\u987B\u58F0\u660E requireFrameAdvance \u548C checkpoint\uFF0C\u4E14\u81F3\u5C11\u4E00\u4E2A contract \u5FC5\u987B\u58F0\u660E requireInput: true\u3002"
|
|
140
142
|
);
|
|
141
143
|
}
|
|
142
|
-
const entryScene = scenes[0];
|
|
143
|
-
for (const scene of scenes.slice(1)) {
|
|
144
|
-
const transitioned = options.contracts.some(
|
|
145
|
-
(contract) => (contract.kind === "transition" || contract.kind === "playthrough") && normalizeList(contract.requireTransition).includes(scene)
|
|
146
|
-
);
|
|
147
|
-
if (!transitioned) issues.push(`\u975E\u5165\u53E3 Scene "${scene}" \u5FC5\u987B\u7531 transition/playthrough contract \u901A\u8FC7\u751F\u4EA7\u8F6C\u573A\u8986\u76D6\u3002`);
|
|
148
|
-
}
|
|
149
|
-
if (entryScene && scenes.length > 1 && (kinds.get("transition") ?? []).length === 0 && (kinds.get("playthrough") ?? []).length === 0 && invalidKindContracts.length === 0) {
|
|
150
|
-
issues.push(`\u4EA4\u4E92\u9879\u76EE\u5165\u53E3 Scene "${entryScene}" \u7F3A\u5C11 transition/playthrough flow\u3002`);
|
|
151
|
-
}
|
|
152
144
|
const restartSignal = projectRoot ? containsProductionRestart(projectRoot) : false;
|
|
153
145
|
if (restartSignal && options.flows?.restart !== true) {
|
|
154
146
|
issues.push("\u68C0\u6D4B\u5230\u751F\u4EA7 Scene \u4F7F\u7528 scene.restart()\uFF1B\u5FC5\u987B\u58F0\u660E flows.restart: true \u5E76\u63D0\u4F9B kind: recovery contract\u3002");
|
|
@@ -209,11 +201,21 @@ function getDefinitionIssues(expected, actual) {
|
|
|
209
201
|
}
|
|
210
202
|
function auditGameplayCollection(options, file, tests) {
|
|
211
203
|
const normalizedFile = file.replaceAll("\\", "/");
|
|
212
|
-
const expected = options.contracts.filter(
|
|
204
|
+
const expected = (options.contracts ?? []).filter(
|
|
213
205
|
(contract) => contract.testFile.replaceAll("\\", "/") === normalizedFile
|
|
214
206
|
);
|
|
215
207
|
const actual = tests.filter((test) => test.metadata);
|
|
216
208
|
const issues = [];
|
|
209
|
+
if (!options.contracts) {
|
|
210
|
+
const actualIds = /* @__PURE__ */ new Set();
|
|
211
|
+
for (const test of actual) {
|
|
212
|
+
const id = test.metadata?.id;
|
|
213
|
+
if (!id) continue;
|
|
214
|
+
if (actualIds.has(id)) issues.push(`contract "${id}" \u5728 ${normalizedFile} \u4E2D\u91CD\u590D\u5B9A\u4E49\u3002`);
|
|
215
|
+
actualIds.add(id);
|
|
216
|
+
}
|
|
217
|
+
return { passed: issues.length === 0, issues };
|
|
218
|
+
}
|
|
217
219
|
for (const contract of expected) {
|
|
218
220
|
const matches = actual.filter((test) => test.metadata?.id === contract.id);
|
|
219
221
|
if (matches.length === 0) {
|
|
@@ -286,7 +288,25 @@ function auditGameplayRun(options, tests) {
|
|
|
286
288
|
const issues = [];
|
|
287
289
|
const actualContracts = tests.filter((test) => test.metadata);
|
|
288
290
|
const observedEvidence = [];
|
|
289
|
-
|
|
291
|
+
const discoveredContracts = actualContracts.flatMap((test) => {
|
|
292
|
+
const metadata = test.metadata;
|
|
293
|
+
if (!metadata) return [];
|
|
294
|
+
return [{
|
|
295
|
+
id: metadata.id,
|
|
296
|
+
kind: metadata.kind,
|
|
297
|
+
testFile: test.file,
|
|
298
|
+
scenes: metadata.scenes,
|
|
299
|
+
...metadata.requirements
|
|
300
|
+
}];
|
|
301
|
+
});
|
|
302
|
+
const expectedContracts = options.contracts ?? discoveredContracts;
|
|
303
|
+
if (!options.contracts) {
|
|
304
|
+
const discoveredIssues = validateGameplayAuditOptions(
|
|
305
|
+
{ ...options, contracts: discoveredContracts }
|
|
306
|
+
);
|
|
307
|
+
issues.push(...discoveredIssues);
|
|
308
|
+
}
|
|
309
|
+
for (const expected of expectedContracts) {
|
|
290
310
|
const matches = actualContracts.filter(
|
|
291
311
|
(test2) => test2.metadata?.id === expected.id
|
|
292
312
|
);
|
|
@@ -329,7 +349,7 @@ function auditGameplayRun(options, tests) {
|
|
|
329
349
|
}
|
|
330
350
|
for (const test of actualContracts) {
|
|
331
351
|
const id = test.metadata?.id;
|
|
332
|
-
if (id && !options.contracts.some((contract) => contract.id === id)) {
|
|
352
|
+
if (id && options.contracts && !options.contracts.some((contract) => contract.id === id)) {
|
|
333
353
|
issues.push(
|
|
334
354
|
`\u53D1\u73B0\u672A\u5217\u5165 gameplayAudit \u6E05\u5355\u7684 contract "${id}"\uFF08${test.file}\uFF09\u3002`
|
|
335
355
|
);
|
|
@@ -524,7 +544,7 @@ var GameplayAuditReporter = class {
|
|
|
524
544
|
(specification) => normalizePath(relative(this.projectRoot, specification.moduleId))
|
|
525
545
|
)
|
|
526
546
|
);
|
|
527
|
-
for (const contract of this.options.contracts) {
|
|
547
|
+
for (const contract of this.options.contracts ?? []) {
|
|
528
548
|
const testFile = normalizePath(contract.testFile);
|
|
529
549
|
if (!scheduledFiles.has(testFile)) {
|
|
530
550
|
this.reportPreflightIssue(
|
|
@@ -568,7 +588,7 @@ var GameplayAuditReporter = class {
|
|
|
568
588
|
} else {
|
|
569
589
|
console.log(
|
|
570
590
|
`
|
|
571
|
-
GAMEPLAY_AUDIT: ALL CONTRACTS PASSED (${
|
|
591
|
+
GAMEPLAY_AUDIT: ALL CONTRACTS PASSED (${tests.filter((test) => test.metadata).length} contracts, ${this.options.scenes.length} scenes)`
|
|
572
592
|
);
|
|
573
593
|
console.log(
|
|
574
594
|
"GAMEPLAY_AUDIT_NOTE: \u73A9\u6CD5\u68C0\u67E5\u5DF2\u901A\u8FC7\uFF1B\u4ECD\u9700\u4EE5\u6700\u540E\u7684 TEST_RESULT \u5224\u65AD\u6574\u4F53\u6210\u529F\u3002"
|