@threenative/core 0.3.2 → 0.3.4
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/capabilities.json +1891 -101
- package/dist/{assets-kyoF7JlJ.d.ts → assets-CqvE429w.d.ts} +52 -3
- package/dist/{audio-BFiGneTL.d.ts → audio-7i3Xl0l3.d.ts} +32 -1
- package/dist/{canvas-layer-BLVijiUJ.d.ts → canvas-layer-DDmC_VVF.d.ts} +1 -1
- package/dist/{game-XGrTzapq.d.ts → game-CljaDv4D.d.ts} +503 -11
- package/dist/{gpu-readback-D2iRvoe9.d.ts → gpu-readback-CqJEfWNQ.d.ts} +16 -6
- package/dist/hot.d.ts +5 -5
- package/dist/hot.js +20 -3
- package/dist/index.d.ts +1496 -43
- package/dist/index.js +8345 -753
- package/dist/playtest.d.ts +11 -5
- package/dist/playtest.js +96 -11
- package/dist/react.d.ts +2 -2
- package/dist/{renderer-C6hqZpoG.d.ts → renderer-CfsS2hxi.d.ts} +436 -14
- package/dist/ui-layer.d.ts +15 -7
- package/dist/ui-layer.js +2 -1
- package/dist/world.d.ts +900 -14
- package/dist/world.js +10876 -126
- package/gpl/fixtures/make_world_fixture.py +184 -0
- package/gpl/recipes/_common.py +11 -0
- package/gpl/recipes/decimate.py +11 -5
- package/gpl/recipes/export_world.py +682 -0
- package/mcp/blender-server.mjs +55 -1
- package/mcp/engine-server.mjs +84 -22
- package/mcp/servers.mjs +3 -3
- package/package.json +6 -6
- package/patches/three@0.185.1.patch +2228 -105
- package/scripts/apply-three-patch.mjs +61 -37
|
@@ -30,14 +30,13 @@ export async function applyThreePatch(options = {}) {
|
|
|
30
30
|
const patchPath = path.join(packageRoot, "patches", PATCH_NAME);
|
|
31
31
|
const patch = parsePatch(await readFile(patchPath, "utf8"), patchPath);
|
|
32
32
|
const plans = await planPatch(threeRoot, patch);
|
|
33
|
+
// `planPatch` refuses any file it does not fully recognise, so every plan that is not already
|
|
34
|
+
// `patched` is safe to write — including the files an older release of this patch already
|
|
35
|
+
// touched, which is the state a project upgrading from the previous `latest` is in.
|
|
33
36
|
if (plans.every((plan) => plan.status === "patched")) return "unchanged";
|
|
34
|
-
if (plans.some((plan) => plan.status !== "stock")) {
|
|
35
|
-
throw new Error(
|
|
36
|
-
`TN_THREE_PATCH_PARTIAL: ${manifestPath} is neither stock nor fully patched; refusing to modify a partial installation.`,
|
|
37
|
-
);
|
|
38
|
-
}
|
|
39
37
|
|
|
40
|
-
for (const plan of plans)
|
|
38
|
+
for (const plan of plans)
|
|
39
|
+
if (plan.status !== "patched") await writeFile(plan.file, plan.contents, "utf8");
|
|
41
40
|
return "patched";
|
|
42
41
|
}
|
|
43
42
|
|
|
@@ -217,56 +216,81 @@ async function planPatch(threeRoot, files) {
|
|
|
217
216
|
}
|
|
218
217
|
const original = await readFile(target, "utf8");
|
|
219
218
|
const lines = original.replaceAll("\r\n", "\n").split("\n");
|
|
220
|
-
const
|
|
219
|
+
const states = classifyFile(lines, file.hunks);
|
|
220
|
+
const unknown = states.findIndex((state) => state === "unknown");
|
|
221
|
+
if (unknown !== -1) {
|
|
222
|
+
throw new Error(
|
|
223
|
+
`TN_THREE_PATCH_PARTIAL: hunk ${String(unknown + 1)} of ${file.oldPath} matches neither the stock nor the patched text in ${target}; refusing to modify an installation this package does not recognise.`,
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
const status = states.every((state) => state === "patched")
|
|
227
|
+
? "patched"
|
|
228
|
+
: states.some((state) => state === "patched")
|
|
229
|
+
? "extended"
|
|
230
|
+
: "stock";
|
|
221
231
|
if (status === "patched") {
|
|
222
232
|
plans.push({ contents: original, file: target, status });
|
|
223
233
|
continue;
|
|
224
234
|
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
}
|
|
230
|
-
plans.push({ contents: applyFile(lines, file.hunks, target).join("\n"), file: target, status });
|
|
235
|
+
plans.push({
|
|
236
|
+
contents: applyFile(lines, file.hunks, states, target).join("\n"),
|
|
237
|
+
file: target,
|
|
238
|
+
status,
|
|
239
|
+
});
|
|
231
240
|
}
|
|
232
241
|
return plans;
|
|
233
242
|
}
|
|
234
243
|
|
|
244
|
+
/**
|
|
245
|
+
* Every hunk's state in this file, in patch order: `"stock"`, `"patched"` or `"unknown"`.
|
|
246
|
+
*
|
|
247
|
+
* Per hunk rather than per file, because an upgrade lands on a file an *older release of this same
|
|
248
|
+
* package's patch* already modified. The consumer declares the patch in its own manifest, so the
|
|
249
|
+
* package manager applies it at install time — meaning a project scaffolded from the previous
|
|
250
|
+
* `latest` carries the previous patch's text, and only this release's new hunks are still stock.
|
|
251
|
+
* Both states are repairable by applying the stock remainder, and the old hunks are not re-derived
|
|
252
|
+
* from a different patch: they are this patch's own hunks, already at their patched text.
|
|
253
|
+
*
|
|
254
|
+
* A hunk in neither state is a file this package does not recognise — hand-edited, or owned by a
|
|
255
|
+
* different patch — and stays the refusal it always was.
|
|
256
|
+
*/
|
|
235
257
|
function classifyFile(lines, hunks) {
|
|
236
|
-
|
|
237
|
-
let patched = true;
|
|
258
|
+
const states = [];
|
|
238
259
|
let offset = 0;
|
|
239
260
|
for (const hunk of hunks) {
|
|
240
|
-
const oldLines = hunk
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
.
|
|
245
|
-
|
|
246
|
-
if (locate(lines, oldLines, hunk.oldStart - 1 + offset) === undefined) stock = false;
|
|
247
|
-
if (locate(lines, newLines, hunk.newStart - 1) === undefined) patched = false;
|
|
261
|
+
const oldLines = hunkLines(hunk, "old");
|
|
262
|
+
const newLines = hunkLines(hunk, "new");
|
|
263
|
+
if (locate(lines, newLines, hunk.newStart - 1) !== undefined) states.push("patched");
|
|
264
|
+
else if (locate(lines, oldLines, hunk.oldStart - 1 + offset) !== undefined)
|
|
265
|
+
states.push("stock");
|
|
266
|
+
else states.push("unknown");
|
|
248
267
|
offset += newLines.length - oldLines.length;
|
|
249
268
|
}
|
|
250
|
-
|
|
251
|
-
if (patched) return "patched";
|
|
252
|
-
return "mixed";
|
|
269
|
+
return states;
|
|
253
270
|
}
|
|
254
271
|
|
|
255
|
-
function
|
|
272
|
+
function hunkLines(hunk, side) {
|
|
273
|
+
return hunk.lines
|
|
274
|
+
.filter((line) =>
|
|
275
|
+
side === "old" ? line[0] === " " || line[0] === "-" : line[0] === " " || line[0] === "+",
|
|
276
|
+
)
|
|
277
|
+
.map((line) => line.slice(1));
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
function applyFile(lines, hunks, states, file) {
|
|
256
281
|
const result = [...lines];
|
|
257
282
|
let offset = 0;
|
|
258
|
-
for (const hunk of hunks) {
|
|
259
|
-
const oldLines = hunk
|
|
260
|
-
|
|
261
|
-
.map((line) => line.slice(1));
|
|
262
|
-
const newLines = hunk.lines
|
|
263
|
-
.filter((line) => line[0] === " " || line[0] === "+")
|
|
264
|
-
.map((line) => line.slice(1));
|
|
283
|
+
for (const [number, hunk] of hunks.entries()) {
|
|
284
|
+
const oldLines = hunkLines(hunk, "old");
|
|
285
|
+
const newLines = hunkLines(hunk, "new");
|
|
265
286
|
const index = locate(result, oldLines, hunk.oldStart - 1 + offset);
|
|
266
|
-
if (
|
|
267
|
-
|
|
287
|
+
if (states[number] === "stock") {
|
|
288
|
+
if (index === undefined)
|
|
289
|
+
throw new Error(`TN_THREE_PATCH_INVALID: stock hunk no longer matches ${file}.`);
|
|
290
|
+
result.splice(index, oldLines.length, ...newLines);
|
|
268
291
|
}
|
|
269
|
-
|
|
292
|
+
// Already-patched hunks are left alone. Their line-count change is already in the file, so
|
|
293
|
+
// the offset still moves to keep later stock hunks near their expected location.
|
|
270
294
|
offset += newLines.length - oldLines.length;
|
|
271
295
|
}
|
|
272
296
|
return result;
|