minecraft-renderer 0.1.63 → 0.1.65
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/mesherWasm.js +22 -22
- package/dist/minecraft-renderer.js +59 -59
- package/dist/minecraft-renderer.js.meta.json +1 -1
- package/dist/threeWorker.js +415 -415
- package/package.json +1 -1
- package/src/graphicsBackend/rendererDefaultOptions.ts +41 -24
- package/src/graphicsBackend/rendererOptionsSync.ts +23 -23
- package/src/index.ts +8 -8
- package/src/lib/worldrendererCommon.removeColumn.test.ts +182 -0
- package/src/lib/worldrendererCommon.ts +16 -6
- package/src/three/entities.ts +54 -170
- package/src/three/entity/animations.js +92 -185
- package/src/three/menuBackground/activeView.ts +1 -1
- package/src/three/menuBackground/config.ts +9 -9
- package/src/three/menuBackground/index.ts +10 -10
- package/src/three/menuBackground/renderer.ts +12 -12
- package/src/three/menuBackground/types.ts +9 -9
- package/src/three/menuBackground/{futuristic.ts → v2.ts} +110 -59
- package/src/three/menuBackground/{futuristicMeta.ts → v2Meta.ts} +6 -6
- package/src/wasm-mesher/tests/mesherWasmRequestTracker.test.ts +29 -0
- package/src/wasm-mesher/worker/mesherWasm.ts +7 -0
- package/src/wasm-mesher/worker/mesherWasmRequestTracker.ts +10 -0
- package/src/worldView/worldView.spiral.test.ts +38 -0
- package/src/worldView/worldView.ts +2 -0
package/src/three/entities.ts
CHANGED
|
@@ -45,14 +45,6 @@ export const TWEEN_DURATION = 120
|
|
|
45
45
|
|
|
46
46
|
const degreesToRadians = (degrees: number) => degrees * (Math.PI / 180)
|
|
47
47
|
|
|
48
|
-
const clamp01 = (v: number) => Math.max(0, Math.min(1, v))
|
|
49
|
-
const clamp = (v: number, a: number, b: number) => Math.max(a, Math.min(b, v))
|
|
50
|
-
const wrapPi = (a: number) => {
|
|
51
|
-
a = (a + Math.PI) % (Math.PI * 2)
|
|
52
|
-
if (a < 0) a += Math.PI * 2
|
|
53
|
-
return a - Math.PI
|
|
54
|
-
}
|
|
55
|
-
|
|
56
48
|
function convert2sComplementToHex(complement: number) {
|
|
57
49
|
if (complement < 0) {
|
|
58
50
|
complement = (0xFF_FF_FF_FF + complement + 1) >>> 0
|
|
@@ -280,130 +272,45 @@ export class Entities {
|
|
|
280
272
|
pendingModelOverrides = new Map<string, { parts: EntityModelOverridePart[] }>()
|
|
281
273
|
|
|
282
274
|
private motionCache = new Map<string, { pos: THREE.Vector3, speed: number }>()
|
|
283
|
-
private
|
|
275
|
+
private readonly MOVE_ON = 0.05
|
|
276
|
+
private readonly MOVE_OFF = 0.02
|
|
277
|
+
private readonly RUN_ON = 4.8
|
|
278
|
+
private readonly RUN_OFF = 4.2
|
|
284
279
|
|
|
285
|
-
private
|
|
286
|
-
private _tpHasBodyYaw = false
|
|
287
|
-
|
|
288
|
-
private updateAutoWalkFlags(entityKey: string, entity: SceneEntity, dt: number, samplePos?: THREE.Vector3) {
|
|
280
|
+
private updateAutoWalkFlags(entityKey: string, entity: SceneEntity, dt: number) {
|
|
289
281
|
if (!entity.playerObject?.animation) return
|
|
290
282
|
const anim: any = entity.playerObject.animation
|
|
283
|
+
if (!('isMoving' in anim) || !('isRunning' in anim)) return
|
|
291
284
|
if (dt <= 0) return
|
|
292
285
|
|
|
293
|
-
const pos = samplePos ?? entity.position
|
|
294
|
-
|
|
295
286
|
const cached = this.motionCache.get(entityKey)
|
|
296
287
|
if (!cached) {
|
|
297
|
-
this.motionCache.set(entityKey, { pos:
|
|
288
|
+
this.motionCache.set(entityKey, { pos: entity.position.clone(), speed: 0 })
|
|
298
289
|
anim.isMoving = false
|
|
299
290
|
anim.isRunning = false
|
|
300
|
-
anim.moveAmount = 0
|
|
301
|
-
anim.runAmount = 0
|
|
302
291
|
return
|
|
303
292
|
}
|
|
304
293
|
|
|
305
|
-
const dx =
|
|
306
|
-
const dz =
|
|
307
|
-
cached.pos.copy(
|
|
308
|
-
|
|
309
|
-
const instSpeed = Math.hypot(dx, dz) / Math.max(dt, 1e-6) // blocks/sec
|
|
310
|
-
|
|
311
|
-
const alpha = 1 - Math.exp(-dt * 12)
|
|
312
|
-
cached.speed += (instSpeed - cached.speed) * alpha
|
|
313
|
-
|
|
314
|
-
const speed = cached.speed
|
|
315
|
-
|
|
316
|
-
const smoothstep = (a: number, b: number, x: number) => {
|
|
317
|
-
const t = clamp01((x - a) / (b - a))
|
|
318
|
-
return t * t * (3 - 2 * t)
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
const MOVE_START = 0.08
|
|
322
|
-
const MOVE_FULL = 0.6
|
|
323
|
-
|
|
324
|
-
const WALK_MAX = 4.3
|
|
325
|
-
const SPRINT_FULL = 5.6
|
|
326
|
-
|
|
327
|
-
const moveAmount = smoothstep(MOVE_START, MOVE_FULL, speed)
|
|
328
|
-
const runAmount = smoothstep(WALK_MAX, SPRINT_FULL, speed)
|
|
329
|
-
|
|
330
|
-
anim.moveAmount = moveAmount
|
|
331
|
-
anim.runAmount = runAmount
|
|
332
|
-
|
|
333
|
-
anim.isMoving = moveAmount > 0.15
|
|
334
|
-
anim.isRunning = runAmount > 0.55
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
private getLocalSneak(): boolean {
|
|
338
|
-
const ps: any = this.worldRenderer.playerStateReactive as any
|
|
339
|
-
return (
|
|
340
|
-
ps?.movementState === 'SNEAKING' ||
|
|
341
|
-
ps?.movementState === 'CROUCHING' ||
|
|
342
|
-
!!ps?.isSneaking ||
|
|
343
|
-
!!ps?.sneaking ||
|
|
344
|
-
!!ps?.isCrouching ||
|
|
345
|
-
!!ps?.crouching ||
|
|
346
|
-
!!ps?.controls?.sneak ||
|
|
347
|
-
!!ps?.controlState?.sneak
|
|
348
|
-
)
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
private updateThirdPersonHeadAndBody(entity: SceneEntity, dt: number) {
|
|
352
|
-
const anim: any = entity.playerObject?.animation
|
|
353
|
-
const rotation = this.worldRenderer.cameraShake.getBaseRotation()
|
|
354
|
-
|
|
355
|
-
const camYaw = rotation.yaw
|
|
356
|
-
const camPitch = rotation.pitch
|
|
357
|
-
|
|
358
|
-
const move = clamp01(anim?.moveAmount ?? (anim?.isMoving ? 1 : 0))
|
|
359
|
-
const run = clamp01(anim?.runAmount ?? (anim?.isRunning ? 1 : 0))
|
|
360
|
-
const moving = move > 0.15
|
|
361
|
-
|
|
362
|
-
if (!this._tpHasBodyYaw) {
|
|
363
|
-
this._tpHasBodyYaw = true
|
|
364
|
-
this._tpBodyYaw = camYaw
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
if (moving) {
|
|
368
|
-
const k = 1 - Math.exp(-dt * (18 + 10 * run))
|
|
369
|
-
this._tpBodyYaw = this._tpBodyYaw + wrapPi(camYaw - this._tpBodyYaw) * k
|
|
294
|
+
const dx = entity.position.x - cached.pos.x
|
|
295
|
+
const dz = entity.position.z - cached.pos.z
|
|
296
|
+
cached.pos.copy(entity.position)
|
|
370
297
|
|
|
371
|
-
|
|
298
|
+
const instSpeed = Math.hypot(dx, dz) / Math.max(dt, 1e-6)
|
|
372
299
|
|
|
373
|
-
|
|
374
|
-
const headYaw = clamp(wrapPi(camYaw - this._tpBodyYaw), -headMax, headMax)
|
|
300
|
+
cached.speed = cached.speed * 0.8 + instSpeed * 0.2
|
|
375
301
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
}
|
|
302
|
+
const movingNow = anim.isMoving
|
|
303
|
+
? cached.speed > this.MOVE_OFF
|
|
304
|
+
: cached.speed > this.MOVE_ON
|
|
380
305
|
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
306
|
+
const runningNow = anim.isRunning
|
|
307
|
+
? cached.speed > this.RUN_OFF
|
|
308
|
+
: cached.speed > this.RUN_ON
|
|
384
309
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
const excess = Math.abs(desiredHeadYaw) - bodyFollowStart
|
|
389
|
-
if (excess > 0) {
|
|
390
|
-
const push = excess / (maxHeadYaw - bodyFollowStart)
|
|
391
|
-
const targetBodyYaw = camYaw - Math.sign(desiredHeadYaw) * bodyFollowStart
|
|
392
|
-
const k = 1 - Math.exp(-dt * (6 + 10 * push))
|
|
393
|
-
this._tpBodyYaw = this._tpBodyYaw + wrapPi(targetBodyYaw - this._tpBodyYaw) * k
|
|
394
|
-
desiredHeadYaw = wrapPi(camYaw - this._tpBodyYaw)
|
|
395
|
-
desiredHeadYaw = clamp(desiredHeadYaw, -maxHeadYaw, maxHeadYaw)
|
|
396
|
-
} else {
|
|
397
|
-
const k = 1 - Math.exp(-dt * 5)
|
|
398
|
-
this._tpBodyYaw = this._tpBodyYaw + wrapPi(camYaw - this._tpBodyYaw) * (k * 0.15)
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
entity.rotation.set(0, this._tpBodyYaw, 0)
|
|
402
|
-
if (anim && 'lookYaw' in anim) anim.lookYaw = desiredHeadYaw
|
|
403
|
-
if (anim && 'lookPitch' in anim) anim.lookPitch = -camPitch
|
|
310
|
+
anim.isMoving = movingNow
|
|
311
|
+
anim.isRunning = movingNow && runningNow
|
|
404
312
|
}
|
|
405
313
|
|
|
406
|
-
|
|
407
314
|
get entitiesByName(): Record<string, SceneEntity[]> {
|
|
408
315
|
const byName: Record<string, SceneEntity[]> = {}
|
|
409
316
|
for (const entity of Object.values(this.entities)) {
|
|
@@ -477,8 +384,6 @@ export class Entities {
|
|
|
477
384
|
this.currentSkinUrls = {}
|
|
478
385
|
|
|
479
386
|
this.motionCache.clear()
|
|
480
|
-
this._wasThirdPerson = false
|
|
481
|
-
this._tpHasBodyYaw = false
|
|
482
387
|
|
|
483
388
|
// Clean up player entity
|
|
484
389
|
if (this.playerEntity) {
|
|
@@ -547,93 +452,67 @@ export class Entities {
|
|
|
547
452
|
const botPos = this.worldRenderer.viewerChunkPosition
|
|
548
453
|
const VISIBLE_DISTANCE = 10 * 10
|
|
549
454
|
|
|
550
|
-
const thirdPersonNow = this.worldRenderer.playerStateUtils.isThirdPerson()
|
|
551
|
-
if (thirdPersonNow !== this._wasThirdPerson) {
|
|
552
|
-
this._wasThirdPerson = thirdPersonNow
|
|
553
|
-
const key = String(this.playerEntity?.originalEntity.id ?? 'player_entity')
|
|
554
|
-
this.motionCache.delete(key)
|
|
555
|
-
|
|
556
|
-
const anim: any = this.playerEntity?.playerObject?.animation
|
|
557
|
-
if (anim?.resetLocomotion) anim.resetLocomotion()
|
|
558
|
-
|
|
559
|
-
this._tpHasBodyYaw = false
|
|
560
|
-
}
|
|
561
|
-
|
|
562
455
|
for (const [entityIdRaw, entity] of [...Object.entries(this.entities), ['player_entity', this.playerEntity] as [string, SceneEntity | null]]) {
|
|
563
456
|
if (!entity) continue
|
|
564
457
|
|
|
458
|
+
let entityKey = entityIdRaw
|
|
565
459
|
const isPlayerEntity = entityIdRaw === 'player_entity'
|
|
566
|
-
const entityKey = isPlayerEntity ? String(this.playerEntity?.originalEntity.id ?? 'player_entity') : String(entityIdRaw)
|
|
567
460
|
|
|
568
461
|
if (isPlayerEntity) {
|
|
569
|
-
|
|
462
|
+
const thirdPerson = this.worldRenderer.playerStateUtils.isThirdPerson()
|
|
463
|
+
entity.visible = thirdPerson
|
|
570
464
|
|
|
571
|
-
if (
|
|
465
|
+
if (thirdPerson) {
|
|
572
466
|
const yOffset = this.worldRenderer.playerStateReactive.eyeHeight
|
|
573
|
-
// Set world position — proxy auto-converts to scene coords
|
|
574
467
|
entity.position.set(
|
|
575
468
|
this.worldRenderer.cameraWorldPos.x,
|
|
576
469
|
this.worldRenderer.cameraWorldPos.y - yOffset,
|
|
577
470
|
this.worldRenderer.cameraWorldPos.z
|
|
578
471
|
)
|
|
579
|
-
|
|
580
|
-
const p: any = (this.worldRenderer.playerStateReactive as any).position
|
|
581
|
-
if (p && typeof p.x === 'number') {
|
|
582
|
-
this.updateAutoWalkFlags(entityKey, entity, dtRaw, new THREE.Vector3(p.x, p.y, p.z))
|
|
583
|
-
} else {
|
|
584
|
-
const wp = this.worldRenderer.sceneOrigin.getWorldPosition(entity)
|
|
585
|
-
this.updateAutoWalkFlags(entityKey, entity, dtRaw, wp ? new THREE.Vector3(wp.x, wp.y, wp.z) : entity.position)
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
this.updateThirdPersonHeadAndBody(entity, dt)
|
|
589
|
-
} else {
|
|
590
|
-
const wp = this.worldRenderer.sceneOrigin.getWorldPosition(entity)
|
|
591
|
-
this.updateAutoWalkFlags(entityKey, entity, dtRaw, wp ? new THREE.Vector3(wp.x, wp.y, wp.z) : entity.position)
|
|
592
472
|
}
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
this.updateAutoWalkFlags(entityKey, entity, dtRaw, wp ? new THREE.Vector3(wp.x, wp.y, wp.z) : entity.position)
|
|
473
|
+
|
|
474
|
+
entityKey = String(this.playerEntity?.originalEntity.id ?? 'player_entity')
|
|
596
475
|
}
|
|
597
476
|
|
|
598
477
|
const { playerObject } = entity
|
|
599
478
|
|
|
600
|
-
|
|
601
|
-
const anim: any = playerObject.animation
|
|
602
|
-
|
|
603
|
-
const flags = Number((entity.originalEntity?.metadata?.[0] ?? 0))
|
|
604
|
-
const remoteSneak = (flags & 0x02) !== 0
|
|
605
|
-
|
|
606
|
-
const localSneak = this.getLocalSneak()
|
|
607
|
-
|
|
608
|
-
if ('isCrouched' in anim) anim.isCrouched = isPlayerEntity ? localSneak : remoteSneak
|
|
479
|
+
this.updateAutoWalkFlags(entityKey, entity, dtRaw)
|
|
609
480
|
|
|
481
|
+
if (playerObject?.animation) {
|
|
610
482
|
playerObject.animation.update(playerObject, dt)
|
|
611
483
|
}
|
|
612
484
|
|
|
613
|
-
// Update GLTF animations
|
|
614
485
|
entity.traverse(child => {
|
|
615
486
|
if (child instanceof Entity.EntityMesh) {
|
|
616
487
|
child.update(dt)
|
|
617
488
|
}
|
|
618
489
|
})
|
|
619
490
|
|
|
620
|
-
// Update visibility based on distance and chunk load status
|
|
621
491
|
if (!isPlayerEntity && botPos && entity.position) {
|
|
622
492
|
const dx = entity.position.x - botPos.x
|
|
623
493
|
const dy = entity.position.y - botPos.y
|
|
624
494
|
const dz = entity.position.z - botPos.z
|
|
625
495
|
const distanceSquared = dx * dx + dy * dy + dz * dz
|
|
626
496
|
|
|
627
|
-
// Entity is visible if within 20 blocks OR in a finished chunk
|
|
628
497
|
entity.visible = !!(distanceSquared < VISIBLE_DISTANCE || this.worldRenderer.shouldObjectVisible(entity))
|
|
629
498
|
|
|
630
499
|
this.maybeRenderPlayerSkin(entityIdRaw)
|
|
631
500
|
}
|
|
632
501
|
|
|
633
502
|
if (entity.visible) {
|
|
634
|
-
// Update armor positions
|
|
635
503
|
this.syncArmorPositions(entity)
|
|
636
504
|
}
|
|
505
|
+
|
|
506
|
+
if (isPlayerEntity && entity.visible) {
|
|
507
|
+
const rotation = this.worldRenderer.cameraShake.getBaseRotation()
|
|
508
|
+
entity.rotation.set(0, rotation.yaw, 0)
|
|
509
|
+
|
|
510
|
+
entity.traverse((c) => {
|
|
511
|
+
if (c.name === 'head') {
|
|
512
|
+
c.rotation.set(-rotation.pitch, 0, 0)
|
|
513
|
+
}
|
|
514
|
+
})
|
|
515
|
+
}
|
|
637
516
|
}
|
|
638
517
|
}
|
|
639
518
|
|
|
@@ -1393,8 +1272,20 @@ export class Entities {
|
|
|
1393
1272
|
})
|
|
1394
1273
|
.start()
|
|
1395
1274
|
}
|
|
1396
|
-
|
|
1397
|
-
|
|
1275
|
+
/** World yaw for the whole model: for PlayerObject skins, rotate body to head look dir; head mesh stays yaw-fixed (pitch only). */
|
|
1276
|
+
let targetYaw: number | undefined
|
|
1277
|
+
if (e.playerObject && overrides?.rotation?.head) {
|
|
1278
|
+
const hy = overrides.rotation.head.y
|
|
1279
|
+
const headYawWorld =
|
|
1280
|
+
typeof hy === 'number' && Number.isFinite(hy) ? hy : entity.yaw
|
|
1281
|
+
if (typeof headYawWorld === 'number' && Number.isFinite(headYawWorld)) {
|
|
1282
|
+
targetYaw = headYawWorld
|
|
1283
|
+
}
|
|
1284
|
+
} else if (typeof entity.yaw === 'number' && Number.isFinite(entity.yaw)) {
|
|
1285
|
+
targetYaw = entity.yaw
|
|
1286
|
+
}
|
|
1287
|
+
if (typeof targetYaw === 'number' && Number.isFinite(targetYaw)) {
|
|
1288
|
+
const dy = shortestYawRadians(e.rotation.y, targetYaw)
|
|
1398
1289
|
// Stop previous rotation tween to prevent accumulation (mirror _posTween)
|
|
1399
1290
|
e.userData._rotTween?.stop()
|
|
1400
1291
|
e.userData._rotTween = new TWEEN.Tween(e.rotation)
|
|
@@ -1404,14 +1295,7 @@ export class Entities {
|
|
|
1404
1295
|
|
|
1405
1296
|
if (e?.playerObject && overrides?.rotation?.head) {
|
|
1406
1297
|
const { playerObject } = e
|
|
1407
|
-
|
|
1408
|
-
const headYawWorld =
|
|
1409
|
-
typeof hy === 'number' && Number.isFinite(hy) ? hy : entity.yaw
|
|
1410
|
-
const headYawOffset =
|
|
1411
|
-
typeof headYawWorld === 'number' && typeof entity.yaw === 'number' && Number.isFinite(headYawWorld) && Number.isFinite(entity.yaw)
|
|
1412
|
-
? shortestYawRadians(entity.yaw, headYawWorld)
|
|
1413
|
-
: 0
|
|
1414
|
-
playerObject.skin.head.rotation.y = headYawOffset
|
|
1298
|
+
playerObject.skin.head.rotation.y = 0
|
|
1415
1299
|
|
|
1416
1300
|
const hp = overrides.rotation.head.x
|
|
1417
1301
|
playerObject.skin.head.rotation.x =
|