minecraft-renderer 0.1.92 → 0.1.94

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.
Files changed (43) hide show
  1. package/dist/minecraft-renderer.js +68 -68
  2. package/dist/minecraft-renderer.js.meta.json +1 -1
  3. package/dist/threeWorker.js +522 -522
  4. package/package.json +1 -1
  5. package/src/graphicsBackend/appViewer.ts +4 -3
  6. package/src/graphicsBackend/config.ts +1 -1
  7. package/src/graphicsBackend/types.ts +4 -1
  8. package/src/lib/worldrendererCommon.ts +3 -3
  9. package/src/three/entities.ts +329 -43
  10. package/src/three/entity/EntityMesh.ts +8 -3
  11. package/src/three/entity/animations.js +37 -25
  12. package/src/three/entity/animations.test.ts +249 -0
  13. package/src/three/entity/boatModelRotation.test.ts +29 -0
  14. package/src/three/entity/boatModelRotation.ts +14 -0
  15. package/src/three/entity/boatPaddleAnimation.test.ts +108 -0
  16. package/src/three/entity/boatPaddleAnimation.ts +104 -0
  17. package/src/three/entity/boatPassengerRendering.ts +20 -0
  18. package/src/three/entity/boatPassengerRotation.test.ts +166 -0
  19. package/src/three/entity/boatPassengerRotation.ts +71 -0
  20. package/src/three/entity/boatRenderSetup.test.ts +236 -0
  21. package/src/three/entity/boatRenderSetup.ts +214 -0
  22. package/src/three/entity/entityHeadPose.test.ts +15 -0
  23. package/src/three/entity/entityHeadPose.ts +22 -0
  24. package/src/three/entity/horseEntityScale.test.ts +11 -0
  25. package/src/three/entity/horseEntityScale.ts +9 -0
  26. package/src/three/entity/horseHeadAnimation.test.ts +159 -0
  27. package/src/three/entity/horseHeadAnimation.ts +151 -0
  28. package/src/three/entity/horsePassengerRendering.test.ts +77 -0
  29. package/src/three/entity/interpolationPolicy.test.ts +259 -0
  30. package/src/three/entity/interpolationPolicy.ts +187 -0
  31. package/src/three/entity/localHorseCameraYawLock.test.ts +72 -0
  32. package/src/three/entity/localVehicleRendering.integration.test.ts +247 -0
  33. package/src/three/entity/minecartLocalPassengerRendering.test.ts +208 -0
  34. package/src/three/entity/networkHeadPitchRendering.test.ts +102 -0
  35. package/src/three/entity/networkHeadPitchRendering.ts +44 -0
  36. package/src/three/entity/remoteBoatPassengerRotation.integration.test.ts +227 -0
  37. package/src/three/entity/remoteBoatPassengerRotation.ts +128 -0
  38. package/src/three/entity/vehiclePassengerProduction.test.ts +214 -0
  39. package/src/three/entity/vehiclePassengerRendering.ts +56 -0
  40. package/src/three/entity/vehiclePassengerUpdate.ts +82 -0
  41. package/src/three/graphicsBackendBase.ts +5 -5
  42. package/src/three/graphicsBackendOffThread.ts +2 -2
  43. package/src/three/worldRendererThree.ts +54 -27
