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/node/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
|
};
|
|
@@ -770,11 +770,11 @@ var ImageLoader = class _ImageLoader {
|
|
|
770
770
|
static async loadCanvasData(src) {
|
|
771
771
|
const keyStr = serializeImageKey({ src });
|
|
772
772
|
const info = this.getInfo(src);
|
|
773
|
-
const
|
|
773
|
+
const cached2 = Caching.rawImageCache.getIfPresent(keyStr);
|
|
774
774
|
try {
|
|
775
775
|
return await this.infoToCanvasData(await info);
|
|
776
776
|
} catch (err) {
|
|
777
|
-
if (
|
|
777
|
+
if (cached2 && Caching.rawImageCache.getIfPresent(keyStr) === cached2) {
|
|
778
778
|
Caching.rawImageCache.invalidate(keyStr);
|
|
779
779
|
}
|
|
780
780
|
throw err;
|
|
@@ -911,8 +911,8 @@ var Textures = class _Textures {
|
|
|
911
911
|
}
|
|
912
912
|
static getImage(key) {
|
|
913
913
|
const keyStr = serializeTextureKey(key);
|
|
914
|
-
const
|
|
915
|
-
if (
|
|
914
|
+
const cached2 = Caching.textureCache.peek(keyStr);
|
|
915
|
+
if (cached2 && TextureLoader.hasFailed(cached2)) {
|
|
916
916
|
Caching.textureCache.invalidate(keyStr);
|
|
917
917
|
}
|
|
918
918
|
return Caching.textureCache.get(keyStr, (k) => {
|
|
@@ -1180,12 +1180,12 @@ var AssetKey = class _AssetKey extends BasicAssetKey {
|
|
|
1180
1180
|
return a.join("/");
|
|
1181
1181
|
}
|
|
1182
1182
|
getFullPath() {
|
|
1183
|
-
let
|
|
1183
|
+
let p10 = [];
|
|
1184
1184
|
if (this.type) {
|
|
1185
|
-
|
|
1185
|
+
p10.push(this.type);
|
|
1186
1186
|
}
|
|
1187
|
-
|
|
1188
|
-
return
|
|
1187
|
+
p10.push(this.path);
|
|
1188
|
+
return p10.join("/");
|
|
1189
1189
|
}
|
|
1190
1190
|
toNamespacedString() {
|
|
1191
1191
|
return this.namespace + ":" + this.getFullPath();
|
|
@@ -1272,7 +1272,7 @@ var ModelMerger = class {
|
|
|
1272
1272
|
merged.display = { ...inheritedDisplay, ...DisplayTransforms.withHandFallbacks(source.display) };
|
|
1273
1273
|
}
|
|
1274
1274
|
}
|
|
1275
|
-
merged.hierarchy = models.map((m) => m.parent).filter((
|
|
1275
|
+
merged.hierarchy = models.map((m) => m.parent).filter((p10) => `${p10}`);
|
|
1276
1276
|
merged.hierarchy.push(`${merged.parent}`);
|
|
1277
1277
|
return merged;
|
|
1278
1278
|
}
|
|
@@ -2001,7 +2001,7 @@ var ModelTextures = class {
|
|
|
2001
2001
|
static async get(key) {
|
|
2002
2002
|
const keyStr = key.serialize();
|
|
2003
2003
|
const pending = this.preload(key);
|
|
2004
|
-
const
|
|
2004
|
+
const cached2 = Caching.textureAssetCache.getIfPresent(keyStr);
|
|
2005
2005
|
try {
|
|
2006
2006
|
const asset = await pending;
|
|
2007
2007
|
if (asset) {
|
|
@@ -2009,7 +2009,7 @@ var ModelTextures = class {
|
|
|
2009
2009
|
}
|
|
2010
2010
|
return void 0;
|
|
2011
2011
|
} catch (err) {
|
|
2012
|
-
if (
|
|
2012
|
+
if (cached2 && Caching.textureAssetCache.getIfPresent(keyStr) === cached2) {
|
|
2013
2013
|
Caching.textureAssetCache.invalidate(keyStr);
|
|
2014
2014
|
}
|
|
2015
2015
|
throw err;
|
|
@@ -3100,6 +3100,10 @@ var SceneObject = class _SceneObject extends Object3D2 {
|
|
|
3100
3100
|
this.setMatrixAt(index, new Matrix43());
|
|
3101
3101
|
return reference;
|
|
3102
3102
|
}
|
|
3103
|
+
/** Returns the live reference for a raycast hit on this object's instance mesh. */
|
|
3104
|
+
getInstanceReference(mesh, index) {
|
|
3105
|
+
return mesh === this.instanceMesh ? this.instanceReferences.get(index) : void 0;
|
|
3106
|
+
}
|
|
3103
3107
|
isInstanceActive(index, reference) {
|
|
3104
3108
|
return this.instanceReferences.get(index) === reference;
|
|
3105
3109
|
}
|
|
@@ -3182,9 +3186,9 @@ var SceneObject = class _SceneObject extends Object3D2 {
|
|
|
3182
3186
|
}
|
|
3183
3187
|
getRotationAt(index, euler = new Euler3()) {
|
|
3184
3188
|
if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
|
|
3185
|
-
const
|
|
3186
|
-
|
|
3187
|
-
return euler;
|
|
3189
|
+
const rotation = new Quaternion3();
|
|
3190
|
+
this.getMatrixAt(index).decompose(new Vector35(), rotation, new Vector35());
|
|
3191
|
+
return euler.setFromQuaternion(rotation);
|
|
3188
3192
|
}
|
|
3189
3193
|
setScaleAt(index, scale) {
|
|
3190
3194
|
if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
|
|
@@ -3434,11 +3438,12 @@ var GuiObject = class extends SceneObject {
|
|
|
3434
3438
|
// src/inspector/SceneInspector.ts
|
|
3435
3439
|
import { Raycaster, Vector2 as Vector22 } from "three";
|
|
3436
3440
|
var p7 = prefix("SceneInspector");
|
|
3437
|
-
var help = "<span>Ctrl+Click to Select<br/></span><br/>";
|
|
3441
|
+
var help = "<span>Ctrl/Cmd+Click to Select<br/></span><br/>";
|
|
3438
3442
|
var SceneInspector = class {
|
|
3439
3443
|
constructor(renderer) {
|
|
3440
3444
|
this.renderer = renderer;
|
|
3441
3445
|
this.mouse = new Vector22();
|
|
3446
|
+
this.listeners = new AbortController();
|
|
3442
3447
|
this.objectInfoContainer = document.createElement("div");
|
|
3443
3448
|
this.objectControlsContainer = document.createElement("div");
|
|
3444
3449
|
this.raycaster = new Raycaster();
|
|
@@ -3448,13 +3453,44 @@ var SceneInspector = class {
|
|
|
3448
3453
|
this.objectInfoContainer.classList.add("minerender-inspector", "minerender-object-info");
|
|
3449
3454
|
this.objectControlsContainer.classList.add("minerender-inspector", "minerender-object-controls");
|
|
3450
3455
|
this.objectInfoContainer.innerHTML = help;
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3456
|
+
const canvas = this.renderer.renderer.domElement;
|
|
3457
|
+
const options = { signal: this.listeners.signal };
|
|
3458
|
+
canvas.addEventListener("pointerdown", (event) => {
|
|
3459
|
+
this.pointer = event.button === 0 && (event.ctrlKey || event.metaKey) ? event : void 0;
|
|
3460
|
+
}, options);
|
|
3461
|
+
canvas.addEventListener("pointermove", (event) => {
|
|
3462
|
+
if (this.pointer?.pointerId === event.pointerId && Math.hypot(event.clientX - this.pointer.clientX, event.clientY - this.pointer.clientY) > 5) {
|
|
3463
|
+
this.pointer = void 0;
|
|
3464
|
+
}
|
|
3465
|
+
}, options);
|
|
3466
|
+
canvas.addEventListener("pointerup", (event) => {
|
|
3467
|
+
const start = this.pointer;
|
|
3468
|
+
this.pointer = void 0;
|
|
3469
|
+
if (start?.pointerId === event.pointerId && Math.hypot(event.clientX - start.clientX, event.clientY - start.clientY) <= 5) {
|
|
3470
|
+
this.onClick(event);
|
|
3471
|
+
}
|
|
3472
|
+
}, options);
|
|
3473
|
+
canvas.addEventListener("pointercancel", () => {
|
|
3474
|
+
this.pointer = void 0;
|
|
3475
|
+
}, options);
|
|
3476
|
+
canvas.addEventListener("pointerleave", () => {
|
|
3477
|
+
this.pointer = void 0;
|
|
3478
|
+
}, options);
|
|
3479
|
+
canvas.addEventListener("contextmenu", (event) => {
|
|
3480
|
+
if (this.pointer?.ctrlKey) event.preventDefault();
|
|
3481
|
+
}, options);
|
|
3482
|
+
}
|
|
3483
|
+
dispose() {
|
|
3484
|
+
this.listeners.abort();
|
|
3485
|
+
this.pointer = void 0;
|
|
3486
|
+
this.selectedObject = void 0;
|
|
3487
|
+
this.objectInfoContainer.remove();
|
|
3488
|
+
this.objectControlsContainer.remove();
|
|
3454
3489
|
}
|
|
3455
3490
|
findMeshChildren(from, out = []) {
|
|
3491
|
+
if (!from.visible) return out;
|
|
3456
3492
|
for (let c of from.children) {
|
|
3457
|
-
if (isMesh(c)) {
|
|
3493
|
+
if (c.visible && isMesh(c)) {
|
|
3458
3494
|
out.push(c);
|
|
3459
3495
|
}
|
|
3460
3496
|
this.findMeshChildren(c, out);
|
|
@@ -3462,50 +3498,43 @@ var SceneInspector = class {
|
|
|
3462
3498
|
return out;
|
|
3463
3499
|
}
|
|
3464
3500
|
onClick(event) {
|
|
3465
|
-
|
|
3466
|
-
if (!event.ctrlKey) return;
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
|
|
3470
|
-
|
|
3471
|
-
|
|
3472
|
-
|
|
3473
|
-
|
|
3474
|
-
|
|
3475
|
-
if (intersects.length > 0) {
|
|
3476
|
-
this.handleRaycasterObjects(intersects);
|
|
3477
|
-
}
|
|
3478
|
-
});
|
|
3501
|
+
const canvas = this.renderer.renderer.domElement;
|
|
3502
|
+
if (event.target !== canvas || event.button !== 0 || !(event.ctrlKey || event.metaKey)) return;
|
|
3503
|
+
const rect = canvas.getBoundingClientRect();
|
|
3504
|
+
const x = event.clientX - rect.left, y = event.clientY - rect.top;
|
|
3505
|
+
if (rect.width <= 0 || rect.height <= 0 || x < 0 || y < 0 || x >= rect.width || y >= rect.height) return;
|
|
3506
|
+
this.mouse.set(x / rect.width * 2 - 1, 1 - y / rect.height * 2);
|
|
3507
|
+
this.renderer.camera.updateWorldMatrix(true, false);
|
|
3508
|
+
this.renderer.scene.updateMatrixWorld(true);
|
|
3509
|
+
this.raycaster.setFromCamera(this.mouse, this.renderer.camera);
|
|
3510
|
+
this.handleRaycasterObjects(this.raycaster.intersectObjects(this.findMeshChildren(this.renderer.scene), false));
|
|
3479
3511
|
}
|
|
3480
3512
|
appendTo(el) {
|
|
3481
3513
|
el.append(this.objectInfoContainer);
|
|
3482
3514
|
el.append(this.objectControlsContainer);
|
|
3483
3515
|
}
|
|
3484
3516
|
handleRaycasterObjects(intersections) {
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
|
|
3495
|
-
|
|
3496
|
-
targetIntersection = firstIntersection;
|
|
3497
|
-
targetObject = firstObject;
|
|
3517
|
+
const hit = intersections[0];
|
|
3518
|
+
if (!hit) return;
|
|
3519
|
+
const instance = this.getIntersectionInstance(hit);
|
|
3520
|
+
this.selectObject(instance?.instanceable ?? hit.object, hit, instance);
|
|
3521
|
+
}
|
|
3522
|
+
getIntersectionInstance(hit) {
|
|
3523
|
+
if (hit?.instanceId === void 0) return void 0;
|
|
3524
|
+
for (let parent = hit.object.parent; parent; parent = parent.parent) {
|
|
3525
|
+
if (isSceneObject(parent)) {
|
|
3526
|
+
const instance = parent.getInstanceReference(hit.object, hit.instanceId);
|
|
3527
|
+
if (instance) return instance;
|
|
3498
3528
|
}
|
|
3499
|
-
if (!targetIntersection || !targetObject) return;
|
|
3500
|
-
this.selectObject(targetObject, targetIntersection);
|
|
3501
3529
|
}
|
|
3530
|
+
return void 0;
|
|
3502
3531
|
}
|
|
3503
|
-
selectObject(targetObject, targetIntersection) {
|
|
3532
|
+
selectObject(targetObject, targetIntersection, instance = this.getIntersectionInstance(targetIntersection)) {
|
|
3504
3533
|
this.selectedObject = targetObject;
|
|
3505
3534
|
console.log(p7, "selected", targetObject);
|
|
3506
|
-
this.redraw(targetObject, targetIntersection);
|
|
3535
|
+
this.redraw(targetObject, targetIntersection, instance);
|
|
3507
3536
|
}
|
|
3508
|
-
redraw(targetObject, targetIntersection) {
|
|
3537
|
+
redraw(targetObject, targetIntersection, instance) {
|
|
3509
3538
|
this.objectInfoContainer.innerHTML = help;
|
|
3510
3539
|
if (targetIntersection) {
|
|
3511
3540
|
this.addInfoLine("Distance", "D", targetIntersection.distance);
|
|
@@ -3518,8 +3547,8 @@ var SceneInspector = class {
|
|
|
3518
3547
|
if (isSceneObject(targetObject.parent)) {
|
|
3519
3548
|
}
|
|
3520
3549
|
}
|
|
3521
|
-
|
|
3522
|
-
|
|
3550
|
+
const atlas = "atlas" in targetObject ? targetObject["atlas"] : void 0;
|
|
3551
|
+
if (atlas?.image.canvas) {
|
|
3523
3552
|
const img = atlas.image.canvas;
|
|
3524
3553
|
img.style.width = "100px";
|
|
3525
3554
|
img.style.height = "100px";
|
|
@@ -3528,28 +3557,31 @@ var SceneInspector = class {
|
|
|
3528
3557
|
this.objectInfoContainer.prepend(img);
|
|
3529
3558
|
}
|
|
3530
3559
|
this.objectControlsContainer.innerHTML = "";
|
|
3531
|
-
this.addControls(targetObject, targetIntersection);
|
|
3560
|
+
this.addControls(targetObject, targetIntersection, instance);
|
|
3532
3561
|
}
|
|
3533
|
-
addControls(object, intersection) {
|
|
3562
|
+
addControls(object, intersection, instance) {
|
|
3534
3563
|
const container = document.createElement("div");
|
|
3535
3564
|
container.append(this.separator("Select Parent/Child"));
|
|
3536
3565
|
if (object.parent) {
|
|
3537
3566
|
container.append(this.buttonControl("Select Parent " + object.parent.constructor.name + " " + object.parent.name, "P", () => {
|
|
3538
|
-
this.selectObject(object.parent, intersection);
|
|
3567
|
+
this.selectObject(object.parent, intersection, instance);
|
|
3539
3568
|
}));
|
|
3540
3569
|
}
|
|
3541
3570
|
if (object.children.length > 0) {
|
|
3542
3571
|
let i = 1;
|
|
3543
3572
|
for (let child of object.children) {
|
|
3544
3573
|
container.append(this.buttonControl("Select Child " + child.constructor.name + " " + child.name, "C" + i++, () => {
|
|
3545
|
-
this.selectObject(child, intersection);
|
|
3574
|
+
this.selectObject(child, intersection, instance);
|
|
3546
3575
|
}));
|
|
3547
3576
|
}
|
|
3548
3577
|
}
|
|
3549
3578
|
container.append(this.separator());
|
|
3550
|
-
|
|
3579
|
+
const selectedInstance = instance && (object === instance.instanceable || object === intersection?.object) ? instance : void 0;
|
|
3580
|
+
if (!selectedInstance) {
|
|
3581
|
+
container.append(this.toggleControl("Visibility", "V", object.visible, (v) => object.visible = v));
|
|
3582
|
+
}
|
|
3551
3583
|
container.append(this.separator("Mesh"));
|
|
3552
|
-
this.addObjectControls(object, intersection, container);
|
|
3584
|
+
this.addObjectControls(object, intersection, container, selectedInstance);
|
|
3553
3585
|
container.append(this.separator());
|
|
3554
3586
|
this.objectControlsContainer.append(container);
|
|
3555
3587
|
}
|
|
@@ -3561,78 +3593,26 @@ var SceneInspector = class {
|
|
|
3561
3593
|
this.objectInfoContainer.append(document.createElement("br"));
|
|
3562
3594
|
return el;
|
|
3563
3595
|
}
|
|
3564
|
-
addObjectControls(target, intersection, container) {
|
|
3596
|
+
addObjectControls(target, intersection, container, instance) {
|
|
3565
3597
|
const posRange = 16 * 16;
|
|
3566
3598
|
const rotRange = 360;
|
|
3567
3599
|
const scaleRange = 4;
|
|
3568
|
-
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
let pos = scObj.getPositionAt(intersection.instanceId);
|
|
3572
|
-
container.append(this.rangeControl("X Position", "X", -posRange + pos.x, posRange + pos.x, pos.x, 1, (v) => {
|
|
3573
|
-
pos = scObj.getPositionAt(intersection.instanceId);
|
|
3574
|
-
pos.x = v;
|
|
3575
|
-
scObj.setPositionAt(intersection.instanceId, pos);
|
|
3576
|
-
}));
|
|
3577
|
-
container.append(this.rangeControl("Y Position", "Y", -posRange + pos.y, posRange + pos.y, pos.y, 1, (v) => {
|
|
3578
|
-
pos = scObj.getPositionAt(intersection.instanceId);
|
|
3579
|
-
pos.y = v;
|
|
3580
|
-
scObj.setPositionAt(intersection.instanceId, pos);
|
|
3581
|
-
}));
|
|
3582
|
-
container.append(this.rangeControl("Z Position", "Z", -posRange + pos.z, posRange + pos.z, pos.z, 1, (v) => {
|
|
3583
|
-
pos = scObj.getPositionAt(intersection.instanceId);
|
|
3584
|
-
pos.z = v;
|
|
3585
|
-
scObj.setPositionAt(intersection.instanceId, pos);
|
|
3586
|
-
}));
|
|
3587
|
-
container.append(this.separator("Rotation"));
|
|
3588
|
-
let rot = scObj.getRotationAt(intersection.instanceId);
|
|
3589
|
-
container.append(this.rangeControl("X Rotation", "X", 0, rotRange, Math.round(toDegrees(rot.x)), 1, (v) => {
|
|
3590
|
-
rot = scObj.getRotationAt(intersection.instanceId);
|
|
3591
|
-
rot.x = toRadians(v);
|
|
3592
|
-
scObj.setRotationAt(intersection.instanceId, rot);
|
|
3593
|
-
}));
|
|
3594
|
-
container.append(this.rangeControl("Y Rotation", "Y", 0, rotRange, Math.round(toDegrees(rot.y)), 1, (v) => {
|
|
3595
|
-
rot = scObj.getRotationAt(intersection.instanceId);
|
|
3596
|
-
rot.y = toRadians(v);
|
|
3597
|
-
scObj.setRotationAt(intersection.instanceId, rot);
|
|
3598
|
-
}));
|
|
3599
|
-
container.append(this.rangeControl("Z Rotation", "Z", 0, rotRange, Math.round(toDegrees(rot.z)), 1, (v) => {
|
|
3600
|
-
rot = scObj.getRotationAt(intersection.instanceId);
|
|
3601
|
-
rot.z = toRadians(v);
|
|
3602
|
-
scObj.setRotationAt(intersection.instanceId, rot);
|
|
3603
|
-
}));
|
|
3604
|
-
container.append(this.separator("Scale"));
|
|
3605
|
-
let scl = scObj.getScale();
|
|
3606
|
-
container.append(this.rangeControl("X Scale", "X", 0, scaleRange, scl.x, 0.1, (v) => {
|
|
3607
|
-
scl = scObj.getScaleAt(intersection.instanceId);
|
|
3608
|
-
scl.x = v;
|
|
3609
|
-
scObj.setScaleAt(intersection.instanceId, scl);
|
|
3610
|
-
}));
|
|
3611
|
-
container.append(this.rangeControl("Y Scale", "Y", 0, scaleRange, scl.y, 0.1, (v) => {
|
|
3612
|
-
scl = scObj.getScaleAt(intersection.instanceId);
|
|
3613
|
-
scl.y = v;
|
|
3614
|
-
scObj.setScaleAt(intersection.instanceId, scl);
|
|
3615
|
-
}));
|
|
3616
|
-
container.append(this.rangeControl("Z Scale", "Z", 0, scaleRange, scl.z, 0.1, (v) => {
|
|
3617
|
-
scl = scObj.getScaleAt(intersection.instanceId);
|
|
3618
|
-
scl.z = v;
|
|
3619
|
-
scObj.setScaleAt(intersection.instanceId, scl);
|
|
3620
|
-
}));
|
|
3621
|
-
} else if (isTransformable(target)) {
|
|
3622
|
-
const parent = target;
|
|
3600
|
+
const transform = instance ?? (isTransformable(target) ? target : void 0);
|
|
3601
|
+
if (transform) {
|
|
3602
|
+
const parent = transform;
|
|
3623
3603
|
container.append(this.separator("Position"));
|
|
3624
3604
|
let pos = parent.getPosition();
|
|
3625
|
-
container.append(this.rangeControl("X Position", "X", -posRange, posRange, pos.x, 1, (v) => {
|
|
3605
|
+
container.append(this.rangeControl("X Position", "X", pos.x - posRange, pos.x + posRange, pos.x, 1, (v) => {
|
|
3626
3606
|
pos = parent.getPosition();
|
|
3627
3607
|
pos.x = v;
|
|
3628
3608
|
parent.setPosition(pos);
|
|
3629
3609
|
}));
|
|
3630
|
-
container.append(this.rangeControl("Y Position", "Y", -posRange, posRange, pos.y, 1, (v) => {
|
|
3610
|
+
container.append(this.rangeControl("Y Position", "Y", pos.y - posRange, pos.y + posRange, pos.y, 1, (v) => {
|
|
3631
3611
|
pos = parent.getPosition();
|
|
3632
3612
|
pos.y = v;
|
|
3633
3613
|
parent.setPosition(pos);
|
|
3634
3614
|
}));
|
|
3635
|
-
container.append(this.rangeControl("Z Position", "Z", -posRange, posRange, pos.z, 1, (v) => {
|
|
3615
|
+
container.append(this.rangeControl("Z Position", "Z", pos.z - posRange, pos.z + posRange, pos.z, 1, (v) => {
|
|
3636
3616
|
pos = parent.getPosition();
|
|
3637
3617
|
pos.z = v;
|
|
3638
3618
|
parent.setPosition(pos);
|
|
@@ -3721,6 +3701,7 @@ var SceneInspector = class {
|
|
|
3721
3701
|
toggle.checked = val;
|
|
3722
3702
|
toggle.addEventListener("change", (e) => {
|
|
3723
3703
|
change(toggle.checked);
|
|
3704
|
+
this.renderer.scene.dirty = true;
|
|
3724
3705
|
});
|
|
3725
3706
|
label.append(toggle);
|
|
3726
3707
|
label.append(document.createElement("br"));
|
|
@@ -3733,7 +3714,6 @@ var SceneInspector = class {
|
|
|
3733
3714
|
label.setAttribute("title", name);
|
|
3734
3715
|
labelText.style.width = "18%";
|
|
3735
3716
|
labelText.style.display = "inline-block";
|
|
3736
|
-
labelText.innerText = `${id} (${val})`;
|
|
3737
3717
|
const range = document.createElement("input");
|
|
3738
3718
|
range.setAttribute("type", "range");
|
|
3739
3719
|
range.style.width = "80%";
|
|
@@ -3741,8 +3721,10 @@ var SceneInspector = class {
|
|
|
3741
3721
|
range.min = `${min}`;
|
|
3742
3722
|
range.step = `${step}`;
|
|
3743
3723
|
range.value = `${val}`;
|
|
3724
|
+
labelText.innerText = `${id} (${range.value})`;
|
|
3744
3725
|
const onChange = () => {
|
|
3745
3726
|
change(parseFloat(range.value));
|
|
3727
|
+
this.renderer.scene.dirty = true;
|
|
3746
3728
|
labelText.innerText = `${id} (${range.value})`;
|
|
3747
3729
|
};
|
|
3748
3730
|
range.addEventListener("input", onChange);
|
|
@@ -3902,6 +3884,93 @@ var ModelCulling = class {
|
|
|
3902
3884
|
}
|
|
3903
3885
|
};
|
|
3904
3886
|
|
|
3887
|
+
// src/model/block/BlockStateResolver.ts
|
|
3888
|
+
import { Euler as Euler5 } from "three";
|
|
3889
|
+
function matchesCondition(condition, state) {
|
|
3890
|
+
return Object.entries(condition).every(([key, value]) => {
|
|
3891
|
+
if (Array.isArray(value)) {
|
|
3892
|
+
if (key === "OR") return value.some((child) => matchesCondition(child, state));
|
|
3893
|
+
if (key === "AND") return value.every((child) => matchesCondition(child, state));
|
|
3894
|
+
return false;
|
|
3895
|
+
}
|
|
3896
|
+
return typeof value === "string" && state[key] !== void 0 && value.split("|").includes(`${state[key]}`);
|
|
3897
|
+
});
|
|
3898
|
+
}
|
|
3899
|
+
var BlockStateResolver = class {
|
|
3900
|
+
static async defaults(blockState) {
|
|
3901
|
+
const defaults = blockState.key ? await BlockStates.getDefaultState(blockState.key) : void 0;
|
|
3902
|
+
const state = {};
|
|
3903
|
+
if (defaults && Object.keys(defaults).length > 0) {
|
|
3904
|
+
for (const key in defaults) state[key] = defaults[key].default;
|
|
3905
|
+
} else if (blockState.variants) {
|
|
3906
|
+
const variant = Object.keys(blockState.variants)[0];
|
|
3907
|
+
if (variant) {
|
|
3908
|
+
for (const property of variant.split(",")) {
|
|
3909
|
+
const [key, value] = property.split("=");
|
|
3910
|
+
state[key] = value;
|
|
3911
|
+
}
|
|
3912
|
+
}
|
|
3913
|
+
} else if (blockState.multipart) {
|
|
3914
|
+
const condition = blockState.multipart.map((part) => part.when).find((when) => when !== void 0 && Object.values(when).every((value) => typeof value === "string"));
|
|
3915
|
+
for (const [key, value] of Object.entries(condition ?? {})) state[key] = value.split("|")[0];
|
|
3916
|
+
}
|
|
3917
|
+
return state;
|
|
3918
|
+
}
|
|
3919
|
+
static select(blockState, state, choose = this.choose) {
|
|
3920
|
+
return this.matching(blockState, state).map(choose);
|
|
3921
|
+
}
|
|
3922
|
+
static matching(blockState, state) {
|
|
3923
|
+
const out = [];
|
|
3924
|
+
if (blockState.variants) {
|
|
3925
|
+
if (Object.keys(blockState.variants).length === 1 && "" in blockState.variants) {
|
|
3926
|
+
out.push(blockState.variants[""]);
|
|
3927
|
+
} else {
|
|
3928
|
+
for (const variantKey in blockState.variants) {
|
|
3929
|
+
const matches = variantKey.split(",").every((property) => {
|
|
3930
|
+
const [key, value] = property.split("=");
|
|
3931
|
+
return `${state[key]}` === `${value}`;
|
|
3932
|
+
});
|
|
3933
|
+
if (matches) out.push(blockState.variants[variantKey]);
|
|
3934
|
+
}
|
|
3935
|
+
}
|
|
3936
|
+
} else if (blockState.multipart) {
|
|
3937
|
+
for (const part of blockState.multipart) {
|
|
3938
|
+
if (part.apply && (!part.when || matchesCondition(part.when, state))) {
|
|
3939
|
+
out.push(part.apply);
|
|
3940
|
+
}
|
|
3941
|
+
}
|
|
3942
|
+
}
|
|
3943
|
+
return out;
|
|
3944
|
+
}
|
|
3945
|
+
static choose(variants) {
|
|
3946
|
+
if (!Array.isArray(variants)) return variants;
|
|
3947
|
+
if (!variants.length) throw new MineRenderError("Blockstate variant arrays must not be empty");
|
|
3948
|
+
const total = variants.reduce((sum, variant) => {
|
|
3949
|
+
const weight = variant.weight ?? 1;
|
|
3950
|
+
if (!Number.isInteger(weight) || weight < 1) {
|
|
3951
|
+
throw new MineRenderError(`Invalid blockstate variant weight: ${weight}`);
|
|
3952
|
+
}
|
|
3953
|
+
return sum + weight;
|
|
3954
|
+
}, 0);
|
|
3955
|
+
let choice = Math.random() * total;
|
|
3956
|
+
for (const variant of variants) {
|
|
3957
|
+
choice -= variant.weight ?? 1;
|
|
3958
|
+
if (choice < 0) return variant;
|
|
3959
|
+
}
|
|
3960
|
+
return variants[variants.length - 1];
|
|
3961
|
+
}
|
|
3962
|
+
static rotation(variant) {
|
|
3963
|
+
const rotation = new Euler5();
|
|
3964
|
+
if (typeof variant.x !== "undefined") {
|
|
3965
|
+
rotation.x = toRadians(clampRotationDegrees(variant.x));
|
|
3966
|
+
}
|
|
3967
|
+
if (typeof variant.y !== "undefined") {
|
|
3968
|
+
rotation.y = toRadians(clampRotationDegrees(typeof variant.x !== "undefined" ? variant.y : 360 - variant.y));
|
|
3969
|
+
}
|
|
3970
|
+
return rotation;
|
|
3971
|
+
}
|
|
3972
|
+
};
|
|
3973
|
+
|
|
3905
3974
|
// src/model/block/blockTints.json
|
|
3906
3975
|
var blockTints_default = {
|
|
3907
3976
|
"minecraft:large_fern": { source: "grass" },
|
|
@@ -3988,7 +4057,7 @@ var BlockTints = class {
|
|
|
3988
4057
|
};
|
|
3989
4058
|
|
|
3990
4059
|
// src/model/scene/ModelObject.ts
|
|
3991
|
-
import { BoxGeometry as BoxGeometry5, BufferAttribute as BufferAttribute4, Color as Color3, Euler as
|
|
4060
|
+
import { BoxGeometry as BoxGeometry5, BufferAttribute as BufferAttribute4, Color as Color3, Euler as Euler6, Matrix4 as Matrix44 } from "three";
|
|
3992
4061
|
|
|
3993
4062
|
// src/three/BufferGeometryUtils.js
|
|
3994
4063
|
import {
|
|
@@ -4582,7 +4651,7 @@ var ModelObject = class _ModelObject extends SceneObject {
|
|
|
4582
4651
|
elGeo.clearGroups();
|
|
4583
4652
|
}
|
|
4584
4653
|
if (this.options.uvLockRotation) {
|
|
4585
|
-
UVMapper.lockUvs(elGeo, el.faces, this.atlas, new
|
|
4654
|
+
UVMapper.lockUvs(elGeo, el.faces, this.atlas, new Euler6(...this.options.uvLockRotation));
|
|
4586
4655
|
}
|
|
4587
4656
|
if (this.options.tints) {
|
|
4588
4657
|
const colors = new Float32Array(elGeo.getAttribute("position").count * 3).fill(1);
|
|
@@ -4678,18 +4747,7 @@ function isModelObject(obj) {
|
|
|
4678
4747
|
|
|
4679
4748
|
// src/model/block/scene/BlockObject.ts
|
|
4680
4749
|
var import_ts_deepmerge6 = __toESM(require_dist());
|
|
4681
|
-
import { Euler as
|
|
4682
|
-
var p10 = prefix("BlockObject");
|
|
4683
|
-
function matchesCondition(condition, state) {
|
|
4684
|
-
return Object.entries(condition).every(([key, value]) => {
|
|
4685
|
-
if (Array.isArray(value)) {
|
|
4686
|
-
if (key === "OR") return value.some((child) => matchesCondition(child, state));
|
|
4687
|
-
if (key === "AND") return value.every((child) => matchesCondition(child, state));
|
|
4688
|
-
return false;
|
|
4689
|
-
}
|
|
4690
|
-
return typeof value === "string" && state[key] !== void 0 && value.split("|").includes(`${state[key]}`);
|
|
4691
|
-
});
|
|
4692
|
-
}
|
|
4750
|
+
import { Euler as Euler7, Matrix4 as Matrix45, Quaternion as Quaternion4, Vector3 as Vector38 } from "three";
|
|
4693
4751
|
var BlockObject = class _BlockObject extends SceneObject {
|
|
4694
4752
|
constructor(blockState, options) {
|
|
4695
4753
|
super(options);
|
|
@@ -4713,22 +4771,7 @@ var BlockObject = class _BlockObject extends SceneObject {
|
|
|
4713
4771
|
}
|
|
4714
4772
|
async init() {
|
|
4715
4773
|
if (this.options.applyDefaultState) {
|
|
4716
|
-
|
|
4717
|
-
if (defaultState && Object.keys(defaultState).length > 0) {
|
|
4718
|
-
const state = {};
|
|
4719
|
-
for (let k in defaultState) {
|
|
4720
|
-
state[k] = defaultState[k].default;
|
|
4721
|
-
}
|
|
4722
|
-
this._setState(state);
|
|
4723
|
-
} else {
|
|
4724
|
-
if (this.blockState.variants) {
|
|
4725
|
-
this._setState(Object.keys(this.blockState.variants)[0]);
|
|
4726
|
-
} else if (this.blockState.multipart) {
|
|
4727
|
-
const condition = this.blockState.multipart.map((part) => part.when).find((when) => when !== void 0 && Object.values(when).every((value) => typeof value === "string"));
|
|
4728
|
-
const state = Object.fromEntries(Object.entries(condition ?? {}).map(([key, value]) => [key, value.split("|")[0]]));
|
|
4729
|
-
this._setState(state);
|
|
4730
|
-
}
|
|
4731
|
-
}
|
|
4774
|
+
this._setState(await BlockStateResolver.defaults(this.blockState));
|
|
4732
4775
|
}
|
|
4733
4776
|
if (this.options.initialState !== void 0) this._setState(this.options.initialState);
|
|
4734
4777
|
await this.recreateModels();
|
|
@@ -4771,7 +4814,7 @@ var BlockObject = class _BlockObject extends SceneObject {
|
|
|
4771
4814
|
const scale = new Vector38();
|
|
4772
4815
|
this.getModelMatrix(model).decompose(position, rotation, scale);
|
|
4773
4816
|
if (position.distanceToSquared(this.position) > 1e-10 || scale.distanceToSquared(new Vector38(1, 1, 1)) > 1e-10) return 0;
|
|
4774
|
-
return ModelCulling.toLocalMask(worldMask, new
|
|
4817
|
+
return ModelCulling.toLocalMask(worldMask, new Euler7().setFromQuaternion(rotation));
|
|
4775
4818
|
}
|
|
4776
4819
|
async setCullMask(worldMask) {
|
|
4777
4820
|
worldMask &= 63;
|
|
@@ -4819,39 +4862,7 @@ var BlockObject = class _BlockObject extends SceneObject {
|
|
|
4819
4862
|
return ref;
|
|
4820
4863
|
}
|
|
4821
4864
|
async mapStateToVariant(state) {
|
|
4822
|
-
|
|
4823
|
-
if (this.blockState.variants) {
|
|
4824
|
-
if (Object.keys(this.blockState.variants).length === 1 && "" in this.blockState.variants) {
|
|
4825
|
-
out.push(this.getSingleVariant(this.blockState.variants[""]));
|
|
4826
|
-
} else {
|
|
4827
|
-
for (let variantKey in this.blockState.variants) {
|
|
4828
|
-
const split = variantKey.split(",");
|
|
4829
|
-
let matches = true;
|
|
4830
|
-
for (let s of split) {
|
|
4831
|
-
const [k, v] = s.split("=");
|
|
4832
|
-
if (`${state[k]}` !== `${v}`) {
|
|
4833
|
-
matches = false;
|
|
4834
|
-
break;
|
|
4835
|
-
}
|
|
4836
|
-
}
|
|
4837
|
-
if (matches) {
|
|
4838
|
-
const variants = this.blockState.variants[variantKey];
|
|
4839
|
-
out.push(this.getSingleVariant(variants));
|
|
4840
|
-
}
|
|
4841
|
-
}
|
|
4842
|
-
}
|
|
4843
|
-
} else if (this.blockState.multipart) {
|
|
4844
|
-
for (let part of this.blockState.multipart) {
|
|
4845
|
-
if (!part.apply) {
|
|
4846
|
-
console.debug(p10, "Missing apply for blockState part", part);
|
|
4847
|
-
continue;
|
|
4848
|
-
}
|
|
4849
|
-
if (!part.when || matchesCondition(part.when, state)) {
|
|
4850
|
-
out.push(this.getSingleVariant(part.apply));
|
|
4851
|
-
}
|
|
4852
|
-
}
|
|
4853
|
-
}
|
|
4854
|
-
return out;
|
|
4865
|
+
return BlockStateResolver.select(this.blockState, state, (variants) => this.getSingleVariant(variants));
|
|
4855
4866
|
}
|
|
4856
4867
|
async recreateModels() {
|
|
4857
4868
|
this.clearModels();
|
|
@@ -4862,21 +4873,7 @@ var BlockObject = class _BlockObject extends SceneObject {
|
|
|
4862
4873
|
}
|
|
4863
4874
|
}
|
|
4864
4875
|
getSingleVariant(variants) {
|
|
4865
|
-
|
|
4866
|
-
if (!variants.length) throw new MineRenderError("Blockstate variant arrays must not be empty");
|
|
4867
|
-
const total = variants.reduce((sum, variant) => {
|
|
4868
|
-
const weight = variant.weight ?? 1;
|
|
4869
|
-
if (!Number.isInteger(weight) || weight < 1) {
|
|
4870
|
-
throw new MineRenderError(`Invalid blockstate variant weight: ${weight}`);
|
|
4871
|
-
}
|
|
4872
|
-
return sum + weight;
|
|
4873
|
-
}, 0);
|
|
4874
|
-
let choice = Math.random() * total;
|
|
4875
|
-
for (const variant of variants) {
|
|
4876
|
-
choice -= variant.weight ?? 1;
|
|
4877
|
-
if (choice < 0) return variant;
|
|
4878
|
-
}
|
|
4879
|
-
return variants[variants.length - 1];
|
|
4876
|
+
return BlockStateResolver.choose(variants);
|
|
4880
4877
|
}
|
|
4881
4878
|
// @deprecated
|
|
4882
4879
|
async createAVariant(variants, instanceInfo) {
|
|
@@ -4884,13 +4881,7 @@ var BlockObject = class _BlockObject extends SceneObject {
|
|
|
4884
4881
|
await this.createVariant(variant);
|
|
4885
4882
|
}
|
|
4886
4883
|
async createVariant(variant) {
|
|
4887
|
-
const rotation =
|
|
4888
|
-
if (typeof variant.x !== "undefined") {
|
|
4889
|
-
rotation.x = toRadians(clampRotationDegrees(variant.x));
|
|
4890
|
-
}
|
|
4891
|
-
if (typeof variant.y !== "undefined") {
|
|
4892
|
-
rotation.y = toRadians(clampRotationDegrees(typeof variant.x !== "undefined" ? variant.y : 360 - variant.y));
|
|
4893
|
-
}
|
|
4884
|
+
const rotation = BlockStateResolver.rotation(variant);
|
|
4894
4885
|
const modelKey = AssetKey.parse("models", variant.model);
|
|
4895
4886
|
modelKey.root = this.blockState.key?.root;
|
|
4896
4887
|
const model = await Models.getMerged(modelKey);
|
|
@@ -9393,32 +9384,121 @@ var AnvilParser = class {
|
|
|
9393
9384
|
};
|
|
9394
9385
|
|
|
9395
9386
|
// src/world/Chunk.ts
|
|
9387
|
+
import { Vector3 as Vector313 } from "three";
|
|
9388
|
+
|
|
9389
|
+
// src/world/MineRenderWorld.ts
|
|
9396
9390
|
import { Vector3 as Vector312 } from "three";
|
|
9397
9391
|
|
|
9392
|
+
// src/world/SectionModels.ts
|
|
9393
|
+
import { Matrix4 as Matrix46, Vector3 as Vector311 } from "three";
|
|
9394
|
+
var SectionModel = class extends ModelObject {
|
|
9395
|
+
applyTextures() {
|
|
9396
|
+
}
|
|
9397
|
+
};
|
|
9398
|
+
function cached(map, key, load) {
|
|
9399
|
+
let value = map.get(key);
|
|
9400
|
+
if (!value) {
|
|
9401
|
+
value = load().catch((error) => {
|
|
9402
|
+
map.delete(key);
|
|
9403
|
+
throw error;
|
|
9404
|
+
});
|
|
9405
|
+
map.set(key, value);
|
|
9406
|
+
}
|
|
9407
|
+
return value;
|
|
9408
|
+
}
|
|
9409
|
+
var SectionModels = class {
|
|
9410
|
+
constructor(maxAtlasSize = 2048) {
|
|
9411
|
+
this.maxAtlasSize = maxAtlasSize;
|
|
9412
|
+
this.states = /* @__PURE__ */ new WeakMap();
|
|
9413
|
+
this.models = /* @__PURE__ */ new WeakMap();
|
|
9414
|
+
this.templates = /* @__PURE__ */ new Set();
|
|
9415
|
+
if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("maxAtlasSize must be a positive integer");
|
|
9416
|
+
}
|
|
9417
|
+
async get(blockState, properties = {}) {
|
|
9418
|
+
if (!blockState.variants || blockState.multipart) return void 0;
|
|
9419
|
+
let states = this.states.get(blockState);
|
|
9420
|
+
if (!states) this.states.set(blockState, states = /* @__PURE__ */ new Map());
|
|
9421
|
+
const key = JSON.stringify(Object.entries(properties).sort(([a], [b]) => a.localeCompare(b)));
|
|
9422
|
+
const prepared = await cached(states, key, () => this.prepare(blockState, properties));
|
|
9423
|
+
if (!prepared) return void 0;
|
|
9424
|
+
return prepared.templates.get(BlockStateResolver.choose(prepared.variants));
|
|
9425
|
+
}
|
|
9426
|
+
async prepare(blockState, properties) {
|
|
9427
|
+
const state = { ...await BlockStateResolver.defaults(blockState), ...properties };
|
|
9428
|
+
const groups = BlockStateResolver.matching(blockState, state);
|
|
9429
|
+
if (groups.length !== 1) return void 0;
|
|
9430
|
+
const variants = groups[0];
|
|
9431
|
+
const choices = Array.isArray(variants) ? variants : [variants];
|
|
9432
|
+
if (!choices.length) return void 0;
|
|
9433
|
+
const templates = /* @__PURE__ */ new Map();
|
|
9434
|
+
for (const variant of choices) {
|
|
9435
|
+
const model = await Models.getMerged(AssetKey.parse("models", variant.model));
|
|
9436
|
+
if (!model) return void 0;
|
|
9437
|
+
const atlas = await UVMapper.getAtlas(model);
|
|
9438
|
+
const rotation = BlockStateResolver.rotation(variant);
|
|
9439
|
+
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;
|
|
9440
|
+
const tints = await BlockTints.get(blockState.key, state, model);
|
|
9441
|
+
let models = this.models.get(model);
|
|
9442
|
+
if (!models) this.models.set(model, models = /* @__PURE__ */ new Map());
|
|
9443
|
+
const key = JSON.stringify([rotation.x, rotation.y, rotation.z, variant.uvlock, tints]);
|
|
9444
|
+
const template = await cached(models, key, async () => {
|
|
9445
|
+
const object = new SectionModel(model, {
|
|
9446
|
+
instanceMeshes: false,
|
|
9447
|
+
mergeMeshes: false,
|
|
9448
|
+
tints,
|
|
9449
|
+
uvLockRotation: variant.uvlock && (rotation.x !== 0 || rotation.y !== 0) ? [rotation.x, rotation.y, rotation.z] : void 0
|
|
9450
|
+
});
|
|
9451
|
+
await object.init();
|
|
9452
|
+
const geometry = object.children[0].geometry;
|
|
9453
|
+
geometry.applyMatrix4(new Matrix46().makeRotationFromEuler(rotation));
|
|
9454
|
+
object.clear();
|
|
9455
|
+
const cullFaces = CUBE_FACES.map((face) => {
|
|
9456
|
+
const local = CUBE_FACES.findIndex((name) => name === atlas.model.elements[0].faces[face]?.cullface);
|
|
9457
|
+
if (local < 0) return 0;
|
|
9458
|
+
const normal = new Vector311(...CUBE_FACE_OFFSETS[local]).applyEuler(rotation);
|
|
9459
|
+
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);
|
|
9460
|
+
return 1 << world;
|
|
9461
|
+
});
|
|
9462
|
+
const template2 = { geometry, atlas, cullFaces };
|
|
9463
|
+
this.templates.add(template2);
|
|
9464
|
+
return template2;
|
|
9465
|
+
});
|
|
9466
|
+
templates.set(variant, template);
|
|
9467
|
+
}
|
|
9468
|
+
return { variants, templates };
|
|
9469
|
+
}
|
|
9470
|
+
clear() {
|
|
9471
|
+
for (const template of this.templates) template.geometry.dispose();
|
|
9472
|
+
this.templates.clear();
|
|
9473
|
+
this.states = /* @__PURE__ */ new WeakMap();
|
|
9474
|
+
this.models = /* @__PURE__ */ new WeakMap();
|
|
9475
|
+
}
|
|
9476
|
+
};
|
|
9477
|
+
|
|
9398
9478
|
// src/world/MineRenderWorld.ts
|
|
9399
|
-
import { Vector3 as Vector311 } from "three";
|
|
9400
9479
|
var MineRenderWorld = class {
|
|
9401
|
-
constructor(scene) {
|
|
9480
|
+
constructor(scene, options = {}) {
|
|
9402
9481
|
this._chunks = /* @__PURE__ */ new Map();
|
|
9403
9482
|
this.pendingCulling = /* @__PURE__ */ new Map();
|
|
9404
9483
|
this.scene = scene;
|
|
9484
|
+
if (options.sectionMeshing) this.sectionModels = new SectionModels(options.maxAtlasSize);
|
|
9405
9485
|
}
|
|
9406
9486
|
getBlockAt(posOrX, y, z) {
|
|
9407
9487
|
if (typeof posOrX == "number") {
|
|
9408
|
-
return this.getBlockAt(new
|
|
9488
|
+
return this.getBlockAt(new Vector312(posOrX, y, z));
|
|
9409
9489
|
}
|
|
9410
9490
|
if (isTripleArray(posOrX)) {
|
|
9411
|
-
return this.getBlockAt(new
|
|
9491
|
+
return this.getBlockAt(new Vector312(posOrX[0], posOrX[1], posOrX[2]));
|
|
9412
9492
|
}
|
|
9413
9493
|
this.validatePosBounds(posOrX);
|
|
9414
9494
|
return this.getChunkAt(posOrX)?.getBlockAt(posOrX);
|
|
9415
9495
|
}
|
|
9416
9496
|
async setBlockAt(posOrX, yOrBlock, z, block) {
|
|
9417
9497
|
if (typeof posOrX == "number") {
|
|
9418
|
-
return this.setBlockAt(new
|
|
9498
|
+
return this.setBlockAt(new Vector312(posOrX, yOrBlock, z), block);
|
|
9419
9499
|
}
|
|
9420
9500
|
if (isTripleArray(posOrX)) {
|
|
9421
|
-
return this.setBlockAt(new
|
|
9501
|
+
return this.setBlockAt(new Vector312(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
|
|
9422
9502
|
}
|
|
9423
9503
|
return this.placeBlock(posOrX, yOrBlock);
|
|
9424
9504
|
}
|
|
@@ -9439,7 +9519,7 @@ var MineRenderWorld = class {
|
|
|
9439
9519
|
const collect = async (positions2) => {
|
|
9440
9520
|
for (const pos of positions2) changes.set(pos.toArray().join(","), pos);
|
|
9441
9521
|
};
|
|
9442
|
-
const place = (block) => this.placeBlock(new
|
|
9522
|
+
const place = (block) => this.placeBlock(new Vector312(...block.position), block, collect);
|
|
9443
9523
|
const keys = /* @__PURE__ */ new Map();
|
|
9444
9524
|
for (const block of multiblock.blocks) {
|
|
9445
9525
|
if (Chunk.isAir(block)) continue;
|
|
@@ -9511,12 +9591,13 @@ var MineRenderWorld = class {
|
|
|
9511
9591
|
for (const chunk of chunks) {
|
|
9512
9592
|
await chunk.dispose();
|
|
9513
9593
|
}
|
|
9594
|
+
this.sectionModels?.clear();
|
|
9514
9595
|
}
|
|
9515
9596
|
updateCulling(positions) {
|
|
9516
9597
|
for (const pos of positions) {
|
|
9517
9598
|
this.pendingCulling.set(pos.toArray().join(","), pos.clone());
|
|
9518
9599
|
for (const offset of CUBE_FACE_OFFSETS) {
|
|
9519
|
-
const neighbor = pos.clone().add(new
|
|
9600
|
+
const neighbor = pos.clone().add(new Vector312(...offset));
|
|
9520
9601
|
this.pendingCulling.set(neighbor.toArray().join(","), neighbor);
|
|
9521
9602
|
}
|
|
9522
9603
|
}
|
|
@@ -9525,17 +9606,22 @@ var MineRenderWorld = class {
|
|
|
9525
9606
|
while (this.pendingCulling.size) {
|
|
9526
9607
|
const batch = [...this.pendingCulling.values()];
|
|
9527
9608
|
this.pendingCulling.clear();
|
|
9609
|
+
const changed = /* @__PURE__ */ new Set();
|
|
9528
9610
|
for (const pos of batch) {
|
|
9529
|
-
const
|
|
9530
|
-
if (!
|
|
9611
|
+
const chunk = this.getChunkAt(pos);
|
|
9612
|
+
if (!chunk) continue;
|
|
9613
|
+
changed.add(chunk);
|
|
9614
|
+
if (!chunk.getBlockAt(pos)) continue;
|
|
9531
9615
|
let mask = 0;
|
|
9532
9616
|
for (const [face, offset] of CUBE_FACE_OFFSETS.entries()) {
|
|
9533
|
-
|
|
9617
|
+
const neighbor = pos.clone().add(new Vector312(...offset));
|
|
9618
|
+
if (this.getChunkAt(neighbor)?.isOccludingAt(neighbor)) {
|
|
9534
9619
|
mask |= 1 << face;
|
|
9535
9620
|
}
|
|
9536
9621
|
}
|
|
9537
|
-
await
|
|
9622
|
+
await chunk.setCullMaskAt(pos, mask);
|
|
9538
9623
|
}
|
|
9624
|
+
for (const chunk of changed) chunk.rebuildSectionMesh();
|
|
9539
9625
|
}
|
|
9540
9626
|
} finally {
|
|
9541
9627
|
this.culling = void 0;
|
|
@@ -9551,7 +9637,8 @@ var MineRenderWorld = class {
|
|
|
9551
9637
|
Math.floor(pos.x / 16),
|
|
9552
9638
|
Math.floor(pos.y / 16),
|
|
9553
9639
|
Math.floor(pos.z / 16),
|
|
9554
|
-
(positions) => this.updateCulling(positions)
|
|
9640
|
+
(positions) => this.updateCulling(positions),
|
|
9641
|
+
this.sectionModels
|
|
9555
9642
|
);
|
|
9556
9643
|
this._chunks.set(key, chunk);
|
|
9557
9644
|
}
|
|
@@ -9561,14 +9648,14 @@ var MineRenderWorld = class {
|
|
|
9561
9648
|
return this._chunks.get(this.worldPosToChunkKey(pos));
|
|
9562
9649
|
}
|
|
9563
9650
|
static worldToScenePosition(pos) {
|
|
9564
|
-
return new
|
|
9651
|
+
return new Vector312(
|
|
9565
9652
|
pos.x * 16,
|
|
9566
9653
|
pos.y * 16,
|
|
9567
9654
|
pos.z * 16
|
|
9568
9655
|
);
|
|
9569
9656
|
}
|
|
9570
9657
|
static sceneToWorldPosition(pos) {
|
|
9571
|
-
return new
|
|
9658
|
+
return new Vector312(
|
|
9572
9659
|
pos.x / 16,
|
|
9573
9660
|
pos.y / 16,
|
|
9574
9661
|
pos.z / 16
|
|
@@ -9587,12 +9674,118 @@ var MineRenderWorld = class {
|
|
|
9587
9674
|
}
|
|
9588
9675
|
};
|
|
9589
9676
|
|
|
9677
|
+
// src/world/SectionMesh.ts
|
|
9678
|
+
import { BufferGeometry as BufferGeometry2, Float32BufferAttribute as Float32BufferAttribute4, Group, Mesh as Mesh7 } from "three";
|
|
9679
|
+
var SectionMesh = class _SectionMesh extends Group {
|
|
9680
|
+
constructor() {
|
|
9681
|
+
super(...arguments);
|
|
9682
|
+
this.ownedMeshes = [];
|
|
9683
|
+
}
|
|
9684
|
+
static build(entries, maxAtlasSize = 2048) {
|
|
9685
|
+
if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("Section atlas size must be a positive integer");
|
|
9686
|
+
const visible = entries.filter((entry) => entry.template.cullFaces.some((direction) => !(entry.cullMask & direction)));
|
|
9687
|
+
const atlases = [...new Set(visible.map((entry) => entry.template.atlas))].sort((a, b) => b.image.height - a.image.height);
|
|
9688
|
+
const pages = [];
|
|
9689
|
+
const locations = /* @__PURE__ */ new Map();
|
|
9690
|
+
for (const atlas of atlases) {
|
|
9691
|
+
const { width, height } = atlas.image;
|
|
9692
|
+
if (width > maxAtlasSize || height > maxAtlasSize) throw new RangeError("Model atlas exceeds the section atlas size limit");
|
|
9693
|
+
let selected;
|
|
9694
|
+
for (const page of pages) {
|
|
9695
|
+
const nextRow = page.x + width > maxAtlasSize;
|
|
9696
|
+
if ((nextRow ? page.y + page.rowHeight : page.y) + height > maxAtlasSize) continue;
|
|
9697
|
+
if (nextRow) {
|
|
9698
|
+
page.y += page.rowHeight;
|
|
9699
|
+
page.x = 0;
|
|
9700
|
+
page.rowHeight = 0;
|
|
9701
|
+
}
|
|
9702
|
+
selected = page;
|
|
9703
|
+
break;
|
|
9704
|
+
}
|
|
9705
|
+
if (!selected) {
|
|
9706
|
+
selected = { placements: [], entries: [], x: 0, y: 0, rowHeight: 0, width: 0, height: 0 };
|
|
9707
|
+
pages.push(selected);
|
|
9708
|
+
}
|
|
9709
|
+
const placement = { atlas, x: selected.x, y: selected.y };
|
|
9710
|
+
selected.placements.push(placement);
|
|
9711
|
+
selected.x += width;
|
|
9712
|
+
selected.rowHeight = Math.max(selected.rowHeight, height);
|
|
9713
|
+
selected.width = Math.max(selected.width, selected.x);
|
|
9714
|
+
selected.height = Math.max(selected.height, selected.y + height);
|
|
9715
|
+
locations.set(atlas, { page: selected, placement });
|
|
9716
|
+
}
|
|
9717
|
+
for (const entry of visible) locations.get(entry.template.atlas).page.entries.push(entry);
|
|
9718
|
+
const section = new _SectionMesh();
|
|
9719
|
+
for (const page of pages) {
|
|
9720
|
+
const canvas = createCanvas2(page.width, page.height);
|
|
9721
|
+
const context = canvas.getContext("2d");
|
|
9722
|
+
for (const { atlas, x, y } of page.placements) {
|
|
9723
|
+
context.drawImage(atlas.image.canvas, x, y);
|
|
9724
|
+
}
|
|
9725
|
+
const positions = [], normals = [], uvs = [], colors = [], indices = [];
|
|
9726
|
+
for (const { index, template, cullMask } of page.entries) {
|
|
9727
|
+
const position = template.geometry.getAttribute("position");
|
|
9728
|
+
const normal = template.geometry.getAttribute("normal");
|
|
9729
|
+
const uv = template.geometry.getAttribute("uv");
|
|
9730
|
+
const color = template.geometry.getAttribute("color");
|
|
9731
|
+
const sourceIndices = template.geometry.getIndex();
|
|
9732
|
+
const placement = locations.get(template.atlas).placement;
|
|
9733
|
+
const offsetX = index % 16 * 16;
|
|
9734
|
+
const offsetY = Math.floor(index / 256) * 16;
|
|
9735
|
+
const offsetZ = Math.floor(index / 16) % 16 * 16;
|
|
9736
|
+
for (let face = 0; face < 6; face++) {
|
|
9737
|
+
if (cullMask & template.cullFaces[face]) continue;
|
|
9738
|
+
const start = positions.length / 3;
|
|
9739
|
+
for (let corner = 0; corner < 4; corner++) {
|
|
9740
|
+
const vertex = face * 4 + corner;
|
|
9741
|
+
positions.push(position.getX(vertex) + offsetX, position.getY(vertex) + offsetY, position.getZ(vertex) + offsetZ);
|
|
9742
|
+
normals.push(normal.getX(vertex), normal.getY(vertex), normal.getZ(vertex));
|
|
9743
|
+
uvs.push(
|
|
9744
|
+
(placement.x + uv.getX(vertex) * template.atlas.image.width) / page.width,
|
|
9745
|
+
1 - (placement.y + (1 - uv.getY(vertex)) * template.atlas.image.height) / page.height
|
|
9746
|
+
);
|
|
9747
|
+
colors.push(color?.getX(vertex) ?? 1, color?.getY(vertex) ?? 1, color?.getZ(vertex) ?? 1);
|
|
9748
|
+
}
|
|
9749
|
+
for (let corner = 0; corner < 6; corner++) indices.push(start + sourceIndices.getX(face * 6 + corner) - face * 4);
|
|
9750
|
+
}
|
|
9751
|
+
}
|
|
9752
|
+
const geometry = new BufferGeometry2();
|
|
9753
|
+
geometry.setAttribute("position", new Float32BufferAttribute4(positions, 3));
|
|
9754
|
+
geometry.setAttribute("normal", new Float32BufferAttribute4(normals, 3));
|
|
9755
|
+
geometry.setAttribute("uv", new Float32BufferAttribute4(uvs, 2));
|
|
9756
|
+
geometry.setAttribute("color", new Float32BufferAttribute4(colors, 3));
|
|
9757
|
+
geometry.setIndex(indices);
|
|
9758
|
+
geometry.computeBoundingBox();
|
|
9759
|
+
geometry.computeBoundingSphere();
|
|
9760
|
+
const material = Materials.createShadedCanvasMaterial(canvas, false);
|
|
9761
|
+
material.vertexColors = true;
|
|
9762
|
+
const texture = material.uniforms?.map?.value ?? material.map;
|
|
9763
|
+
const mesh = new Mesh7(geometry, material);
|
|
9764
|
+
section.add(mesh);
|
|
9765
|
+
section.ownedMeshes.push({ mesh, texture });
|
|
9766
|
+
}
|
|
9767
|
+
return section;
|
|
9768
|
+
}
|
|
9769
|
+
dispose() {
|
|
9770
|
+
for (const { mesh, texture } of this.ownedMeshes.splice(0)) {
|
|
9771
|
+
mesh.removeFromParent();
|
|
9772
|
+
mesh.geometry.dispose();
|
|
9773
|
+
mesh.material.dispose();
|
|
9774
|
+
texture?.dispose();
|
|
9775
|
+
}
|
|
9776
|
+
this.removeFromParent();
|
|
9777
|
+
}
|
|
9778
|
+
};
|
|
9779
|
+
|
|
9590
9780
|
// src/world/Chunk.ts
|
|
9591
9781
|
var Chunk = class _Chunk {
|
|
9592
|
-
constructor(scene, x, y, z, onBlocksChanged) {
|
|
9782
|
+
constructor(scene, x, y, z, onBlocksChanged, sectionModels) {
|
|
9593
9783
|
this.onBlocksChanged = onBlocksChanged;
|
|
9784
|
+
this.sectionModels = sectionModels;
|
|
9594
9785
|
this.data = new ChunkData();
|
|
9595
9786
|
this.renderedBlocks = /* @__PURE__ */ new Map();
|
|
9787
|
+
this.sectionBlocks = /* @__PURE__ */ new Map();
|
|
9788
|
+
this.meshDirty = false;
|
|
9596
9789
|
this.scene = scene;
|
|
9597
9790
|
this.x = x;
|
|
9598
9791
|
this.y = y;
|
|
@@ -9600,10 +9793,10 @@ var Chunk = class _Chunk {
|
|
|
9600
9793
|
}
|
|
9601
9794
|
getBlockAt(posOrX, y, z) {
|
|
9602
9795
|
if (typeof posOrX == "number") {
|
|
9603
|
-
return this.getBlockAt(new
|
|
9796
|
+
return this.getBlockAt(new Vector313(posOrX, y, z));
|
|
9604
9797
|
}
|
|
9605
9798
|
if (isTripleArray(posOrX)) {
|
|
9606
|
-
return this.getBlockAt(new
|
|
9799
|
+
return this.getBlockAt(new Vector313(posOrX[0], posOrX[1], posOrX[2]));
|
|
9607
9800
|
}
|
|
9608
9801
|
const pos = this.worldPosToChunkPos(posOrX);
|
|
9609
9802
|
const index = _Chunk.chunkPosToBlockIndex(pos);
|
|
@@ -9611,10 +9804,10 @@ var Chunk = class _Chunk {
|
|
|
9611
9804
|
}
|
|
9612
9805
|
async setBlockAt(posOrX, yOrBlock, z, block) {
|
|
9613
9806
|
if (typeof posOrX == "number") {
|
|
9614
|
-
return this.setBlockAt(new
|
|
9807
|
+
return this.setBlockAt(new Vector313(posOrX, yOrBlock, z), block);
|
|
9615
9808
|
}
|
|
9616
9809
|
if (isTripleArray(posOrX)) {
|
|
9617
|
-
return this.setBlockAt(new
|
|
9810
|
+
return this.setBlockAt(new Vector313(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
|
|
9618
9811
|
}
|
|
9619
9812
|
const worldPos = posOrX;
|
|
9620
9813
|
const pos = this.worldPosToChunkPos(worldPos);
|
|
@@ -9631,7 +9824,8 @@ var Chunk = class _Chunk {
|
|
|
9631
9824
|
const index = _Chunk.chunkPosToBlockIndex(pos);
|
|
9632
9825
|
this.data.set(index, block);
|
|
9633
9826
|
const readBlock = this.data.snapshot(index);
|
|
9634
|
-
this.renderedBlocks.get(index)?.object
|
|
9827
|
+
this.renderedBlocks.get(index)?.object?.removeFromScene();
|
|
9828
|
+
if (this.sectionBlocks.delete(index)) this.meshDirty = true;
|
|
9635
9829
|
this.renderedBlocks.delete(index);
|
|
9636
9830
|
let object;
|
|
9637
9831
|
try {
|
|
@@ -9642,13 +9836,19 @@ var Chunk = class _Chunk {
|
|
|
9642
9836
|
this.data.set(index, void 0);
|
|
9643
9837
|
return void 0;
|
|
9644
9838
|
}
|
|
9645
|
-
|
|
9646
|
-
|
|
9647
|
-
|
|
9648
|
-
|
|
9649
|
-
|
|
9650
|
-
|
|
9651
|
-
|
|
9839
|
+
const template = await this.sectionModels?.get(blockState, stored.properties);
|
|
9840
|
+
if (template) {
|
|
9841
|
+
this.sectionBlocks.set(index, { index, template, cullMask: 0 });
|
|
9842
|
+
this.meshDirty = true;
|
|
9843
|
+
} else {
|
|
9844
|
+
object = await this.scene.addBlock(blockState, {
|
|
9845
|
+
mergeMeshes: true,
|
|
9846
|
+
instanceMeshes: true,
|
|
9847
|
+
maxInstanceCount: 2e3,
|
|
9848
|
+
initialState: stored.properties
|
|
9849
|
+
});
|
|
9850
|
+
object.setPosition(MineRenderWorld.worldToScenePosition(worldPos));
|
|
9851
|
+
}
|
|
9652
9852
|
const info = { get block() {
|
|
9653
9853
|
return readBlock();
|
|
9654
9854
|
}, object };
|
|
@@ -9662,11 +9862,43 @@ var Chunk = class _Chunk {
|
|
|
9662
9862
|
await onBlocksChanged?.([worldPos]);
|
|
9663
9863
|
}
|
|
9664
9864
|
}
|
|
9865
|
+
isOccludingAt(pos) {
|
|
9866
|
+
const index = _Chunk.chunkPosToBlockIndex(this.worldPosToChunkPos(pos));
|
|
9867
|
+
return this.sectionBlocks.has(index) || (this.renderedBlocks.get(index)?.object?.isOccluding ?? false);
|
|
9868
|
+
}
|
|
9869
|
+
async setCullMaskAt(pos, mask) {
|
|
9870
|
+
const index = _Chunk.chunkPosToBlockIndex(this.worldPosToChunkPos(pos));
|
|
9871
|
+
const entry = this.sectionBlocks.get(index);
|
|
9872
|
+
if (entry) {
|
|
9873
|
+
if (entry.cullMask !== mask) {
|
|
9874
|
+
entry.cullMask = mask;
|
|
9875
|
+
this.meshDirty = true;
|
|
9876
|
+
}
|
|
9877
|
+
} else {
|
|
9878
|
+
await this.renderedBlocks.get(index)?.object?.setCullMask(mask);
|
|
9879
|
+
}
|
|
9880
|
+
}
|
|
9881
|
+
rebuildSectionMesh() {
|
|
9882
|
+
if (!this.meshDirty) return;
|
|
9883
|
+
const next = this.sectionBlocks.size ? SectionMesh.build([...this.sectionBlocks.values()], this.sectionModels.maxAtlasSize) : void 0;
|
|
9884
|
+
this.sectionMesh?.dispose();
|
|
9885
|
+
this.sectionMesh = next;
|
|
9886
|
+
if (next) {
|
|
9887
|
+
next.position.set(this.x * 256, this.y * 256, this.z * 256);
|
|
9888
|
+
this.scene.add(next);
|
|
9889
|
+
}
|
|
9890
|
+
this.scene.dirty = true;
|
|
9891
|
+
this.meshDirty = false;
|
|
9892
|
+
}
|
|
9665
9893
|
async clear(onBlocksChanged = this.onBlocksChanged) {
|
|
9666
9894
|
const positions = [...this.renderedBlocks.keys()].map((index) => this.chunkPosToWorldPos(
|
|
9667
|
-
new
|
|
9895
|
+
new Vector313(index % 16, Math.floor(index / 256), Math.floor(index / 16) % 16)
|
|
9668
9896
|
));
|
|
9669
|
-
for (const info of this.renderedBlocks.values()) info.object
|
|
9897
|
+
for (const info of this.renderedBlocks.values()) info.object?.removeFromScene();
|
|
9898
|
+
this.sectionBlocks.clear();
|
|
9899
|
+
this.sectionMesh?.dispose();
|
|
9900
|
+
this.sectionMesh = void 0;
|
|
9901
|
+
this.meshDirty = false;
|
|
9670
9902
|
this.renderedBlocks.clear();
|
|
9671
9903
|
this.data.clear();
|
|
9672
9904
|
await onBlocksChanged?.(positions);
|
|
@@ -9684,14 +9916,14 @@ var Chunk = class _Chunk {
|
|
|
9684
9916
|
return pos.y * 16 * 16 + pos.z * 16 + pos.x;
|
|
9685
9917
|
}
|
|
9686
9918
|
worldPosToChunkPos(pos) {
|
|
9687
|
-
return new
|
|
9919
|
+
return new Vector313(
|
|
9688
9920
|
pos.x - this.x * 16,
|
|
9689
9921
|
pos.y - this.y * 16,
|
|
9690
9922
|
pos.z - this.z * 16
|
|
9691
9923
|
);
|
|
9692
9924
|
}
|
|
9693
9925
|
chunkPosToWorldPos(pos) {
|
|
9694
|
-
return new
|
|
9926
|
+
return new Vector313(
|
|
9695
9927
|
this.x * 16 + pos.x,
|
|
9696
9928
|
this.y * 16 + pos.y,
|
|
9697
9929
|
this.z * 16 + pos.z
|
|
@@ -9714,6 +9946,7 @@ export {
|
|
|
9714
9946
|
BasicAssetKey,
|
|
9715
9947
|
BatchedExecutor,
|
|
9716
9948
|
BlockObject,
|
|
9949
|
+
BlockStateResolver,
|
|
9717
9950
|
BlockStates,
|
|
9718
9951
|
BlockTints,
|
|
9719
9952
|
BrowserArchiveProxy,
|
|
@@ -9772,6 +10005,8 @@ export {
|
|
|
9772
10005
|
SceneStats,
|
|
9773
10006
|
SceneStatsDisplay,
|
|
9774
10007
|
SchematicParser,
|
|
10008
|
+
SectionMesh,
|
|
10009
|
+
SectionModels,
|
|
9775
10010
|
SkinImage,
|
|
9776
10011
|
SkinObject,
|
|
9777
10012
|
SkinPart,
|