minerender 2.1.0-alpha.41 → 2.1.0-alpha.43
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/dist/browser/index.d.mts +83 -27
- package/dist/browser/index.d.ts +83 -27
- package/dist/browser/index.js +560 -325
- package/dist/browser/index.js.map +1 -1
- package/dist/browser/index.mjs +474 -239
- package/dist/browser/index.mjs.map +1 -1
- package/dist/bundle.js +902 -661
- package/dist/bundle.js.map +1 -1
- package/dist/node/index.d.mts +83 -27
- package/dist/node/index.d.ts +83 -27
- package/dist/node/index.js +563 -325
- package/dist/node/index.js.map +1 -1
- package/dist/node/index.mjs +474 -239
- package/dist/node/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/browser/index.mjs
CHANGED
|
@@ -32,8 +32,8 @@ var require_dist = __commonJS({
|
|
|
32
32
|
__assign = Object.assign || function(t) {
|
|
33
33
|
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
34
34
|
s = arguments[i];
|
|
35
|
-
for (var
|
|
36
|
-
t[
|
|
35
|
+
for (var p10 in s) if (Object.prototype.hasOwnProperty.call(s, p10))
|
|
36
|
+
t[p10] = s[p10];
|
|
37
37
|
}
|
|
38
38
|
return t;
|
|
39
39
|
};
|
|
@@ -766,11 +766,11 @@ var ImageLoader = class _ImageLoader {
|
|
|
766
766
|
static async loadCanvasData(src) {
|
|
767
767
|
const keyStr = serializeImageKey({ src });
|
|
768
768
|
const info = this.getInfo(src);
|
|
769
|
-
const
|
|
769
|
+
const cached2 = Caching.rawImageCache.getIfPresent(keyStr);
|
|
770
770
|
try {
|
|
771
771
|
return await this.infoToCanvasData(await info);
|
|
772
772
|
} catch (err) {
|
|
773
|
-
if (
|
|
773
|
+
if (cached2 && Caching.rawImageCache.getIfPresent(keyStr) === cached2) {
|
|
774
774
|
Caching.rawImageCache.invalidate(keyStr);
|
|
775
775
|
}
|
|
776
776
|
throw err;
|
|
@@ -905,8 +905,8 @@ var Textures = class _Textures {
|
|
|
905
905
|
}
|
|
906
906
|
static getImage(key) {
|
|
907
907
|
const keyStr = serializeTextureKey(key);
|
|
908
|
-
const
|
|
909
|
-
if (
|
|
908
|
+
const cached2 = Caching.textureCache.peek(keyStr);
|
|
909
|
+
if (cached2 && TextureLoader.hasFailed(cached2)) {
|
|
910
910
|
Caching.textureCache.invalidate(keyStr);
|
|
911
911
|
}
|
|
912
912
|
return Caching.textureCache.get(keyStr, (k) => {
|
|
@@ -1173,12 +1173,12 @@ var AssetKey = class _AssetKey extends BasicAssetKey {
|
|
|
1173
1173
|
return a.join("/");
|
|
1174
1174
|
}
|
|
1175
1175
|
getFullPath() {
|
|
1176
|
-
let
|
|
1176
|
+
let p10 = [];
|
|
1177
1177
|
if (this.type) {
|
|
1178
|
-
|
|
1178
|
+
p10.push(this.type);
|
|
1179
1179
|
}
|
|
1180
|
-
|
|
1181
|
-
return
|
|
1180
|
+
p10.push(this.path);
|
|
1181
|
+
return p10.join("/");
|
|
1182
1182
|
}
|
|
1183
1183
|
toNamespacedString() {
|
|
1184
1184
|
return this.namespace + ":" + this.getFullPath();
|
|
@@ -1265,7 +1265,7 @@ var ModelMerger = class {
|
|
|
1265
1265
|
merged.display = { ...inheritedDisplay, ...DisplayTransforms.withHandFallbacks(source.display) };
|
|
1266
1266
|
}
|
|
1267
1267
|
}
|
|
1268
|
-
merged.hierarchy = models.map((m) => m.parent).filter((
|
|
1268
|
+
merged.hierarchy = models.map((m) => m.parent).filter((p10) => `${p10}`);
|
|
1269
1269
|
merged.hierarchy.push(`${merged.parent}`);
|
|
1270
1270
|
return merged;
|
|
1271
1271
|
}
|
|
@@ -1972,7 +1972,7 @@ var ModelTextures = class {
|
|
|
1972
1972
|
static async get(key) {
|
|
1973
1973
|
const keyStr = key.serialize();
|
|
1974
1974
|
const pending = this.preload(key);
|
|
1975
|
-
const
|
|
1975
|
+
const cached2 = Caching.textureAssetCache.getIfPresent(keyStr);
|
|
1976
1976
|
try {
|
|
1977
1977
|
const asset = await pending;
|
|
1978
1978
|
if (asset) {
|
|
@@ -1980,7 +1980,7 @@ var ModelTextures = class {
|
|
|
1980
1980
|
}
|
|
1981
1981
|
return void 0;
|
|
1982
1982
|
} catch (err) {
|
|
1983
|
-
if (
|
|
1983
|
+
if (cached2 && Caching.textureAssetCache.getIfPresent(keyStr) === cached2) {
|
|
1984
1984
|
Caching.textureAssetCache.invalidate(keyStr);
|
|
1985
1985
|
}
|
|
1986
1986
|
throw err;
|
|
@@ -3048,6 +3048,10 @@ var _SceneObject = class _SceneObject extends Object3D2 {
|
|
|
3048
3048
|
this.setMatrixAt(index, new Matrix43());
|
|
3049
3049
|
return reference;
|
|
3050
3050
|
}
|
|
3051
|
+
/** Returns the live reference for a raycast hit on this object's instance mesh. */
|
|
3052
|
+
getInstanceReference(mesh, index) {
|
|
3053
|
+
return mesh === this.instanceMesh ? this.instanceReferences.get(index) : void 0;
|
|
3054
|
+
}
|
|
3051
3055
|
isInstanceActive(index, reference) {
|
|
3052
3056
|
return this.instanceReferences.get(index) === reference;
|
|
3053
3057
|
}
|
|
@@ -3130,9 +3134,9 @@ var _SceneObject = class _SceneObject extends Object3D2 {
|
|
|
3130
3134
|
}
|
|
3131
3135
|
getRotationAt(index, euler = new Euler3()) {
|
|
3132
3136
|
if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
|
|
3133
|
-
const
|
|
3134
|
-
|
|
3135
|
-
return euler;
|
|
3137
|
+
const rotation = new Quaternion3();
|
|
3138
|
+
this.getMatrixAt(index).decompose(new Vector35(), rotation, new Vector35());
|
|
3139
|
+
return euler.setFromQuaternion(rotation);
|
|
3136
3140
|
}
|
|
3137
3141
|
setScaleAt(index, scale) {
|
|
3138
3142
|
if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
|
|
@@ -3388,11 +3392,12 @@ var GuiObject = class extends SceneObject {
|
|
|
3388
3392
|
// src/inspector/SceneInspector.ts
|
|
3389
3393
|
import { Raycaster, Vector2 as Vector22 } from "three";
|
|
3390
3394
|
var p7 = prefix("SceneInspector");
|
|
3391
|
-
var help = "<span>Ctrl+Click to Select<br/></span><br/>";
|
|
3395
|
+
var help = "<span>Ctrl/Cmd+Click to Select<br/></span><br/>";
|
|
3392
3396
|
var SceneInspector = class {
|
|
3393
3397
|
constructor(renderer) {
|
|
3394
3398
|
this.renderer = renderer;
|
|
3395
3399
|
this.mouse = new Vector22();
|
|
3400
|
+
this.listeners = new AbortController();
|
|
3396
3401
|
this.objectInfoContainer = document.createElement("div");
|
|
3397
3402
|
this.objectControlsContainer = document.createElement("div");
|
|
3398
3403
|
this.raycaster = new Raycaster();
|
|
@@ -3402,13 +3407,44 @@ var SceneInspector = class {
|
|
|
3402
3407
|
this.objectInfoContainer.classList.add("minerender-inspector", "minerender-object-info");
|
|
3403
3408
|
this.objectControlsContainer.classList.add("minerender-inspector", "minerender-object-controls");
|
|
3404
3409
|
this.objectInfoContainer.innerHTML = help;
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3410
|
+
const canvas = this.renderer.renderer.domElement;
|
|
3411
|
+
const options = { signal: this.listeners.signal };
|
|
3412
|
+
canvas.addEventListener("pointerdown", (event) => {
|
|
3413
|
+
this.pointer = event.button === 0 && (event.ctrlKey || event.metaKey) ? event : void 0;
|
|
3414
|
+
}, options);
|
|
3415
|
+
canvas.addEventListener("pointermove", (event) => {
|
|
3416
|
+
if (this.pointer?.pointerId === event.pointerId && Math.hypot(event.clientX - this.pointer.clientX, event.clientY - this.pointer.clientY) > 5) {
|
|
3417
|
+
this.pointer = void 0;
|
|
3418
|
+
}
|
|
3419
|
+
}, options);
|
|
3420
|
+
canvas.addEventListener("pointerup", (event) => {
|
|
3421
|
+
const start = this.pointer;
|
|
3422
|
+
this.pointer = void 0;
|
|
3423
|
+
if (start?.pointerId === event.pointerId && Math.hypot(event.clientX - start.clientX, event.clientY - start.clientY) <= 5) {
|
|
3424
|
+
this.onClick(event);
|
|
3425
|
+
}
|
|
3426
|
+
}, options);
|
|
3427
|
+
canvas.addEventListener("pointercancel", () => {
|
|
3428
|
+
this.pointer = void 0;
|
|
3429
|
+
}, options);
|
|
3430
|
+
canvas.addEventListener("pointerleave", () => {
|
|
3431
|
+
this.pointer = void 0;
|
|
3432
|
+
}, options);
|
|
3433
|
+
canvas.addEventListener("contextmenu", (event) => {
|
|
3434
|
+
if (this.pointer?.ctrlKey) event.preventDefault();
|
|
3435
|
+
}, options);
|
|
3436
|
+
}
|
|
3437
|
+
dispose() {
|
|
3438
|
+
this.listeners.abort();
|
|
3439
|
+
this.pointer = void 0;
|
|
3440
|
+
this.selectedObject = void 0;
|
|
3441
|
+
this.objectInfoContainer.remove();
|
|
3442
|
+
this.objectControlsContainer.remove();
|
|
3408
3443
|
}
|
|
3409
3444
|
findMeshChildren(from, out = []) {
|
|
3445
|
+
if (!from.visible) return out;
|
|
3410
3446
|
for (let c of from.children) {
|
|
3411
|
-
if (isMesh(c)) {
|
|
3447
|
+
if (c.visible && isMesh(c)) {
|
|
3412
3448
|
out.push(c);
|
|
3413
3449
|
}
|
|
3414
3450
|
this.findMeshChildren(c, out);
|
|
@@ -3416,50 +3452,43 @@ var SceneInspector = class {
|
|
|
3416
3452
|
return out;
|
|
3417
3453
|
}
|
|
3418
3454
|
onClick(event) {
|
|
3419
|
-
|
|
3420
|
-
if (!event.ctrlKey) return;
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
if (intersects.length > 0) {
|
|
3430
|
-
this.handleRaycasterObjects(intersects);
|
|
3431
|
-
}
|
|
3432
|
-
});
|
|
3455
|
+
const canvas = this.renderer.renderer.domElement;
|
|
3456
|
+
if (event.target !== canvas || event.button !== 0 || !(event.ctrlKey || event.metaKey)) return;
|
|
3457
|
+
const rect = canvas.getBoundingClientRect();
|
|
3458
|
+
const x = event.clientX - rect.left, y = event.clientY - rect.top;
|
|
3459
|
+
if (rect.width <= 0 || rect.height <= 0 || x < 0 || y < 0 || x >= rect.width || y >= rect.height) return;
|
|
3460
|
+
this.mouse.set(x / rect.width * 2 - 1, 1 - y / rect.height * 2);
|
|
3461
|
+
this.renderer.camera.updateWorldMatrix(true, false);
|
|
3462
|
+
this.renderer.scene.updateMatrixWorld(true);
|
|
3463
|
+
this.raycaster.setFromCamera(this.mouse, this.renderer.camera);
|
|
3464
|
+
this.handleRaycasterObjects(this.raycaster.intersectObjects(this.findMeshChildren(this.renderer.scene), false));
|
|
3433
3465
|
}
|
|
3434
3466
|
appendTo(el) {
|
|
3435
3467
|
el.append(this.objectInfoContainer);
|
|
3436
3468
|
el.append(this.objectControlsContainer);
|
|
3437
3469
|
}
|
|
3438
3470
|
handleRaycasterObjects(intersections) {
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
targetIntersection = firstIntersection;
|
|
3451
|
-
targetObject = firstObject;
|
|
3471
|
+
const hit = intersections[0];
|
|
3472
|
+
if (!hit) return;
|
|
3473
|
+
const instance = this.getIntersectionInstance(hit);
|
|
3474
|
+
this.selectObject(instance?.instanceable ?? hit.object, hit, instance);
|
|
3475
|
+
}
|
|
3476
|
+
getIntersectionInstance(hit) {
|
|
3477
|
+
if (hit?.instanceId === void 0) return void 0;
|
|
3478
|
+
for (let parent = hit.object.parent; parent; parent = parent.parent) {
|
|
3479
|
+
if (isSceneObject(parent)) {
|
|
3480
|
+
const instance = parent.getInstanceReference(hit.object, hit.instanceId);
|
|
3481
|
+
if (instance) return instance;
|
|
3452
3482
|
}
|
|
3453
|
-
if (!targetIntersection || !targetObject) return;
|
|
3454
|
-
this.selectObject(targetObject, targetIntersection);
|
|
3455
3483
|
}
|
|
3484
|
+
return void 0;
|
|
3456
3485
|
}
|
|
3457
|
-
selectObject(targetObject, targetIntersection) {
|
|
3486
|
+
selectObject(targetObject, targetIntersection, instance = this.getIntersectionInstance(targetIntersection)) {
|
|
3458
3487
|
this.selectedObject = targetObject;
|
|
3459
3488
|
console.log(p7, "selected", targetObject);
|
|
3460
|
-
this.redraw(targetObject, targetIntersection);
|
|
3489
|
+
this.redraw(targetObject, targetIntersection, instance);
|
|
3461
3490
|
}
|
|
3462
|
-
redraw(targetObject, targetIntersection) {
|
|
3491
|
+
redraw(targetObject, targetIntersection, instance) {
|
|
3463
3492
|
this.objectInfoContainer.innerHTML = help;
|
|
3464
3493
|
if (targetIntersection) {
|
|
3465
3494
|
this.addInfoLine("Distance", "D", targetIntersection.distance);
|
|
@@ -3472,8 +3501,8 @@ var SceneInspector = class {
|
|
|
3472
3501
|
if (isSceneObject(targetObject.parent)) {
|
|
3473
3502
|
}
|
|
3474
3503
|
}
|
|
3475
|
-
|
|
3476
|
-
|
|
3504
|
+
const atlas = "atlas" in targetObject ? targetObject["atlas"] : void 0;
|
|
3505
|
+
if (atlas?.image.canvas) {
|
|
3477
3506
|
const img = atlas.image.canvas;
|
|
3478
3507
|
img.style.width = "100px";
|
|
3479
3508
|
img.style.height = "100px";
|
|
@@ -3482,28 +3511,31 @@ var SceneInspector = class {
|
|
|
3482
3511
|
this.objectInfoContainer.prepend(img);
|
|
3483
3512
|
}
|
|
3484
3513
|
this.objectControlsContainer.innerHTML = "";
|
|
3485
|
-
this.addControls(targetObject, targetIntersection);
|
|
3514
|
+
this.addControls(targetObject, targetIntersection, instance);
|
|
3486
3515
|
}
|
|
3487
|
-
addControls(object, intersection) {
|
|
3516
|
+
addControls(object, intersection, instance) {
|
|
3488
3517
|
const container = document.createElement("div");
|
|
3489
3518
|
container.append(this.separator("Select Parent/Child"));
|
|
3490
3519
|
if (object.parent) {
|
|
3491
3520
|
container.append(this.buttonControl("Select Parent " + object.parent.constructor.name + " " + object.parent.name, "P", () => {
|
|
3492
|
-
this.selectObject(object.parent, intersection);
|
|
3521
|
+
this.selectObject(object.parent, intersection, instance);
|
|
3493
3522
|
}));
|
|
3494
3523
|
}
|
|
3495
3524
|
if (object.children.length > 0) {
|
|
3496
3525
|
let i = 1;
|
|
3497
3526
|
for (let child of object.children) {
|
|
3498
3527
|
container.append(this.buttonControl("Select Child " + child.constructor.name + " " + child.name, "C" + i++, () => {
|
|
3499
|
-
this.selectObject(child, intersection);
|
|
3528
|
+
this.selectObject(child, intersection, instance);
|
|
3500
3529
|
}));
|
|
3501
3530
|
}
|
|
3502
3531
|
}
|
|
3503
3532
|
container.append(this.separator());
|
|
3504
|
-
|
|
3533
|
+
const selectedInstance = instance && (object === instance.instanceable || object === intersection?.object) ? instance : void 0;
|
|
3534
|
+
if (!selectedInstance) {
|
|
3535
|
+
container.append(this.toggleControl("Visibility", "V", object.visible, (v) => object.visible = v));
|
|
3536
|
+
}
|
|
3505
3537
|
container.append(this.separator("Mesh"));
|
|
3506
|
-
this.addObjectControls(object, intersection, container);
|
|
3538
|
+
this.addObjectControls(object, intersection, container, selectedInstance);
|
|
3507
3539
|
container.append(this.separator());
|
|
3508
3540
|
this.objectControlsContainer.append(container);
|
|
3509
3541
|
}
|
|
@@ -3515,78 +3547,26 @@ var SceneInspector = class {
|
|
|
3515
3547
|
this.objectInfoContainer.append(document.createElement("br"));
|
|
3516
3548
|
return el;
|
|
3517
3549
|
}
|
|
3518
|
-
addObjectControls(target, intersection, container) {
|
|
3550
|
+
addObjectControls(target, intersection, container, instance) {
|
|
3519
3551
|
const posRange = 16 * 16;
|
|
3520
3552
|
const rotRange = 360;
|
|
3521
3553
|
const scaleRange = 4;
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
let pos = scObj.getPositionAt(intersection.instanceId);
|
|
3526
|
-
container.append(this.rangeControl("X Position", "X", -posRange + pos.x, posRange + pos.x, pos.x, 1, (v) => {
|
|
3527
|
-
pos = scObj.getPositionAt(intersection.instanceId);
|
|
3528
|
-
pos.x = v;
|
|
3529
|
-
scObj.setPositionAt(intersection.instanceId, pos);
|
|
3530
|
-
}));
|
|
3531
|
-
container.append(this.rangeControl("Y Position", "Y", -posRange + pos.y, posRange + pos.y, pos.y, 1, (v) => {
|
|
3532
|
-
pos = scObj.getPositionAt(intersection.instanceId);
|
|
3533
|
-
pos.y = v;
|
|
3534
|
-
scObj.setPositionAt(intersection.instanceId, pos);
|
|
3535
|
-
}));
|
|
3536
|
-
container.append(this.rangeControl("Z Position", "Z", -posRange + pos.z, posRange + pos.z, pos.z, 1, (v) => {
|
|
3537
|
-
pos = scObj.getPositionAt(intersection.instanceId);
|
|
3538
|
-
pos.z = v;
|
|
3539
|
-
scObj.setPositionAt(intersection.instanceId, pos);
|
|
3540
|
-
}));
|
|
3541
|
-
container.append(this.separator("Rotation"));
|
|
3542
|
-
let rot = scObj.getRotationAt(intersection.instanceId);
|
|
3543
|
-
container.append(this.rangeControl("X Rotation", "X", 0, rotRange, Math.round(toDegrees(rot.x)), 1, (v) => {
|
|
3544
|
-
rot = scObj.getRotationAt(intersection.instanceId);
|
|
3545
|
-
rot.x = toRadians(v);
|
|
3546
|
-
scObj.setRotationAt(intersection.instanceId, rot);
|
|
3547
|
-
}));
|
|
3548
|
-
container.append(this.rangeControl("Y Rotation", "Y", 0, rotRange, Math.round(toDegrees(rot.y)), 1, (v) => {
|
|
3549
|
-
rot = scObj.getRotationAt(intersection.instanceId);
|
|
3550
|
-
rot.y = toRadians(v);
|
|
3551
|
-
scObj.setRotationAt(intersection.instanceId, rot);
|
|
3552
|
-
}));
|
|
3553
|
-
container.append(this.rangeControl("Z Rotation", "Z", 0, rotRange, Math.round(toDegrees(rot.z)), 1, (v) => {
|
|
3554
|
-
rot = scObj.getRotationAt(intersection.instanceId);
|
|
3555
|
-
rot.z = toRadians(v);
|
|
3556
|
-
scObj.setRotationAt(intersection.instanceId, rot);
|
|
3557
|
-
}));
|
|
3558
|
-
container.append(this.separator("Scale"));
|
|
3559
|
-
let scl = scObj.getScale();
|
|
3560
|
-
container.append(this.rangeControl("X Scale", "X", 0, scaleRange, scl.x, 0.1, (v) => {
|
|
3561
|
-
scl = scObj.getScaleAt(intersection.instanceId);
|
|
3562
|
-
scl.x = v;
|
|
3563
|
-
scObj.setScaleAt(intersection.instanceId, scl);
|
|
3564
|
-
}));
|
|
3565
|
-
container.append(this.rangeControl("Y Scale", "Y", 0, scaleRange, scl.y, 0.1, (v) => {
|
|
3566
|
-
scl = scObj.getScaleAt(intersection.instanceId);
|
|
3567
|
-
scl.y = v;
|
|
3568
|
-
scObj.setScaleAt(intersection.instanceId, scl);
|
|
3569
|
-
}));
|
|
3570
|
-
container.append(this.rangeControl("Z Scale", "Z", 0, scaleRange, scl.z, 0.1, (v) => {
|
|
3571
|
-
scl = scObj.getScaleAt(intersection.instanceId);
|
|
3572
|
-
scl.z = v;
|
|
3573
|
-
scObj.setScaleAt(intersection.instanceId, scl);
|
|
3574
|
-
}));
|
|
3575
|
-
} else if (isTransformable(target)) {
|
|
3576
|
-
const parent = target;
|
|
3554
|
+
const transform = instance ?? (isTransformable(target) ? target : void 0);
|
|
3555
|
+
if (transform) {
|
|
3556
|
+
const parent = transform;
|
|
3577
3557
|
container.append(this.separator("Position"));
|
|
3578
3558
|
let pos = parent.getPosition();
|
|
3579
|
-
container.append(this.rangeControl("X Position", "X", -posRange, posRange, pos.x, 1, (v) => {
|
|
3559
|
+
container.append(this.rangeControl("X Position", "X", pos.x - posRange, pos.x + posRange, pos.x, 1, (v) => {
|
|
3580
3560
|
pos = parent.getPosition();
|
|
3581
3561
|
pos.x = v;
|
|
3582
3562
|
parent.setPosition(pos);
|
|
3583
3563
|
}));
|
|
3584
|
-
container.append(this.rangeControl("Y Position", "Y", -posRange, posRange, pos.y, 1, (v) => {
|
|
3564
|
+
container.append(this.rangeControl("Y Position", "Y", pos.y - posRange, pos.y + posRange, pos.y, 1, (v) => {
|
|
3585
3565
|
pos = parent.getPosition();
|
|
3586
3566
|
pos.y = v;
|
|
3587
3567
|
parent.setPosition(pos);
|
|
3588
3568
|
}));
|
|
3589
|
-
container.append(this.rangeControl("Z Position", "Z", -posRange, posRange, pos.z, 1, (v) => {
|
|
3569
|
+
container.append(this.rangeControl("Z Position", "Z", pos.z - posRange, pos.z + posRange, pos.z, 1, (v) => {
|
|
3590
3570
|
pos = parent.getPosition();
|
|
3591
3571
|
pos.z = v;
|
|
3592
3572
|
parent.setPosition(pos);
|
|
@@ -3675,6 +3655,7 @@ var SceneInspector = class {
|
|
|
3675
3655
|
toggle.checked = val;
|
|
3676
3656
|
toggle.addEventListener("change", (e) => {
|
|
3677
3657
|
change(toggle.checked);
|
|
3658
|
+
this.renderer.scene.dirty = true;
|
|
3678
3659
|
});
|
|
3679
3660
|
label.append(toggle);
|
|
3680
3661
|
label.append(document.createElement("br"));
|
|
@@ -3687,7 +3668,6 @@ var SceneInspector = class {
|
|
|
3687
3668
|
label.setAttribute("title", name);
|
|
3688
3669
|
labelText.style.width = "18%";
|
|
3689
3670
|
labelText.style.display = "inline-block";
|
|
3690
|
-
labelText.innerText = `${id} (${val})`;
|
|
3691
3671
|
const range = document.createElement("input");
|
|
3692
3672
|
range.setAttribute("type", "range");
|
|
3693
3673
|
range.style.width = "80%";
|
|
@@ -3695,8 +3675,10 @@ var SceneInspector = class {
|
|
|
3695
3675
|
range.min = `${min}`;
|
|
3696
3676
|
range.step = `${step}`;
|
|
3697
3677
|
range.value = `${val}`;
|
|
3678
|
+
labelText.innerText = `${id} (${range.value})`;
|
|
3698
3679
|
const onChange = () => {
|
|
3699
3680
|
change(parseFloat(range.value));
|
|
3681
|
+
this.renderer.scene.dirty = true;
|
|
3700
3682
|
labelText.innerText = `${id} (${range.value})`;
|
|
3701
3683
|
};
|
|
3702
3684
|
range.addEventListener("input", onChange);
|
|
@@ -3856,6 +3838,93 @@ var ModelCulling = class {
|
|
|
3856
3838
|
}
|
|
3857
3839
|
};
|
|
3858
3840
|
|
|
3841
|
+
// src/model/block/BlockStateResolver.ts
|
|
3842
|
+
import { Euler as Euler5 } from "three";
|
|
3843
|
+
function matchesCondition(condition, state) {
|
|
3844
|
+
return Object.entries(condition).every(([key, value]) => {
|
|
3845
|
+
if (Array.isArray(value)) {
|
|
3846
|
+
if (key === "OR") return value.some((child) => matchesCondition(child, state));
|
|
3847
|
+
if (key === "AND") return value.every((child) => matchesCondition(child, state));
|
|
3848
|
+
return false;
|
|
3849
|
+
}
|
|
3850
|
+
return typeof value === "string" && state[key] !== void 0 && value.split("|").includes(`${state[key]}`);
|
|
3851
|
+
});
|
|
3852
|
+
}
|
|
3853
|
+
var BlockStateResolver = class {
|
|
3854
|
+
static async defaults(blockState) {
|
|
3855
|
+
const defaults = blockState.key ? await BlockStates.getDefaultState(blockState.key) : void 0;
|
|
3856
|
+
const state = {};
|
|
3857
|
+
if (defaults && Object.keys(defaults).length > 0) {
|
|
3858
|
+
for (const key in defaults) state[key] = defaults[key].default;
|
|
3859
|
+
} else if (blockState.variants) {
|
|
3860
|
+
const variant = Object.keys(blockState.variants)[0];
|
|
3861
|
+
if (variant) {
|
|
3862
|
+
for (const property of variant.split(",")) {
|
|
3863
|
+
const [key, value] = property.split("=");
|
|
3864
|
+
state[key] = value;
|
|
3865
|
+
}
|
|
3866
|
+
}
|
|
3867
|
+
} else if (blockState.multipart) {
|
|
3868
|
+
const condition = blockState.multipart.map((part) => part.when).find((when) => when !== void 0 && Object.values(when).every((value) => typeof value === "string"));
|
|
3869
|
+
for (const [key, value] of Object.entries(condition ?? {})) state[key] = value.split("|")[0];
|
|
3870
|
+
}
|
|
3871
|
+
return state;
|
|
3872
|
+
}
|
|
3873
|
+
static select(blockState, state, choose = this.choose) {
|
|
3874
|
+
return this.matching(blockState, state).map(choose);
|
|
3875
|
+
}
|
|
3876
|
+
static matching(blockState, state) {
|
|
3877
|
+
const out = [];
|
|
3878
|
+
if (blockState.variants) {
|
|
3879
|
+
if (Object.keys(blockState.variants).length === 1 && "" in blockState.variants) {
|
|
3880
|
+
out.push(blockState.variants[""]);
|
|
3881
|
+
} else {
|
|
3882
|
+
for (const variantKey in blockState.variants) {
|
|
3883
|
+
const matches = variantKey.split(",").every((property) => {
|
|
3884
|
+
const [key, value] = property.split("=");
|
|
3885
|
+
return `${state[key]}` === `${value}`;
|
|
3886
|
+
});
|
|
3887
|
+
if (matches) out.push(blockState.variants[variantKey]);
|
|
3888
|
+
}
|
|
3889
|
+
}
|
|
3890
|
+
} else if (blockState.multipart) {
|
|
3891
|
+
for (const part of blockState.multipart) {
|
|
3892
|
+
if (part.apply && (!part.when || matchesCondition(part.when, state))) {
|
|
3893
|
+
out.push(part.apply);
|
|
3894
|
+
}
|
|
3895
|
+
}
|
|
3896
|
+
}
|
|
3897
|
+
return out;
|
|
3898
|
+
}
|
|
3899
|
+
static choose(variants) {
|
|
3900
|
+
if (!Array.isArray(variants)) return variants;
|
|
3901
|
+
if (!variants.length) throw new MineRenderError("Blockstate variant arrays must not be empty");
|
|
3902
|
+
const total = variants.reduce((sum, variant) => {
|
|
3903
|
+
const weight = variant.weight ?? 1;
|
|
3904
|
+
if (!Number.isInteger(weight) || weight < 1) {
|
|
3905
|
+
throw new MineRenderError(`Invalid blockstate variant weight: ${weight}`);
|
|
3906
|
+
}
|
|
3907
|
+
return sum + weight;
|
|
3908
|
+
}, 0);
|
|
3909
|
+
let choice = Math.random() * total;
|
|
3910
|
+
for (const variant of variants) {
|
|
3911
|
+
choice -= variant.weight ?? 1;
|
|
3912
|
+
if (choice < 0) return variant;
|
|
3913
|
+
}
|
|
3914
|
+
return variants[variants.length - 1];
|
|
3915
|
+
}
|
|
3916
|
+
static rotation(variant) {
|
|
3917
|
+
const rotation = new Euler5();
|
|
3918
|
+
if (typeof variant.x !== "undefined") {
|
|
3919
|
+
rotation.x = toRadians(clampRotationDegrees(variant.x));
|
|
3920
|
+
}
|
|
3921
|
+
if (typeof variant.y !== "undefined") {
|
|
3922
|
+
rotation.y = toRadians(clampRotationDegrees(typeof variant.x !== "undefined" ? variant.y : 360 - variant.y));
|
|
3923
|
+
}
|
|
3924
|
+
return rotation;
|
|
3925
|
+
}
|
|
3926
|
+
};
|
|
3927
|
+
|
|
3859
3928
|
// src/model/block/blockTints.json
|
|
3860
3929
|
var blockTints_default = {
|
|
3861
3930
|
"minecraft:large_fern": { source: "grass" },
|
|
@@ -3942,7 +4011,7 @@ var BlockTints = class {
|
|
|
3942
4011
|
};
|
|
3943
4012
|
|
|
3944
4013
|
// src/model/scene/ModelObject.ts
|
|
3945
|
-
import { BoxGeometry as BoxGeometry5, BufferAttribute as BufferAttribute4, Color as Color3, Euler as
|
|
4014
|
+
import { BoxGeometry as BoxGeometry5, BufferAttribute as BufferAttribute4, Color as Color3, Euler as Euler6, Matrix4 as Matrix44 } from "three";
|
|
3946
4015
|
|
|
3947
4016
|
// src/three/BufferGeometryUtils.js
|
|
3948
4017
|
import {
|
|
@@ -4533,7 +4602,7 @@ var _ModelObject = class _ModelObject extends SceneObject {
|
|
|
4533
4602
|
elGeo.clearGroups();
|
|
4534
4603
|
}
|
|
4535
4604
|
if (this.options.uvLockRotation) {
|
|
4536
|
-
UVMapper.lockUvs(elGeo, el.faces, this.atlas, new
|
|
4605
|
+
UVMapper.lockUvs(elGeo, el.faces, this.atlas, new Euler6(...this.options.uvLockRotation));
|
|
4537
4606
|
}
|
|
4538
4607
|
if (this.options.tints) {
|
|
4539
4608
|
const colors = new Float32Array(elGeo.getAttribute("position").count * 3).fill(1);
|
|
@@ -4631,18 +4700,7 @@ function isModelObject(obj) {
|
|
|
4631
4700
|
|
|
4632
4701
|
// src/model/block/scene/BlockObject.ts
|
|
4633
4702
|
var import_ts_deepmerge6 = __toESM(require_dist());
|
|
4634
|
-
import { Euler as
|
|
4635
|
-
var p10 = prefix("BlockObject");
|
|
4636
|
-
function matchesCondition(condition, state) {
|
|
4637
|
-
return Object.entries(condition).every(([key, value]) => {
|
|
4638
|
-
if (Array.isArray(value)) {
|
|
4639
|
-
if (key === "OR") return value.some((child) => matchesCondition(child, state));
|
|
4640
|
-
if (key === "AND") return value.every((child) => matchesCondition(child, state));
|
|
4641
|
-
return false;
|
|
4642
|
-
}
|
|
4643
|
-
return typeof value === "string" && state[key] !== void 0 && value.split("|").includes(`${state[key]}`);
|
|
4644
|
-
});
|
|
4645
|
-
}
|
|
4703
|
+
import { Euler as Euler7, Matrix4 as Matrix45, Quaternion as Quaternion4, Vector3 as Vector38 } from "three";
|
|
4646
4704
|
var _BlockObject = class _BlockObject extends SceneObject {
|
|
4647
4705
|
constructor(blockState, options) {
|
|
4648
4706
|
super(options);
|
|
@@ -4661,22 +4719,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
|
|
|
4661
4719
|
}
|
|
4662
4720
|
async init() {
|
|
4663
4721
|
if (this.options.applyDefaultState) {
|
|
4664
|
-
|
|
4665
|
-
if (defaultState && Object.keys(defaultState).length > 0) {
|
|
4666
|
-
const state = {};
|
|
4667
|
-
for (let k in defaultState) {
|
|
4668
|
-
state[k] = defaultState[k].default;
|
|
4669
|
-
}
|
|
4670
|
-
this._setState(state);
|
|
4671
|
-
} else {
|
|
4672
|
-
if (this.blockState.variants) {
|
|
4673
|
-
this._setState(Object.keys(this.blockState.variants)[0]);
|
|
4674
|
-
} else if (this.blockState.multipart) {
|
|
4675
|
-
const condition = this.blockState.multipart.map((part) => part.when).find((when) => when !== void 0 && Object.values(when).every((value) => typeof value === "string"));
|
|
4676
|
-
const state = Object.fromEntries(Object.entries(condition ?? {}).map(([key, value]) => [key, value.split("|")[0]]));
|
|
4677
|
-
this._setState(state);
|
|
4678
|
-
}
|
|
4679
|
-
}
|
|
4722
|
+
this._setState(await BlockStateResolver.defaults(this.blockState));
|
|
4680
4723
|
}
|
|
4681
4724
|
if (this.options.initialState !== void 0) this._setState(this.options.initialState);
|
|
4682
4725
|
await this.recreateModels();
|
|
@@ -4719,7 +4762,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
|
|
|
4719
4762
|
const scale = new Vector38();
|
|
4720
4763
|
this.getModelMatrix(model).decompose(position, rotation, scale);
|
|
4721
4764
|
if (position.distanceToSquared(this.position) > 1e-10 || scale.distanceToSquared(new Vector38(1, 1, 1)) > 1e-10) return 0;
|
|
4722
|
-
return ModelCulling.toLocalMask(worldMask, new
|
|
4765
|
+
return ModelCulling.toLocalMask(worldMask, new Euler7().setFromQuaternion(rotation));
|
|
4723
4766
|
}
|
|
4724
4767
|
async setCullMask(worldMask) {
|
|
4725
4768
|
worldMask &= 63;
|
|
@@ -4767,39 +4810,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
|
|
|
4767
4810
|
return ref;
|
|
4768
4811
|
}
|
|
4769
4812
|
async mapStateToVariant(state) {
|
|
4770
|
-
|
|
4771
|
-
if (this.blockState.variants) {
|
|
4772
|
-
if (Object.keys(this.blockState.variants).length === 1 && "" in this.blockState.variants) {
|
|
4773
|
-
out.push(this.getSingleVariant(this.blockState.variants[""]));
|
|
4774
|
-
} else {
|
|
4775
|
-
for (let variantKey in this.blockState.variants) {
|
|
4776
|
-
const split = variantKey.split(",");
|
|
4777
|
-
let matches = true;
|
|
4778
|
-
for (let s of split) {
|
|
4779
|
-
const [k, v] = s.split("=");
|
|
4780
|
-
if (`${state[k]}` !== `${v}`) {
|
|
4781
|
-
matches = false;
|
|
4782
|
-
break;
|
|
4783
|
-
}
|
|
4784
|
-
}
|
|
4785
|
-
if (matches) {
|
|
4786
|
-
const variants = this.blockState.variants[variantKey];
|
|
4787
|
-
out.push(this.getSingleVariant(variants));
|
|
4788
|
-
}
|
|
4789
|
-
}
|
|
4790
|
-
}
|
|
4791
|
-
} else if (this.blockState.multipart) {
|
|
4792
|
-
for (let part of this.blockState.multipart) {
|
|
4793
|
-
if (!part.apply) {
|
|
4794
|
-
console.debug(p10, "Missing apply for blockState part", part);
|
|
4795
|
-
continue;
|
|
4796
|
-
}
|
|
4797
|
-
if (!part.when || matchesCondition(part.when, state)) {
|
|
4798
|
-
out.push(this.getSingleVariant(part.apply));
|
|
4799
|
-
}
|
|
4800
|
-
}
|
|
4801
|
-
}
|
|
4802
|
-
return out;
|
|
4813
|
+
return BlockStateResolver.select(this.blockState, state, (variants) => this.getSingleVariant(variants));
|
|
4803
4814
|
}
|
|
4804
4815
|
async recreateModels() {
|
|
4805
4816
|
this.clearModels();
|
|
@@ -4810,21 +4821,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
|
|
|
4810
4821
|
}
|
|
4811
4822
|
}
|
|
4812
4823
|
getSingleVariant(variants) {
|
|
4813
|
-
|
|
4814
|
-
if (!variants.length) throw new MineRenderError("Blockstate variant arrays must not be empty");
|
|
4815
|
-
const total = variants.reduce((sum, variant) => {
|
|
4816
|
-
const weight = variant.weight ?? 1;
|
|
4817
|
-
if (!Number.isInteger(weight) || weight < 1) {
|
|
4818
|
-
throw new MineRenderError(`Invalid blockstate variant weight: ${weight}`);
|
|
4819
|
-
}
|
|
4820
|
-
return sum + weight;
|
|
4821
|
-
}, 0);
|
|
4822
|
-
let choice = Math.random() * total;
|
|
4823
|
-
for (const variant of variants) {
|
|
4824
|
-
choice -= variant.weight ?? 1;
|
|
4825
|
-
if (choice < 0) return variant;
|
|
4826
|
-
}
|
|
4827
|
-
return variants[variants.length - 1];
|
|
4824
|
+
return BlockStateResolver.choose(variants);
|
|
4828
4825
|
}
|
|
4829
4826
|
// @deprecated
|
|
4830
4827
|
async createAVariant(variants, instanceInfo) {
|
|
@@ -4832,13 +4829,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
|
|
|
4832
4829
|
await this.createVariant(variant);
|
|
4833
4830
|
}
|
|
4834
4831
|
async createVariant(variant) {
|
|
4835
|
-
const rotation =
|
|
4836
|
-
if (typeof variant.x !== "undefined") {
|
|
4837
|
-
rotation.x = toRadians(clampRotationDegrees(variant.x));
|
|
4838
|
-
}
|
|
4839
|
-
if (typeof variant.y !== "undefined") {
|
|
4840
|
-
rotation.y = toRadians(clampRotationDegrees(typeof variant.x !== "undefined" ? variant.y : 360 - variant.y));
|
|
4841
|
-
}
|
|
4832
|
+
const rotation = BlockStateResolver.rotation(variant);
|
|
4842
4833
|
const modelKey = AssetKey.parse("models", variant.model);
|
|
4843
4834
|
modelKey.root = this.blockState.key?.root;
|
|
4844
4835
|
const model = await Models.getMerged(modelKey);
|
|
@@ -9343,32 +9334,121 @@ var AnvilParser = class {
|
|
|
9343
9334
|
};
|
|
9344
9335
|
|
|
9345
9336
|
// src/world/Chunk.ts
|
|
9337
|
+
import { Vector3 as Vector313 } from "three";
|
|
9338
|
+
|
|
9339
|
+
// src/world/MineRenderWorld.ts
|
|
9346
9340
|
import { Vector3 as Vector312 } from "three";
|
|
9347
9341
|
|
|
9342
|
+
// src/world/SectionModels.ts
|
|
9343
|
+
import { Matrix4 as Matrix46, Vector3 as Vector311 } from "three";
|
|
9344
|
+
var SectionModel = class extends ModelObject {
|
|
9345
|
+
applyTextures() {
|
|
9346
|
+
}
|
|
9347
|
+
};
|
|
9348
|
+
function cached(map, key, load) {
|
|
9349
|
+
let value = map.get(key);
|
|
9350
|
+
if (!value) {
|
|
9351
|
+
value = load().catch((error) => {
|
|
9352
|
+
map.delete(key);
|
|
9353
|
+
throw error;
|
|
9354
|
+
});
|
|
9355
|
+
map.set(key, value);
|
|
9356
|
+
}
|
|
9357
|
+
return value;
|
|
9358
|
+
}
|
|
9359
|
+
var SectionModels = class {
|
|
9360
|
+
constructor(maxAtlasSize = 2048) {
|
|
9361
|
+
this.maxAtlasSize = maxAtlasSize;
|
|
9362
|
+
this.states = /* @__PURE__ */ new WeakMap();
|
|
9363
|
+
this.models = /* @__PURE__ */ new WeakMap();
|
|
9364
|
+
this.templates = /* @__PURE__ */ new Set();
|
|
9365
|
+
if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("maxAtlasSize must be a positive integer");
|
|
9366
|
+
}
|
|
9367
|
+
async get(blockState, properties = {}) {
|
|
9368
|
+
if (!blockState.variants || blockState.multipart) return void 0;
|
|
9369
|
+
let states = this.states.get(blockState);
|
|
9370
|
+
if (!states) this.states.set(blockState, states = /* @__PURE__ */ new Map());
|
|
9371
|
+
const key = JSON.stringify(Object.entries(properties).sort(([a], [b]) => a.localeCompare(b)));
|
|
9372
|
+
const prepared = await cached(states, key, () => this.prepare(blockState, properties));
|
|
9373
|
+
if (!prepared) return void 0;
|
|
9374
|
+
return prepared.templates.get(BlockStateResolver.choose(prepared.variants));
|
|
9375
|
+
}
|
|
9376
|
+
async prepare(blockState, properties) {
|
|
9377
|
+
const state = { ...await BlockStateResolver.defaults(blockState), ...properties };
|
|
9378
|
+
const groups = BlockStateResolver.matching(blockState, state);
|
|
9379
|
+
if (groups.length !== 1) return void 0;
|
|
9380
|
+
const variants = groups[0];
|
|
9381
|
+
const choices = Array.isArray(variants) ? variants : [variants];
|
|
9382
|
+
if (!choices.length) return void 0;
|
|
9383
|
+
const templates = /* @__PURE__ */ new Map();
|
|
9384
|
+
for (const variant of choices) {
|
|
9385
|
+
const model = await Models.getMerged(AssetKey.parse("models", variant.model));
|
|
9386
|
+
if (!model) return void 0;
|
|
9387
|
+
const atlas = await UVMapper.getAtlas(model);
|
|
9388
|
+
const rotation = BlockStateResolver.rotation(variant);
|
|
9389
|
+
if (!atlas || atlas.hasAnimation || !ModelCulling.isOpaqueFullCube(atlas) || atlas.image.width > this.maxAtlasSize || atlas.image.height > this.maxAtlasSize || ModelCulling.toLocalMask(63, rotation) !== 63) return void 0;
|
|
9390
|
+
const tints = await BlockTints.get(blockState.key, state, model);
|
|
9391
|
+
let models = this.models.get(model);
|
|
9392
|
+
if (!models) this.models.set(model, models = /* @__PURE__ */ new Map());
|
|
9393
|
+
const key = JSON.stringify([rotation.x, rotation.y, rotation.z, variant.uvlock, tints]);
|
|
9394
|
+
const template = await cached(models, key, async () => {
|
|
9395
|
+
const object = new SectionModel(model, {
|
|
9396
|
+
instanceMeshes: false,
|
|
9397
|
+
mergeMeshes: false,
|
|
9398
|
+
tints,
|
|
9399
|
+
uvLockRotation: variant.uvlock && (rotation.x !== 0 || rotation.y !== 0) ? [rotation.x, rotation.y, rotation.z] : void 0
|
|
9400
|
+
});
|
|
9401
|
+
await object.init();
|
|
9402
|
+
const geometry = object.children[0].geometry;
|
|
9403
|
+
geometry.applyMatrix4(new Matrix46().makeRotationFromEuler(rotation));
|
|
9404
|
+
object.clear();
|
|
9405
|
+
const cullFaces = CUBE_FACES.map((face) => {
|
|
9406
|
+
const local = CUBE_FACES.findIndex((name) => name === atlas.model.elements[0].faces[face]?.cullface);
|
|
9407
|
+
if (local < 0) return 0;
|
|
9408
|
+
const normal = new Vector311(...CUBE_FACE_OFFSETS[local]).applyEuler(rotation);
|
|
9409
|
+
const world = CUBE_FACE_OFFSETS.findIndex(([x, y, z]) => Math.abs(normal.x - x) < 1e-6 && Math.abs(normal.y - y) < 1e-6 && Math.abs(normal.z - z) < 1e-6);
|
|
9410
|
+
return 1 << world;
|
|
9411
|
+
});
|
|
9412
|
+
const template2 = { geometry, atlas, cullFaces };
|
|
9413
|
+
this.templates.add(template2);
|
|
9414
|
+
return template2;
|
|
9415
|
+
});
|
|
9416
|
+
templates.set(variant, template);
|
|
9417
|
+
}
|
|
9418
|
+
return { variants, templates };
|
|
9419
|
+
}
|
|
9420
|
+
clear() {
|
|
9421
|
+
for (const template of this.templates) template.geometry.dispose();
|
|
9422
|
+
this.templates.clear();
|
|
9423
|
+
this.states = /* @__PURE__ */ new WeakMap();
|
|
9424
|
+
this.models = /* @__PURE__ */ new WeakMap();
|
|
9425
|
+
}
|
|
9426
|
+
};
|
|
9427
|
+
|
|
9348
9428
|
// src/world/MineRenderWorld.ts
|
|
9349
|
-
import { Vector3 as Vector311 } from "three";
|
|
9350
9429
|
var MineRenderWorld = class {
|
|
9351
|
-
constructor(scene) {
|
|
9430
|
+
constructor(scene, options = {}) {
|
|
9352
9431
|
this._chunks = /* @__PURE__ */ new Map();
|
|
9353
9432
|
this.pendingCulling = /* @__PURE__ */ new Map();
|
|
9354
9433
|
this.scene = scene;
|
|
9434
|
+
if (options.sectionMeshing) this.sectionModels = new SectionModels(options.maxAtlasSize);
|
|
9355
9435
|
}
|
|
9356
9436
|
getBlockAt(posOrX, y, z) {
|
|
9357
9437
|
if (typeof posOrX == "number") {
|
|
9358
|
-
return this.getBlockAt(new
|
|
9438
|
+
return this.getBlockAt(new Vector312(posOrX, y, z));
|
|
9359
9439
|
}
|
|
9360
9440
|
if (isTripleArray(posOrX)) {
|
|
9361
|
-
return this.getBlockAt(new
|
|
9441
|
+
return this.getBlockAt(new Vector312(posOrX[0], posOrX[1], posOrX[2]));
|
|
9362
9442
|
}
|
|
9363
9443
|
this.validatePosBounds(posOrX);
|
|
9364
9444
|
return this.getChunkAt(posOrX)?.getBlockAt(posOrX);
|
|
9365
9445
|
}
|
|
9366
9446
|
async setBlockAt(posOrX, yOrBlock, z, block) {
|
|
9367
9447
|
if (typeof posOrX == "number") {
|
|
9368
|
-
return this.setBlockAt(new
|
|
9448
|
+
return this.setBlockAt(new Vector312(posOrX, yOrBlock, z), block);
|
|
9369
9449
|
}
|
|
9370
9450
|
if (isTripleArray(posOrX)) {
|
|
9371
|
-
return this.setBlockAt(new
|
|
9451
|
+
return this.setBlockAt(new Vector312(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
|
|
9372
9452
|
}
|
|
9373
9453
|
return this.placeBlock(posOrX, yOrBlock);
|
|
9374
9454
|
}
|
|
@@ -9389,7 +9469,7 @@ var MineRenderWorld = class {
|
|
|
9389
9469
|
const collect = async (positions2) => {
|
|
9390
9470
|
for (const pos of positions2) changes.set(pos.toArray().join(","), pos);
|
|
9391
9471
|
};
|
|
9392
|
-
const place = (block) => this.placeBlock(new
|
|
9472
|
+
const place = (block) => this.placeBlock(new Vector312(...block.position), block, collect);
|
|
9393
9473
|
const keys = /* @__PURE__ */ new Map();
|
|
9394
9474
|
for (const block of multiblock.blocks) {
|
|
9395
9475
|
if (Chunk.isAir(block)) continue;
|
|
@@ -9461,12 +9541,13 @@ var MineRenderWorld = class {
|
|
|
9461
9541
|
for (const chunk of chunks) {
|
|
9462
9542
|
await chunk.dispose();
|
|
9463
9543
|
}
|
|
9544
|
+
this.sectionModels?.clear();
|
|
9464
9545
|
}
|
|
9465
9546
|
updateCulling(positions) {
|
|
9466
9547
|
for (const pos of positions) {
|
|
9467
9548
|
this.pendingCulling.set(pos.toArray().join(","), pos.clone());
|
|
9468
9549
|
for (const offset of CUBE_FACE_OFFSETS) {
|
|
9469
|
-
const neighbor = pos.clone().add(new
|
|
9550
|
+
const neighbor = pos.clone().add(new Vector312(...offset));
|
|
9470
9551
|
this.pendingCulling.set(neighbor.toArray().join(","), neighbor);
|
|
9471
9552
|
}
|
|
9472
9553
|
}
|
|
@@ -9475,17 +9556,22 @@ var MineRenderWorld = class {
|
|
|
9475
9556
|
while (this.pendingCulling.size) {
|
|
9476
9557
|
const batch = [...this.pendingCulling.values()];
|
|
9477
9558
|
this.pendingCulling.clear();
|
|
9559
|
+
const changed = /* @__PURE__ */ new Set();
|
|
9478
9560
|
for (const pos of batch) {
|
|
9479
|
-
const
|
|
9480
|
-
if (!
|
|
9561
|
+
const chunk = this.getChunkAt(pos);
|
|
9562
|
+
if (!chunk) continue;
|
|
9563
|
+
changed.add(chunk);
|
|
9564
|
+
if (!chunk.getBlockAt(pos)) continue;
|
|
9481
9565
|
let mask = 0;
|
|
9482
9566
|
for (const [face, offset] of CUBE_FACE_OFFSETS.entries()) {
|
|
9483
|
-
|
|
9567
|
+
const neighbor = pos.clone().add(new Vector312(...offset));
|
|
9568
|
+
if (this.getChunkAt(neighbor)?.isOccludingAt(neighbor)) {
|
|
9484
9569
|
mask |= 1 << face;
|
|
9485
9570
|
}
|
|
9486
9571
|
}
|
|
9487
|
-
await
|
|
9572
|
+
await chunk.setCullMaskAt(pos, mask);
|
|
9488
9573
|
}
|
|
9574
|
+
for (const chunk of changed) chunk.rebuildSectionMesh();
|
|
9489
9575
|
}
|
|
9490
9576
|
} finally {
|
|
9491
9577
|
this.culling = void 0;
|
|
@@ -9501,7 +9587,8 @@ var MineRenderWorld = class {
|
|
|
9501
9587
|
Math.floor(pos.x / 16),
|
|
9502
9588
|
Math.floor(pos.y / 16),
|
|
9503
9589
|
Math.floor(pos.z / 16),
|
|
9504
|
-
(positions) => this.updateCulling(positions)
|
|
9590
|
+
(positions) => this.updateCulling(positions),
|
|
9591
|
+
this.sectionModels
|
|
9505
9592
|
);
|
|
9506
9593
|
this._chunks.set(key, chunk);
|
|
9507
9594
|
}
|
|
@@ -9511,14 +9598,14 @@ var MineRenderWorld = class {
|
|
|
9511
9598
|
return this._chunks.get(this.worldPosToChunkKey(pos));
|
|
9512
9599
|
}
|
|
9513
9600
|
static worldToScenePosition(pos) {
|
|
9514
|
-
return new
|
|
9601
|
+
return new Vector312(
|
|
9515
9602
|
pos.x * 16,
|
|
9516
9603
|
pos.y * 16,
|
|
9517
9604
|
pos.z * 16
|
|
9518
9605
|
);
|
|
9519
9606
|
}
|
|
9520
9607
|
static sceneToWorldPosition(pos) {
|
|
9521
|
-
return new
|
|
9608
|
+
return new Vector312(
|
|
9522
9609
|
pos.x / 16,
|
|
9523
9610
|
pos.y / 16,
|
|
9524
9611
|
pos.z / 16
|
|
@@ -9537,12 +9624,118 @@ var MineRenderWorld = class {
|
|
|
9537
9624
|
}
|
|
9538
9625
|
};
|
|
9539
9626
|
|
|
9627
|
+
// src/world/SectionMesh.ts
|
|
9628
|
+
import { BufferGeometry as BufferGeometry2, Float32BufferAttribute as Float32BufferAttribute4, Group, Mesh as Mesh7 } from "three";
|
|
9629
|
+
var SectionMesh = class _SectionMesh extends Group {
|
|
9630
|
+
constructor() {
|
|
9631
|
+
super(...arguments);
|
|
9632
|
+
this.ownedMeshes = [];
|
|
9633
|
+
}
|
|
9634
|
+
static build(entries, maxAtlasSize = 2048) {
|
|
9635
|
+
if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("Section atlas size must be a positive integer");
|
|
9636
|
+
const visible = entries.filter((entry) => entry.template.cullFaces.some((direction) => !(entry.cullMask & direction)));
|
|
9637
|
+
const atlases = [...new Set(visible.map((entry) => entry.template.atlas))].sort((a, b) => b.image.height - a.image.height);
|
|
9638
|
+
const pages = [];
|
|
9639
|
+
const locations = /* @__PURE__ */ new Map();
|
|
9640
|
+
for (const atlas of atlases) {
|
|
9641
|
+
const { width, height } = atlas.image;
|
|
9642
|
+
if (width > maxAtlasSize || height > maxAtlasSize) throw new RangeError("Model atlas exceeds the section atlas size limit");
|
|
9643
|
+
let selected;
|
|
9644
|
+
for (const page of pages) {
|
|
9645
|
+
const nextRow = page.x + width > maxAtlasSize;
|
|
9646
|
+
if ((nextRow ? page.y + page.rowHeight : page.y) + height > maxAtlasSize) continue;
|
|
9647
|
+
if (nextRow) {
|
|
9648
|
+
page.y += page.rowHeight;
|
|
9649
|
+
page.x = 0;
|
|
9650
|
+
page.rowHeight = 0;
|
|
9651
|
+
}
|
|
9652
|
+
selected = page;
|
|
9653
|
+
break;
|
|
9654
|
+
}
|
|
9655
|
+
if (!selected) {
|
|
9656
|
+
selected = { placements: [], entries: [], x: 0, y: 0, rowHeight: 0, width: 0, height: 0 };
|
|
9657
|
+
pages.push(selected);
|
|
9658
|
+
}
|
|
9659
|
+
const placement = { atlas, x: selected.x, y: selected.y };
|
|
9660
|
+
selected.placements.push(placement);
|
|
9661
|
+
selected.x += width;
|
|
9662
|
+
selected.rowHeight = Math.max(selected.rowHeight, height);
|
|
9663
|
+
selected.width = Math.max(selected.width, selected.x);
|
|
9664
|
+
selected.height = Math.max(selected.height, selected.y + height);
|
|
9665
|
+
locations.set(atlas, { page: selected, placement });
|
|
9666
|
+
}
|
|
9667
|
+
for (const entry of visible) locations.get(entry.template.atlas).page.entries.push(entry);
|
|
9668
|
+
const section = new _SectionMesh();
|
|
9669
|
+
for (const page of pages) {
|
|
9670
|
+
const canvas = createCanvas(page.width, page.height);
|
|
9671
|
+
const context = canvas.getContext("2d");
|
|
9672
|
+
for (const { atlas, x, y } of page.placements) {
|
|
9673
|
+
context.drawImage(atlas.image.canvas, x, y);
|
|
9674
|
+
}
|
|
9675
|
+
const positions = [], normals = [], uvs = [], colors = [], indices = [];
|
|
9676
|
+
for (const { index, template, cullMask } of page.entries) {
|
|
9677
|
+
const position = template.geometry.getAttribute("position");
|
|
9678
|
+
const normal = template.geometry.getAttribute("normal");
|
|
9679
|
+
const uv = template.geometry.getAttribute("uv");
|
|
9680
|
+
const color = template.geometry.getAttribute("color");
|
|
9681
|
+
const sourceIndices = template.geometry.getIndex();
|
|
9682
|
+
const placement = locations.get(template.atlas).placement;
|
|
9683
|
+
const offsetX = index % 16 * 16;
|
|
9684
|
+
const offsetY = Math.floor(index / 256) * 16;
|
|
9685
|
+
const offsetZ = Math.floor(index / 16) % 16 * 16;
|
|
9686
|
+
for (let face = 0; face < 6; face++) {
|
|
9687
|
+
if (cullMask & template.cullFaces[face]) continue;
|
|
9688
|
+
const start = positions.length / 3;
|
|
9689
|
+
for (let corner = 0; corner < 4; corner++) {
|
|
9690
|
+
const vertex = face * 4 + corner;
|
|
9691
|
+
positions.push(position.getX(vertex) + offsetX, position.getY(vertex) + offsetY, position.getZ(vertex) + offsetZ);
|
|
9692
|
+
normals.push(normal.getX(vertex), normal.getY(vertex), normal.getZ(vertex));
|
|
9693
|
+
uvs.push(
|
|
9694
|
+
(placement.x + uv.getX(vertex) * template.atlas.image.width) / page.width,
|
|
9695
|
+
1 - (placement.y + (1 - uv.getY(vertex)) * template.atlas.image.height) / page.height
|
|
9696
|
+
);
|
|
9697
|
+
colors.push(color?.getX(vertex) ?? 1, color?.getY(vertex) ?? 1, color?.getZ(vertex) ?? 1);
|
|
9698
|
+
}
|
|
9699
|
+
for (let corner = 0; corner < 6; corner++) indices.push(start + sourceIndices.getX(face * 6 + corner) - face * 4);
|
|
9700
|
+
}
|
|
9701
|
+
}
|
|
9702
|
+
const geometry = new BufferGeometry2();
|
|
9703
|
+
geometry.setAttribute("position", new Float32BufferAttribute4(positions, 3));
|
|
9704
|
+
geometry.setAttribute("normal", new Float32BufferAttribute4(normals, 3));
|
|
9705
|
+
geometry.setAttribute("uv", new Float32BufferAttribute4(uvs, 2));
|
|
9706
|
+
geometry.setAttribute("color", new Float32BufferAttribute4(colors, 3));
|
|
9707
|
+
geometry.setIndex(indices);
|
|
9708
|
+
geometry.computeBoundingBox();
|
|
9709
|
+
geometry.computeBoundingSphere();
|
|
9710
|
+
const material = Materials.createShadedCanvasMaterial(canvas, false);
|
|
9711
|
+
material.vertexColors = true;
|
|
9712
|
+
const texture = material.uniforms?.map?.value ?? material.map;
|
|
9713
|
+
const mesh = new Mesh7(geometry, material);
|
|
9714
|
+
section.add(mesh);
|
|
9715
|
+
section.ownedMeshes.push({ mesh, texture });
|
|
9716
|
+
}
|
|
9717
|
+
return section;
|
|
9718
|
+
}
|
|
9719
|
+
dispose() {
|
|
9720
|
+
for (const { mesh, texture } of this.ownedMeshes.splice(0)) {
|
|
9721
|
+
mesh.removeFromParent();
|
|
9722
|
+
mesh.geometry.dispose();
|
|
9723
|
+
mesh.material.dispose();
|
|
9724
|
+
texture?.dispose();
|
|
9725
|
+
}
|
|
9726
|
+
this.removeFromParent();
|
|
9727
|
+
}
|
|
9728
|
+
};
|
|
9729
|
+
|
|
9540
9730
|
// src/world/Chunk.ts
|
|
9541
9731
|
var Chunk = class _Chunk {
|
|
9542
|
-
constructor(scene, x, y, z, onBlocksChanged) {
|
|
9732
|
+
constructor(scene, x, y, z, onBlocksChanged, sectionModels) {
|
|
9543
9733
|
this.onBlocksChanged = onBlocksChanged;
|
|
9734
|
+
this.sectionModels = sectionModels;
|
|
9544
9735
|
this.data = new ChunkData();
|
|
9545
9736
|
this.renderedBlocks = /* @__PURE__ */ new Map();
|
|
9737
|
+
this.sectionBlocks = /* @__PURE__ */ new Map();
|
|
9738
|
+
this.meshDirty = false;
|
|
9546
9739
|
this.scene = scene;
|
|
9547
9740
|
this.x = x;
|
|
9548
9741
|
this.y = y;
|
|
@@ -9550,10 +9743,10 @@ var Chunk = class _Chunk {
|
|
|
9550
9743
|
}
|
|
9551
9744
|
getBlockAt(posOrX, y, z) {
|
|
9552
9745
|
if (typeof posOrX == "number") {
|
|
9553
|
-
return this.getBlockAt(new
|
|
9746
|
+
return this.getBlockAt(new Vector313(posOrX, y, z));
|
|
9554
9747
|
}
|
|
9555
9748
|
if (isTripleArray(posOrX)) {
|
|
9556
|
-
return this.getBlockAt(new
|
|
9749
|
+
return this.getBlockAt(new Vector313(posOrX[0], posOrX[1], posOrX[2]));
|
|
9557
9750
|
}
|
|
9558
9751
|
const pos = this.worldPosToChunkPos(posOrX);
|
|
9559
9752
|
const index = _Chunk.chunkPosToBlockIndex(pos);
|
|
@@ -9561,10 +9754,10 @@ var Chunk = class _Chunk {
|
|
|
9561
9754
|
}
|
|
9562
9755
|
async setBlockAt(posOrX, yOrBlock, z, block) {
|
|
9563
9756
|
if (typeof posOrX == "number") {
|
|
9564
|
-
return this.setBlockAt(new
|
|
9757
|
+
return this.setBlockAt(new Vector313(posOrX, yOrBlock, z), block);
|
|
9565
9758
|
}
|
|
9566
9759
|
if (isTripleArray(posOrX)) {
|
|
9567
|
-
return this.setBlockAt(new
|
|
9760
|
+
return this.setBlockAt(new Vector313(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
|
|
9568
9761
|
}
|
|
9569
9762
|
const worldPos = posOrX;
|
|
9570
9763
|
const pos = this.worldPosToChunkPos(worldPos);
|
|
@@ -9581,7 +9774,8 @@ var Chunk = class _Chunk {
|
|
|
9581
9774
|
const index = _Chunk.chunkPosToBlockIndex(pos);
|
|
9582
9775
|
this.data.set(index, block);
|
|
9583
9776
|
const readBlock = this.data.snapshot(index);
|
|
9584
|
-
this.renderedBlocks.get(index)?.object
|
|
9777
|
+
this.renderedBlocks.get(index)?.object?.removeFromScene();
|
|
9778
|
+
if (this.sectionBlocks.delete(index)) this.meshDirty = true;
|
|
9585
9779
|
this.renderedBlocks.delete(index);
|
|
9586
9780
|
let object;
|
|
9587
9781
|
try {
|
|
@@ -9592,13 +9786,19 @@ var Chunk = class _Chunk {
|
|
|
9592
9786
|
this.data.set(index, void 0);
|
|
9593
9787
|
return void 0;
|
|
9594
9788
|
}
|
|
9595
|
-
|
|
9596
|
-
|
|
9597
|
-
|
|
9598
|
-
|
|
9599
|
-
|
|
9600
|
-
|
|
9601
|
-
|
|
9789
|
+
const template = await this.sectionModels?.get(blockState, stored.properties);
|
|
9790
|
+
if (template) {
|
|
9791
|
+
this.sectionBlocks.set(index, { index, template, cullMask: 0 });
|
|
9792
|
+
this.meshDirty = true;
|
|
9793
|
+
} else {
|
|
9794
|
+
object = await this.scene.addBlock(blockState, {
|
|
9795
|
+
mergeMeshes: true,
|
|
9796
|
+
instanceMeshes: true,
|
|
9797
|
+
maxInstanceCount: 2e3,
|
|
9798
|
+
initialState: stored.properties
|
|
9799
|
+
});
|
|
9800
|
+
object.setPosition(MineRenderWorld.worldToScenePosition(worldPos));
|
|
9801
|
+
}
|
|
9602
9802
|
const info = { get block() {
|
|
9603
9803
|
return readBlock();
|
|
9604
9804
|
}, object };
|
|
@@ -9612,11 +9812,43 @@ var Chunk = class _Chunk {
|
|
|
9612
9812
|
await onBlocksChanged?.([worldPos]);
|
|
9613
9813
|
}
|
|
9614
9814
|
}
|
|
9815
|
+
isOccludingAt(pos) {
|
|
9816
|
+
const index = _Chunk.chunkPosToBlockIndex(this.worldPosToChunkPos(pos));
|
|
9817
|
+
return this.sectionBlocks.has(index) || (this.renderedBlocks.get(index)?.object?.isOccluding ?? false);
|
|
9818
|
+
}
|
|
9819
|
+
async setCullMaskAt(pos, mask) {
|
|
9820
|
+
const index = _Chunk.chunkPosToBlockIndex(this.worldPosToChunkPos(pos));
|
|
9821
|
+
const entry = this.sectionBlocks.get(index);
|
|
9822
|
+
if (entry) {
|
|
9823
|
+
if (entry.cullMask !== mask) {
|
|
9824
|
+
entry.cullMask = mask;
|
|
9825
|
+
this.meshDirty = true;
|
|
9826
|
+
}
|
|
9827
|
+
} else {
|
|
9828
|
+
await this.renderedBlocks.get(index)?.object?.setCullMask(mask);
|
|
9829
|
+
}
|
|
9830
|
+
}
|
|
9831
|
+
rebuildSectionMesh() {
|
|
9832
|
+
if (!this.meshDirty) return;
|
|
9833
|
+
const next = this.sectionBlocks.size ? SectionMesh.build([...this.sectionBlocks.values()], this.sectionModels.maxAtlasSize) : void 0;
|
|
9834
|
+
this.sectionMesh?.dispose();
|
|
9835
|
+
this.sectionMesh = next;
|
|
9836
|
+
if (next) {
|
|
9837
|
+
next.position.set(this.x * 256, this.y * 256, this.z * 256);
|
|
9838
|
+
this.scene.add(next);
|
|
9839
|
+
}
|
|
9840
|
+
this.scene.dirty = true;
|
|
9841
|
+
this.meshDirty = false;
|
|
9842
|
+
}
|
|
9615
9843
|
async clear(onBlocksChanged = this.onBlocksChanged) {
|
|
9616
9844
|
const positions = [...this.renderedBlocks.keys()].map((index) => this.chunkPosToWorldPos(
|
|
9617
|
-
new
|
|
9845
|
+
new Vector313(index % 16, Math.floor(index / 256), Math.floor(index / 16) % 16)
|
|
9618
9846
|
));
|
|
9619
|
-
for (const info of this.renderedBlocks.values()) info.object
|
|
9847
|
+
for (const info of this.renderedBlocks.values()) info.object?.removeFromScene();
|
|
9848
|
+
this.sectionBlocks.clear();
|
|
9849
|
+
this.sectionMesh?.dispose();
|
|
9850
|
+
this.sectionMesh = void 0;
|
|
9851
|
+
this.meshDirty = false;
|
|
9620
9852
|
this.renderedBlocks.clear();
|
|
9621
9853
|
this.data.clear();
|
|
9622
9854
|
await onBlocksChanged?.(positions);
|
|
@@ -9634,14 +9866,14 @@ var Chunk = class _Chunk {
|
|
|
9634
9866
|
return pos.y * 16 * 16 + pos.z * 16 + pos.x;
|
|
9635
9867
|
}
|
|
9636
9868
|
worldPosToChunkPos(pos) {
|
|
9637
|
-
return new
|
|
9869
|
+
return new Vector313(
|
|
9638
9870
|
pos.x - this.x * 16,
|
|
9639
9871
|
pos.y - this.y * 16,
|
|
9640
9872
|
pos.z - this.z * 16
|
|
9641
9873
|
);
|
|
9642
9874
|
}
|
|
9643
9875
|
chunkPosToWorldPos(pos) {
|
|
9644
|
-
return new
|
|
9876
|
+
return new Vector313(
|
|
9645
9877
|
this.x * 16 + pos.x,
|
|
9646
9878
|
this.y * 16 + pos.y,
|
|
9647
9879
|
this.z * 16 + pos.z
|
|
@@ -9664,6 +9896,7 @@ export {
|
|
|
9664
9896
|
BasicAssetKey,
|
|
9665
9897
|
BatchedExecutor,
|
|
9666
9898
|
BlockObject,
|
|
9899
|
+
BlockStateResolver,
|
|
9667
9900
|
BlockStates,
|
|
9668
9901
|
BlockTints,
|
|
9669
9902
|
BrowserArchiveProxy,
|
|
@@ -9722,6 +9955,8 @@ export {
|
|
|
9722
9955
|
SceneStats,
|
|
9723
9956
|
SceneStatsDisplay,
|
|
9724
9957
|
SchematicParser,
|
|
9958
|
+
SectionMesh,
|
|
9959
|
+
SectionModels,
|
|
9725
9960
|
SkinImage,
|
|
9726
9961
|
SkinObject,
|
|
9727
9962
|
SkinPart,
|