@@ -0,0 +1,82 @@
1
+ //@ts-nocheck
2
+ import { isBoatEntityName } from './boatModelRotation'
3
+ import {
4
+ getBoatPassengerWorldPosition,
5
+ getHorsePassengerWorldPosition,
6
+ getMinecartPassengerWorldPosition,
7
+ isRideableHorseEntityName,
8
+ isRideableMinecartEntityName,
9
+ type EntityRenderHints,
10
+ type Vec3Like
11
+ } from './interpolationPolicy'
12
+ import {
13
+ anchorVehiclePassengerPosition,
14
+ isFiniteVec3,
15
+ releaseVehiclePassengerPosition,
16
+ shouldSkipLocalPassengerAnchoring,
17
+ type VehiclePassengerRenderState
18
+ } from './vehiclePassengerRendering'
19
+
20
+ export type VehiclePassengerSceneEntity = VehiclePassengerRenderState & {
21
+ playerObject?: unknown
22
+ originalEntity: { id: number }
23
+ }
24
+
25
+ export type VehiclePassengerVehicle = {
26
+ originalEntity: { id: number | string; name: string; height?: number }
27
+ userData: { renderHints?: EntityRenderHints }
28
+ rotation: { y: number }
29
+ realName?: string
30
+ }
31
+
32
+ export function updateVehiclePassengerPositions(args: {
33
+ entities: Record<string, VehiclePassengerSceneEntity | VehiclePassengerVehicle>
34
+ localPlayer: VehiclePassengerSceneEntity | null
35
+ getWorldPosition: (target: unknown) => Vec3Like | undefined
36
+ }): Set<VehiclePassengerSceneEntity> {
37
+ const attachedPassengers = new Set<VehiclePassengerSceneEntity>()
38
+
39
+ for (const entity of Object.values(args.entities)) {
40
+ const vehicle = entity as VehiclePassengerVehicle
41
+ const renderHints = vehicle.userData.renderHints
42
+ const passengerIds = renderHints?.passengerIds ?? renderHints?.boatPassengerIds
43
+ if (!Array.isArray(passengerIds) || passengerIds.length === 0) continue
44
+
45
+ const vehicleName = vehicle.realName ?? vehicle.originalEntity.name
46
+ const layout = renderHints?.passengerLayout ?? (isBoatEntityName(vehicleName) ? 'boat' : undefined)
47
+ if (layout !== 'boat' && layout !== 'minecart' && layout !== 'horse') continue
48
+ if (layout === 'boat' && !isBoatEntityName(vehicleName)) continue
49
+ if (layout === 'minecart' && !isRideableMinecartEntityName(vehicleName)) continue
50
+ if (layout === 'horse' && !isRideableHorseEntityName(vehicleName)) continue
51
+
52
+ const vehicleWorldPos = args.getWorldPosition(vehicle)
53
+ if (!isFiniteVec3(vehicleWorldPos)) continue
54
+ const vehicleId = String(vehicle.originalEntity.id)
55
+
56
+ for (const [passengerIndex, passengerId] of passengerIds.entries()) {
57
+ const isLocalPassenger = passengerId === args.localPlayer?.originalEntity.id
58
+ const passenger = isLocalPassenger ? args.localPlayer : (args.entities[passengerId] as VehiclePassengerSceneEntity | undefined)
59
+ if (!passenger?.playerObject) continue
60
+ if (passenger === args.localPlayer && shouldSkipLocalPassengerAnchoring(layout)) continue
61
+
62
+ const passengerWorldPos =
63
+ layout === 'minecart'
64
+ ? getMinecartPassengerWorldPosition(vehicleWorldPos)
65
+ : layout === 'horse'
66
+ ? getHorsePassengerWorldPosition(vehicleWorldPos, vehicleName, vehicle.originalEntity.height ?? 1.6)
67
+ : getBoatPassengerWorldPosition(vehicleWorldPos, vehicle.rotation.y, passengerIndex, passengerIds.length)
68
+
69
+ if (!isFiniteVec3(passengerWorldPos)) continue
70
+ anchorVehiclePassengerPosition(passenger, passengerWorldPos, vehicleId)
71
+ attachedPassengers.add(passenger)
72
+ }
73
+ }
74
+
75
+ for (const passenger of [...Object.values(args.entities), ...(args.localPlayer ? [args.localPlayer] : [])] as VehiclePassengerSceneEntity[]) {
76
+ const vehicleId = passenger.userData._passengerVehicleId ?? (passenger.userData._boatPassengerVehicleId as string | undefined)
77
+ if (vehicleId === undefined || attachedPassengers.has(passenger)) continue
78
+ releaseVehiclePassengerPosition(passenger, vehicleId, args.getWorldPosition(passenger))
79
+ }
80
+
81
+ return attachedPassengers
82
+ }
@@ -8,7 +8,7 @@
8
8
 
9
9
  import * as THREE from 'three'
10
10
  import { Vec3 } from 'vec3'
11
- import type { GraphicsBackend, GraphicsInitOptions, DisplayWorldOptions } from '../graphicsBackend'
11
+ import type { GraphicsBackend, GraphicsInitOptions, DisplayWorldOptions, UpdateCameraOptions } from '../graphicsBackend'
12
12
  import { createWorkerProxy, restoreTransferred } from '../lib/workerProxy'
13
13
  import { ResourcesManager } from '../resourcesManager'
14
14
  import { FrameTimingCollector } from '../lib/frameTimingCollector'
@@ -280,10 +280,10 @@ export const createGraphicsBackendBase = () => {
280
280
  }
281
281
  }
282
282
  }),
283
- updateCamera(pos: Vec3 | null, yaw: number, pitch: number) {
283
+ updateCamera(pos: Vec3 | null, yaw: number, pitch: number, options?: UpdateCameraOptions) {
284
284
  // Mark camera update event for frame timing visualization
285
285
  frameTimingCollector?.markCameraUpdate(!pos)
286
- worldRenderer?.setFirstPersonCamera(pos, yaw, pitch)
286
+ worldRenderer?.setFirstPersonCamera(pos, yaw, pitch, options)
287
287
  },
288
288
  get soundSystem() {
289
289
  return worldRenderer?.soundSystem
@@ -311,10 +311,10 @@ export const createGraphicsBackendBase = () => {
311
311
  startWorld,
312
312
  disconnect,
313
313
  setRendering: backend.setRendering,
314
- updateCamera(pos, yaw, pitch) {
314
+ updateCamera(pos, yaw, pitch, options?: UpdateCameraOptions) {
315
315
  const posVec = pos ? new Vec3(pos.x, pos.y, pos.z) : null
316
316
  frameTimingCollector?.markCameraUpdate(!posVec)
317
- backend.updateCamera(posVec, yaw, pitch)
317
+ backend.updateCamera(posVec, yaw, pitch, options)
318
318
  },
319
319
  async callBackendMethod<K extends keyof ThreeJsBackendMethods>(
320
320
  method: K,
@@ -154,8 +154,8 @@ export const createGraphicsBackendOffThread: GraphicsBackendLoader = async initO
154
154
  setRendering(rendering) {
155
155
  proxy.setRendering(rendering)
156
156
  },
157
- updateCamera(pos, yaw, pitch) {
158
- proxy.updateCamera(pos ? { x: pos.x, y: pos.y, z: pos.z } : null, yaw, pitch)
157
+ updateCamera(pos, yaw, pitch, options) {
158
+ proxy.updateCamera(pos ? { x: pos.x, y: pos.y, z: pos.z } : null, yaw, pitch, options)
159
159
  },
160
160
  soundSystem: undefined,
161
161
  backendMethods: backendMethodsProxy
@@ -16,11 +16,18 @@ import { getMyHand } from './hand'
16
16
  import { createHoldingBlock } from './holdingBlockFactory'
17
17
  import type { IHoldingBlock } from './holdingBlockTypes'
18
18
  import { getMesh } from './entity/EntityMesh'
19
+ import { resolveEntityHeadPose } from './entity/entityHeadPose'
19
20
  import { armorModel } from './entity/armorModels'
20
21
  import { disposeObject, loadThreeJsTextureFromBitmap } from './threeJsUtils'
21
22
  import { CursorBlock } from './world/cursorBlock'
22
23
  import { getItemUv } from './appShared'
23
24
  import { Entities } from './entities'
25
+ import {
26
+ getCameraMovementTweenDurationMs,
27
+ shouldRestartCameraPositionTween,
28
+ type CameraMovementMode,
29
+ type UpdateCameraOptions
30
+ } from './entity/interpolationPolicy'
24
31
  import { ThreeJsSound } from './threeJsSound'
25
32
  import { CameraShake } from './cameraShake'
26
33
  import { ThreeJsMedia } from './threeJsMedia'
@@ -160,6 +167,8 @@ export class WorldRendererThree extends WorldRendererCommon {
160
167
 
161
168
  private currentPosTween?: tweenJs.Tween<{ x: number; y: number; z: number }>
162
169
  private currentRotTween?: tweenJs.Tween<{ pitch: number; yaw: number }>
170
+ private currentCameraTarget: { x: number; y: number; z: number } | null = null
171
+ private currentCameraMovementMode: CameraMovementMode | null = null
163
172
 
164
173
  // Pre-allocated objects for getThirdPersonCamera (avoid per-frame allocs)
165
174
  private readonly _tpDirection = new THREE.Vector3()
@@ -492,17 +501,18 @@ export class WorldRendererThree extends WorldRendererCommon {
492
501
  }
493
502
 
494
503
  updateEntity(e, isPosUpdate = false) {
504
+ const headPose = resolveEntityHeadPose(e)
495
505
  const overrides = {
496
506
  rotation: {
497
507
  head: {
498
- x: e.headPitch ?? e.pitch,
499
- y: e.headYaw,
508
+ x: headPose.pitch,
509
+ y: headPose.headYaw,
500
510
  z: 0
501
511
  }
502
512
  }
503
513
  }
504
514
  if (isPosUpdate) {
505
- this.entities.updateEntityPosition(e, false, overrides)
515
+ this.entities.updateEntityPosition(e, false, overrides, e.headRotationOnly === true)
506
516
  } else {
507
517
  this.entities.update(e, overrides)
508
518
  }
@@ -584,6 +594,9 @@ export class WorldRendererThree extends WorldRendererCommon {
584
594
  this.onReactiveConfigUpdated('futuristicReveal', () => {
585
595
  this.updateModulesFromConfig()
586
596
  })
597
+ this.onReactiveDebugUpdated('disableEntities', () => {
598
+ this.entities.syncSceneAttachment()
599
+ })
587
600
 
588
601
  let currentHandRenderer = this.displayOptions.inWorldRenderingConfig.handRenderer
589
602
  this.onReactiveConfigUpdated('handRenderer', value => {
@@ -990,10 +1003,10 @@ export class WorldRendererThree extends WorldRendererCommon {
990
1003
  }
991
1004
  }
992
1005
 
993
- setFirstPersonCamera(pos: Vec3 | null, yaw: number, pitch: number) {
1006
+ setFirstPersonCamera(pos: Vec3 | null, yaw: number, pitch: number, options?: UpdateCameraOptions) {
994
1007
  const yOffset = this.playerStateReactive.eyeHeight
995
1008
 
996
- this.updateCamera(pos?.offset(0, yOffset, 0) ?? null, yaw, pitch)
1009
+ this.updateCamera(pos?.offset(0, yOffset, 0) ?? null, yaw, pitch, options)
997
1010
  // this.media.tryIntersectMedia()
998
1011
  this.updateCameraSectionPos()
999
1012
  }
@@ -1149,34 +1162,50 @@ export class WorldRendererThree extends WorldRendererCommon {
1149
1162
  }
1150
1163
  }
1151
1164
 
1152
- updateCamera(pos: Vec3 | null, yaw: number, pitch: number): void {
1165
+ updateCamera(pos: Vec3 | null, yaw: number, pitch: number, options?: UpdateCameraOptions): void {
1153
1166
  // Skip position/rotation updates if cinematic script is running
1154
1167
  if (this.cinimaticScript.running) {
1155
1168
  return
1156
1169
  }
1157
1170
 
1158
- // if (this.freeFlyMode) {
1159
- // pos = this.freeFlyState.position
1160
- // pitch = this.freeFlyState.pitch
1161
- // yaw = this.freeFlyState.yaw
1162
- // }
1163
-
1164
1171
  if (pos) {
1165
1172
  if (this.renderer.xr.isPresenting) {
1166
1173
  pos.y -= this.camera.position.y // Fix Y position of camera in world
1167
1174
  }
1168
1175
 
1169
- this.currentPosTween?.stop()
1170
- // Use instant camera updates (0 delay) in playground mode when camera controls are enabled
1171
- const tweenDelay = this.displayOptions.inWorldRenderingConfig.instantCameraUpdate ? 0 : this.playerStateUtils.isSpectatingEntity() ? 150 : 50
1172
- this.currentPosTween = new tweenJs.Tween(this.cameraWorldPos)
1173
- .to({ x: pos.x, y: pos.y, z: pos.z }, tweenDelay)
1174
- .onUpdate(() => {
1175
- this.sceneOrigin.update(this.cameraWorldPos.x, this.cameraWorldPos.y, this.cameraWorldPos.z)
1176
+ const movementMode: CameraMovementMode = this.playerStateUtils.isSpectatingEntity() ? 'spectating' : (options?.movementMode ?? 'local-player')
1177
+ const instant = options?.instant === true || this.displayOptions.inWorldRenderingConfig.instantCameraUpdate === true
1178
+ const target = { x: pos.x, y: pos.y, z: pos.z }
1179
+ const restartTween = shouldRestartCameraPositionTween({
1180
+ target,
1181
+ currentTarget: this.currentCameraTarget,
1182
+ movementMode,
1183
+ previousMovementMode: this.currentCameraMovementMode,
1184
+ instant
1185
+ })
1186
+ const tweenDelay = getCameraMovementTweenDurationMs(movementMode, instant)
1187
+
1188
+ if (restartTween) {
1189
+ this.currentCameraTarget = { ...target }
1190
+ this.currentCameraMovementMode = movementMode
1191
+ this.currentPosTween?.stop()
1192
+ if (instant || tweenDelay === 0) {
1193
+ this.cameraWorldPos.x = target.x
1194
+ this.cameraWorldPos.y = target.y
1195
+ this.cameraWorldPos.z = target.z
1196
+ this.sceneOrigin.update(target.x, target.y, target.z)
1176
1197
  this.cameraObject.position.set(0, 0, 0)
1177
- })
1178
- .start()
1179
- // this.freeFlyState.position = pos
1198
+ this.currentPosTween = undefined
1199
+ } else {
1200
+ this.currentPosTween = new tweenJs.Tween(this.cameraWorldPos)
1201
+ .to(target, tweenDelay)
1202
+ .onUpdate(() => {
1203
+ this.sceneOrigin.update(this.cameraWorldPos.x, this.cameraWorldPos.y, this.cameraWorldPos.z)
1204
+ this.cameraObject.position.set(0, 0, 0)
1205
+ })
1206
+ .start()
1207
+ }
1208
+ }
1180
1209
  }
1181
1210
 
1182
1211
  if (this.playerStateUtils.isSpectatingEntity()) {
@@ -1363,11 +1392,9 @@ export class WorldRendererThree extends WorldRendererCommon {
1363
1392
  this.chunkMeshManager.clearCullDirty()
1364
1393
  }
1365
1394
  this.chunkMeshManager.updateCaveCullingDebug(this.reactiveDebugParams.caveCullingDebug, smartCull)
1366
- if (!this.reactiveDebugParams.disableEntities) {
1367
- const entitiesStart = performance.now()
1368
- this.entities.render()
1369
- entitiesRenderMs = performance.now() - entitiesStart
1370
- }
1395
+ const entitiesStart = performance.now()
1396
+ this.entities.render()
1397
+ entitiesRenderMs = performance.now() - entitiesStart
1371
1398
  this.chunkMeshManager.sortVisibleBlendSections(camX, camY, camZ)
1372
1399
  if (!didBlendAllAttrUpload && globalLegacyBlendBuffer?.hasPendingIndexUploads()) {
1373
1400
  globalLegacyBlendBuffer.uploadDirtyIndexRange()