minecraft-renderer 0.1.0
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 +297 -0
- package/dist/index.html +83 -0
- package/dist/static/image/arrow.6f27b59f.png +0 -0
- package/dist/static/image/blocksAtlasLatest.7850afa3.png +0 -0
- package/dist/static/image/blocksAtlasLegacy.5c76823d.png +0 -0
- package/dist/static/image/itemsAtlasLatest.36036f95.png +0 -0
- package/dist/static/image/itemsAtlasLegacy.dcb1b58d.png +0 -0
- package/dist/static/image/tipped_arrow.6f27b59f.png +0 -0
- package/dist/static/js/365.f05233ab.js +8462 -0
- package/dist/static/js/365.f05233ab.js.LICENSE.txt +52 -0
- package/dist/static/js/async/738.efa27644.js +1 -0
- package/dist/static/js/index.092ec5be.js +56 -0
- package/dist/static/js/lib-polyfill.98986ac5.js +1 -0
- package/dist/static/js/lib-react.5c9129e0.js +2 -0
- package/dist/static/js/lib-react.5c9129e0.js.LICENSE.txt +39 -0
- package/package.json +104 -0
- package/src/assets/destroy_stage_0.png +0 -0
- package/src/assets/destroy_stage_1.png +0 -0
- package/src/assets/destroy_stage_2.png +0 -0
- package/src/assets/destroy_stage_3.png +0 -0
- package/src/assets/destroy_stage_4.png +0 -0
- package/src/assets/destroy_stage_5.png +0 -0
- package/src/assets/destroy_stage_6.png +0 -0
- package/src/assets/destroy_stage_7.png +0 -0
- package/src/assets/destroy_stage_8.png +0 -0
- package/src/assets/destroy_stage_9.png +0 -0
- package/src/examples/README.md +146 -0
- package/src/examples/appViewerExample.ts +205 -0
- package/src/examples/initialMenuStart.ts +161 -0
- package/src/graphicsBackend/appViewer.ts +297 -0
- package/src/graphicsBackend/config.ts +119 -0
- package/src/graphicsBackend/index.ts +10 -0
- package/src/graphicsBackend/playerState.ts +61 -0
- package/src/graphicsBackend/types.ts +143 -0
- package/src/index.ts +97 -0
- package/src/lib/DebugGui.ts +190 -0
- package/src/lib/animationController.ts +85 -0
- package/src/lib/buildSharedConfig.mjs +1 -0
- package/src/lib/cameraBobbing.ts +94 -0
- package/src/lib/canvas2DOverlay.example.ts +361 -0
- package/src/lib/canvas2DOverlay.quickstart.ts +242 -0
- package/src/lib/canvas2DOverlay.ts +381 -0
- package/src/lib/cleanupDecorator.ts +29 -0
- package/src/lib/createPlayerObject.ts +55 -0
- package/src/lib/frameTimingCollector.ts +164 -0
- package/src/lib/guiRenderer.ts +283 -0
- package/src/lib/items.ts +140 -0
- package/src/lib/mesherlogReader.ts +131 -0
- package/src/lib/moreBlockDataGenerated.json +714 -0
- package/src/lib/preflatMap.json +1741 -0
- package/src/lib/simpleUtils.ts +40 -0
- package/src/lib/smoothSwitcher.ts +168 -0
- package/src/lib/spiral.ts +29 -0
- package/src/lib/ui/newStats.ts +120 -0
- package/src/lib/utils/proxy.ts +23 -0
- package/src/lib/utils/skins.ts +63 -0
- package/src/lib/utils.ts +76 -0
- package/src/lib/workerProxy.ts +342 -0
- package/src/lib/worldrendererCommon.ts +1088 -0
- package/src/mesher/mesher.ts +253 -0
- package/src/mesher/models.ts +769 -0
- package/src/mesher/modelsGeometryCommon.ts +142 -0
- package/src/mesher/shared.ts +80 -0
- package/src/mesher/standaloneRenderer.ts +270 -0
- package/src/mesher/test/a.ts +3 -0
- package/src/mesher/test/mesherTester.ts +76 -0
- package/src/mesher/test/playground.ts +19 -0
- package/src/mesher/test/test-perf.ts +74 -0
- package/src/mesher/test/tests.test.ts +56 -0
- package/src/mesher/world.ts +294 -0
- package/src/mesher/worldConstants.ts +1 -0
- package/src/modules/index.ts +11 -0
- package/src/modules/starfield.ts +313 -0
- package/src/modules/types.ts +110 -0
- package/src/playerState/playerState.ts +78 -0
- package/src/playerState/types.ts +36 -0
- package/src/playground/allEntitiesDebug.ts +170 -0
- package/src/playground/baseScene.ts +587 -0
- package/src/playground/mobileControls.tsx +268 -0
- package/src/playground/playground.html +83 -0
- package/src/playground/playground.ts +11 -0
- package/src/playground/playgroundUi.tsx +140 -0
- package/src/playground/reactUtils.ts +71 -0
- package/src/playground/scenes/allEntities.ts +13 -0
- package/src/playground/scenes/entities.ts +37 -0
- package/src/playground/scenes/floorRandom.ts +33 -0
- package/src/playground/scenes/frequentUpdates.ts +148 -0
- package/src/playground/scenes/geometryExport.ts +142 -0
- package/src/playground/scenes/index.ts +12 -0
- package/src/playground/scenes/lightingStarfield.ts +40 -0
- package/src/playground/scenes/main.ts +313 -0
- package/src/playground/scenes/railsCobweb.ts +14 -0
- package/src/playground/scenes/rotationIssue.ts +7 -0
- package/src/playground/scenes/slabsOptimization.ts +16 -0
- package/src/playground/scenes/transparencyIssue.ts +11 -0
- package/src/playground/shared.ts +79 -0
- package/src/resourcesManager/index.ts +5 -0
- package/src/resourcesManager/resourcesManager.ts +314 -0
- package/src/shims/minecraftData.ts +41 -0
- package/src/sign-renderer/index.html +21 -0
- package/src/sign-renderer/index.ts +216 -0
- package/src/sign-renderer/noop.js +1 -0
- package/src/sign-renderer/playground.ts +38 -0
- package/src/sign-renderer/tests.test.ts +69 -0
- package/src/sign-renderer/vite.config.ts +10 -0
- package/src/three/appShared.ts +75 -0
- package/src/three/bannerRenderer.ts +275 -0
- package/src/three/cameraShake.ts +120 -0
- package/src/three/cinimaticScript.ts +350 -0
- package/src/three/documentRenderer.ts +491 -0
- package/src/three/entities.ts +1580 -0
- package/src/three/entity/EntityMesh.ts +707 -0
- package/src/three/entity/animations.js +171 -0
- package/src/three/entity/armorModels.json +204 -0
- package/src/three/entity/armorModels.ts +36 -0
- package/src/three/entity/entities.json +6230 -0
- package/src/three/entity/exportedModels.js +38 -0
- package/src/three/entity/externalTextures.json +1 -0
- package/src/three/entity/models/allay.obj +325 -0
- package/src/three/entity/models/arrow.obj +60 -0
- package/src/three/entity/models/axolotl.obj +509 -0
- package/src/three/entity/models/blaze.obj +601 -0
- package/src/three/entity/models/boat.obj +417 -0
- package/src/three/entity/models/camel.obj +1061 -0
- package/src/three/entity/models/cat.obj +509 -0
- package/src/three/entity/models/chicken.obj +371 -0
- package/src/three/entity/models/cod.obj +371 -0
- package/src/three/entity/models/creeper.obj +279 -0
- package/src/three/entity/models/dolphin.obj +371 -0
- package/src/three/entity/models/ender_dragon.obj +2993 -0
- package/src/three/entity/models/enderman.obj +325 -0
- package/src/three/entity/models/endermite.obj +187 -0
- package/src/three/entity/models/fox.obj +463 -0
- package/src/three/entity/models/frog.obj +739 -0
- package/src/three/entity/models/ghast.obj +463 -0
- package/src/three/entity/models/goat.obj +601 -0
- package/src/three/entity/models/guardian.obj +1015 -0
- package/src/three/entity/models/horse.obj +1061 -0
- package/src/three/entity/models/llama.obj +509 -0
- package/src/three/entity/models/minecart.obj +233 -0
- package/src/three/entity/models/parrot.obj +509 -0
- package/src/three/entity/models/piglin.obj +739 -0
- package/src/three/entity/models/pillager.obj +371 -0
- package/src/three/entity/models/rabbit.obj +555 -0
- package/src/three/entity/models/sheep.obj +555 -0
- package/src/three/entity/models/shulker.obj +141 -0
- package/src/three/entity/models/sniffer.obj +693 -0
- package/src/three/entity/models/spider.obj +509 -0
- package/src/three/entity/models/tadpole.obj +95 -0
- package/src/three/entity/models/turtle.obj +371 -0
- package/src/three/entity/models/vex.obj +325 -0
- package/src/three/entity/models/villager.obj +509 -0
- package/src/three/entity/models/warden.obj +463 -0
- package/src/three/entity/models/witch.obj +647 -0
- package/src/three/entity/models/wolf.obj +509 -0
- package/src/three/entity/models/zombie_villager.obj +463 -0
- package/src/three/entity/objModels.js +1 -0
- package/src/three/fireworks.ts +661 -0
- package/src/three/fireworksRenderer.ts +434 -0
- package/src/three/globals.d.ts +7 -0
- package/src/three/graphicsBackend.ts +274 -0
- package/src/three/graphicsBackendOffThread.ts +107 -0
- package/src/three/hand.ts +89 -0
- package/src/three/holdingBlock.ts +926 -0
- package/src/three/index.ts +20 -0
- package/src/three/itemMesh.ts +427 -0
- package/src/three/modules.d.ts +14 -0
- package/src/three/panorama.ts +308 -0
- package/src/three/panoramaShared.ts +1 -0
- package/src/three/renderSlot.ts +82 -0
- package/src/three/skyboxRenderer.ts +406 -0
- package/src/three/starField.ts +13 -0
- package/src/three/threeJsMedia.ts +731 -0
- package/src/three/threeJsMethods.ts +15 -0
- package/src/three/threeJsParticles.ts +160 -0
- package/src/three/threeJsSound.ts +95 -0
- package/src/three/threeJsUtils.ts +90 -0
- package/src/three/waypointSprite.ts +435 -0
- package/src/three/waypoints.ts +163 -0
- package/src/three/world/cursorBlock.ts +172 -0
- package/src/three/world/vr.ts +257 -0
- package/src/three/worldGeometryExport.ts +259 -0
- package/src/three/worldGeometryHandler.ts +279 -0
- package/src/three/worldRendererThree.ts +1381 -0
- package/src/worldView/index.ts +6 -0
- package/src/worldView/types.ts +66 -0
- package/src/worldView/worldView.ts +424 -0
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Three.js Graphics Backend - Main entry point for Three.js WebGL rendering.
|
|
3
|
+
*
|
|
4
|
+
* This module provides the GraphicsBackend implementation using Three.js.
|
|
5
|
+
* It creates and manages:
|
|
6
|
+
* - WebGL renderer (via DocumentRenderer)
|
|
7
|
+
* - World renderer (via WorldRendererThree - to be implemented)
|
|
8
|
+
* - Scene management
|
|
9
|
+
* - Camera updates
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import * as THREE from 'three'
|
|
13
|
+
import { Vec3 } from 'vec3'
|
|
14
|
+
import type { GraphicsBackendLoader, GraphicsBackend, GraphicsInitOptions, DisplayWorldOptions } from '@/graphicsBackend'
|
|
15
|
+
import { createWorkerProxy, restoreTransferred } from '@/lib/workerProxy'
|
|
16
|
+
import { ResourcesManager } from '@/resourcesManager'
|
|
17
|
+
// import { WorldViewWorker } from '@/worldView'
|
|
18
|
+
import { FrameTimingCollector } from '@/lib/frameTimingCollector'
|
|
19
|
+
import { WorldRendererThree } from './worldRendererThree'
|
|
20
|
+
import { DocumentRenderer, isWebWorker, ThreeRendererMainData } from './documentRenderer'
|
|
21
|
+
import { PanoramaRenderer } from './panorama'
|
|
22
|
+
|
|
23
|
+
// Disable Three.js color management for compatibility
|
|
24
|
+
THREE.ColorManagement.enabled = false
|
|
25
|
+
// Enable Three.js in global scope for debugging
|
|
26
|
+
globalThis.THREE = THREE
|
|
27
|
+
|
|
28
|
+
const getBackendMethods = (worldRenderer: WorldRendererThree): any => {
|
|
29
|
+
return {
|
|
30
|
+
updateMap: worldRenderer.entities.updateMap.bind(worldRenderer.entities),
|
|
31
|
+
updateCustomBlock: worldRenderer.updateCustomBlock.bind(worldRenderer),
|
|
32
|
+
getBlockInfo: worldRenderer.getBlockInfo.bind(worldRenderer),
|
|
33
|
+
playEntityAnimation: worldRenderer.entities.playAnimation.bind(worldRenderer.entities),
|
|
34
|
+
damageEntity: worldRenderer.entities.handleDamageEvent.bind(worldRenderer.entities),
|
|
35
|
+
updatePlayerSkin: worldRenderer.entities.updatePlayerSkin.bind(worldRenderer.entities),
|
|
36
|
+
changeHandSwingingState: worldRenderer.changeHandSwingingState.bind(worldRenderer),
|
|
37
|
+
getHighestBlocks: worldRenderer.getHighestBlocks.bind(worldRenderer),
|
|
38
|
+
reloadWorld: worldRenderer.reloadWorld.bind(worldRenderer),
|
|
39
|
+
updateEntityModel: worldRenderer.entities.updateEntityModel.bind(worldRenderer.entities),
|
|
40
|
+
playEntityModelAnimation: worldRenderer.entities.playEntityModelAnimation.bind(worldRenderer.entities),
|
|
41
|
+
addMedia: worldRenderer.media.addMedia.bind(worldRenderer.media),
|
|
42
|
+
destroyMedia: worldRenderer.media.destroyMedia.bind(worldRenderer.media),
|
|
43
|
+
setControlMode: worldRenderer.media.setControlMode.bind(worldRenderer.media),
|
|
44
|
+
setVideoPlaying: worldRenderer.media.setVideoPlaying.bind(worldRenderer.media),
|
|
45
|
+
setVideoSeeking: worldRenderer.media.setVideoSeeking.bind(worldRenderer.media),
|
|
46
|
+
setVideoVolume: worldRenderer.media.setVideoVolume.bind(worldRenderer.media),
|
|
47
|
+
setVideoSpeed: worldRenderer.media.setVideoSpeed.bind(worldRenderer.media),
|
|
48
|
+
handleUserClick: worldRenderer.media.handleUserClick.bind(worldRenderer.media),
|
|
49
|
+
addSectionAnimation(id: string, animation: typeof worldRenderer.sectionsOffsetsAnimations[string]) {
|
|
50
|
+
worldRenderer.sectionsOffsetsAnimations[id] = animation
|
|
51
|
+
},
|
|
52
|
+
removeSectionAnimation(id: string) {
|
|
53
|
+
delete worldRenderer.sectionsOffsetsAnimations[id]
|
|
54
|
+
},
|
|
55
|
+
shakeFromDamage: worldRenderer.cameraShake.shakeFromDamage.bind(worldRenderer.cameraShake),
|
|
56
|
+
onPageInteraction: worldRenderer.media.onPageInteraction.bind(worldRenderer.media),
|
|
57
|
+
downloadMesherLog: worldRenderer.downloadMesherLog.bind(worldRenderer),
|
|
58
|
+
// Fireworks methods
|
|
59
|
+
explodeFirework: worldRenderer.fireworksLegacy.explode.bind(worldRenderer.fireworksLegacy),
|
|
60
|
+
explodeFireworkFacingCamera: worldRenderer.fireworksLegacy.explodeFacingCamera.bind(worldRenderer.fireworksLegacy),
|
|
61
|
+
addWaypoint: worldRenderer.waypoints.addWaypoint.bind(worldRenderer.waypoints),
|
|
62
|
+
removeWaypoint: worldRenderer.waypoints.removeWaypoint.bind(worldRenderer.waypoints),
|
|
63
|
+
// Cinematic script methods
|
|
64
|
+
startCinimaticScript: worldRenderer.cinimaticScript.startScript.bind(worldRenderer.cinimaticScript),
|
|
65
|
+
stopCinimaticScript: worldRenderer.cinimaticScript.stopScript.bind(worldRenderer.cinimaticScript),
|
|
66
|
+
launchFirework: worldRenderer.fireworks.launchFirework.bind(worldRenderer.fireworks),
|
|
67
|
+
// New method for updating skybox
|
|
68
|
+
setSkyboxImage: worldRenderer.skyboxRenderer.setSkyboxImage.bind(worldRenderer.skyboxRenderer),
|
|
69
|
+
async loadGeometryExport(exportData: any) {
|
|
70
|
+
// Import dynamically to avoid circular dependencies
|
|
71
|
+
const { applyWorldGeometryExport } = await import('./worldGeometryExport')
|
|
72
|
+
return applyWorldGeometryExport(worldRenderer, exportData)
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export type ThreeJsBackendMethods = ReturnType<typeof getBackendMethods>
|
|
78
|
+
|
|
79
|
+
const initOptionsRestorers = [
|
|
80
|
+
ResourcesManager,
|
|
81
|
+
// WorldDataEmitterWorker
|
|
82
|
+
]
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Creates the base graphics backend with core functionality.
|
|
86
|
+
*/
|
|
87
|
+
export const createGraphicsBackendBase = () => {
|
|
88
|
+
// Private state
|
|
89
|
+
let initOptions!: GraphicsInitOptions
|
|
90
|
+
let documentRenderer: DocumentRenderer | null = null
|
|
91
|
+
let panoramaRenderer: PanoramaRenderer | null = null
|
|
92
|
+
let worldRenderer: WorldRendererThree | null = null
|
|
93
|
+
let frameTimingCollector: FrameTimingCollector | null = null
|
|
94
|
+
|
|
95
|
+
const init = (initOptionsArg: GraphicsInitOptions, mainData?: ThreeRendererMainData) => {
|
|
96
|
+
if (isWebWorker) {
|
|
97
|
+
initOptions = restoreTransferred(initOptionsArg, initOptionsRestorers, globalThis as unknown as Worker)
|
|
98
|
+
} else {
|
|
99
|
+
initOptions = initOptionsArg
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
documentRenderer = new DocumentRenderer(initOptions, mainData?.canvas)
|
|
103
|
+
; (globalThis as any).renderer = documentRenderer.renderer
|
|
104
|
+
; (globalThis as any).documentRenderer = documentRenderer
|
|
105
|
+
; (globalThis as any).threeJsBackend = backend
|
|
106
|
+
; (globalThis as any).resourcesManager = initOptions.resourcesManager
|
|
107
|
+
|
|
108
|
+
callModsMethod('default', backend)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const startPanorama = async () => {
|
|
112
|
+
if (!documentRenderer) throw new Error('Document renderer not initialized')
|
|
113
|
+
if (worldRenderer) return
|
|
114
|
+
|
|
115
|
+
if (!panoramaRenderer) {
|
|
116
|
+
panoramaRenderer = new PanoramaRenderer(documentRenderer, initOptions, !!process.env.SINGLE_FILE_BUILD_MODE)
|
|
117
|
+
; (globalThis as any).panoramaRenderer = panoramaRenderer
|
|
118
|
+
|
|
119
|
+
callModsMethod('panoramaCreated', panoramaRenderer)
|
|
120
|
+
await panoramaRenderer.start()
|
|
121
|
+
callModsMethod('panoramaReady', panoramaRenderer)
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const startWorld = async (displayOptionsArg: DisplayWorldOptions) => {
|
|
126
|
+
const displayOptions: DisplayWorldOptions = isWebWorker ? restoreTransferred(displayOptionsArg, initOptionsRestorers, globalThis as unknown as Worker) : displayOptionsArg
|
|
127
|
+
|
|
128
|
+
if (!documentRenderer) throw new Error('Document renderer not initialized')
|
|
129
|
+
|
|
130
|
+
documentRenderer.nonReactiveState = displayOptions.nonReactiveState
|
|
131
|
+
|
|
132
|
+
if (panoramaRenderer) {
|
|
133
|
+
panoramaRenderer.dispose()
|
|
134
|
+
panoramaRenderer = null
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
worldRenderer = new WorldRendererThree(documentRenderer.renderer, initOptions, displayOptions)
|
|
138
|
+
|
|
139
|
+
await worldRenderer.worldReadyPromise
|
|
140
|
+
|
|
141
|
+
frameTimingCollector = new FrameTimingCollector(displayOptions.nonReactiveState)
|
|
142
|
+
; (globalThis as any).frameTimingCollector = frameTimingCollector
|
|
143
|
+
|
|
144
|
+
const originalRender = documentRenderer.render
|
|
145
|
+
|
|
146
|
+
documentRenderer.render = function (sizeChanged: boolean) {
|
|
147
|
+
originalRender.call(this, sizeChanged)
|
|
148
|
+
frameTimingCollector?.markFrameStart()
|
|
149
|
+
|
|
150
|
+
if (!displayOptions.inWorldRenderingConfig.paused) {
|
|
151
|
+
worldRenderer?.render(sizeChanged)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
frameTimingCollector?.markFrameEnd()
|
|
155
|
+
frameTimingCollector?.markFrameDisplay()
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
documentRenderer.inWorldRenderingConfig = displayOptions.inWorldRenderingConfig
|
|
159
|
+
|
|
160
|
+
; (globalThis as any).world = worldRenderer
|
|
161
|
+
|
|
162
|
+
callModsMethod('worldReady', worldRenderer)
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const disconnect = () => {
|
|
166
|
+
if (panoramaRenderer) {
|
|
167
|
+
panoramaRenderer.dispose()
|
|
168
|
+
panoramaRenderer = null
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (documentRenderer) {
|
|
172
|
+
documentRenderer.dispose()
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (worldRenderer) {
|
|
176
|
+
worldRenderer.destroy()
|
|
177
|
+
worldRenderer = null
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Public interface
|
|
182
|
+
const backend: GraphicsBackend = {
|
|
183
|
+
id: 'threejs',
|
|
184
|
+
displayName: `three.js ${THREE.REVISION}`,
|
|
185
|
+
startPanorama,
|
|
186
|
+
startWorld,
|
|
187
|
+
disconnect,
|
|
188
|
+
setRendering(rendering) {
|
|
189
|
+
documentRenderer!.setPaused(!rendering)
|
|
190
|
+
if (worldRenderer) worldRenderer.renderingActive = rendering
|
|
191
|
+
},
|
|
192
|
+
getDebugOverlay: () => ({
|
|
193
|
+
get entitiesString() {
|
|
194
|
+
return worldRenderer?.entities.getDebugString()
|
|
195
|
+
},
|
|
196
|
+
}),
|
|
197
|
+
updateCamera(pos: Vec3 | null, yaw: number, pitch: number) {
|
|
198
|
+
// Mark camera update event for frame timing visualization
|
|
199
|
+
frameTimingCollector?.markCameraUpdate(!pos)
|
|
200
|
+
worldRenderer?.setFirstPersonCamera(pos, yaw, pitch)
|
|
201
|
+
},
|
|
202
|
+
get soundSystem() {
|
|
203
|
+
return worldRenderer?.soundSystem
|
|
204
|
+
},
|
|
205
|
+
get backendMethods() {
|
|
206
|
+
if (!worldRenderer) return undefined
|
|
207
|
+
return getBackendMethods(worldRenderer)
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return {
|
|
212
|
+
main: {
|
|
213
|
+
init,
|
|
214
|
+
backend
|
|
215
|
+
},
|
|
216
|
+
workerProxy() {
|
|
217
|
+
return createWorkerProxy({
|
|
218
|
+
init(initOptionsArg: GraphicsInitOptions, canvas: OffscreenCanvas) {
|
|
219
|
+
init(initOptionsArg, { canvas })
|
|
220
|
+
},
|
|
221
|
+
updateSizeExternal(width: number, height: number, pixelRatio: number) {
|
|
222
|
+
documentRenderer?.updateSizeExternal(width, height, pixelRatio)
|
|
223
|
+
},
|
|
224
|
+
startPanorama,
|
|
225
|
+
startWorld,
|
|
226
|
+
disconnect,
|
|
227
|
+
setRendering: backend.setRendering,
|
|
228
|
+
updateCamera(pos, yaw, pitch) {
|
|
229
|
+
const posVec = pos ? new Vec3(pos.x, pos.y, pos.z) : null
|
|
230
|
+
frameTimingCollector?.markCameraUpdate(!posVec)
|
|
231
|
+
backend.updateCamera(posVec, yaw, pitch)
|
|
232
|
+
},
|
|
233
|
+
async callBackendMethod<K extends keyof ThreeJsBackendMethods>(
|
|
234
|
+
method: K,
|
|
235
|
+
...args: Parameters<ThreeJsBackendMethods[K]>
|
|
236
|
+
): Promise<ReturnType<ThreeJsBackendMethods[K]> extends Promise<infer R> ? R : ReturnType<ThreeJsBackendMethods[K]>> {
|
|
237
|
+
if (!worldRenderer) {
|
|
238
|
+
throw new Error('World renderer not initialized')
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const methods = getBackendMethods(worldRenderer)
|
|
242
|
+
const target = methods[method]
|
|
243
|
+
|
|
244
|
+
if (!target) {
|
|
245
|
+
throw new Error(`Backend method ${String(method)} is unavailable`)
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
return target(...args)
|
|
249
|
+
}
|
|
250
|
+
})
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
const createGraphicsBackend = (initOptions: GraphicsInitOptions) => {
|
|
256
|
+
const { main } = createGraphicsBackendBase()
|
|
257
|
+
main.init(initOptions)
|
|
258
|
+
return main.backend
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
const callModsMethod = (method: string, ...args: any[]) => {
|
|
262
|
+
for (const mod of Object.values((globalThis.loadedMods ?? {}) as Record<string, any>)) {
|
|
263
|
+
try {
|
|
264
|
+
mod.threeJsBackendModule?.[method]?.(...args)
|
|
265
|
+
} catch (err) {
|
|
266
|
+
const errorMessage = `[mod three.js] Error calling ${method} on ${mod.name}: ${err}`
|
|
267
|
+
throw new Error(errorMessage)
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
createGraphicsBackend.id = 'threejs'
|
|
273
|
+
|
|
274
|
+
export default createGraphicsBackend
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import * as THREE from 'three'
|
|
2
|
+
import { GraphicsBackend, GraphicsBackendLoader } from '@/graphicsBackend'
|
|
3
|
+
import { useWorkerProxy, deepPrepareForTransfer, findProblemTransfer } from '@/lib/workerProxy'
|
|
4
|
+
import { initMesherWorker, meshersSendMcData } from '@/lib/worldrendererCommon'
|
|
5
|
+
import { dynamicMcDataFiles } from '@/lib/buildSharedConfig.mjs'
|
|
6
|
+
import { addNewStat } from '@/lib/ui/newStats'
|
|
7
|
+
import { createGraphicsBackendBase, type ThreeJsBackendMethods } from './graphicsBackend'
|
|
8
|
+
import { addCanvasForWorker } from './documentRenderer'
|
|
9
|
+
|
|
10
|
+
export const createGraphicsBackendOffThread: GraphicsBackendLoader = async (initOptions) => {
|
|
11
|
+
const worker = initMesherWorker(() => { })
|
|
12
|
+
const promise = new Promise(resolve => {
|
|
13
|
+
worker.onmessage = ({ data }) => {
|
|
14
|
+
if (data.type === 'sideControlTookOver') {
|
|
15
|
+
resolve(data)
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
})
|
|
19
|
+
worker.postMessage({ type: 'sideControl', value: 'graphicsBackendThree' })
|
|
20
|
+
await promise
|
|
21
|
+
type WorkerType = ReturnType<ReturnType<typeof createGraphicsBackendBase>['workerProxy']>
|
|
22
|
+
|
|
23
|
+
const proxy = useWorkerProxy<WorkerType>(worker)
|
|
24
|
+
const canvas = addCanvasForWorker()
|
|
25
|
+
canvas.onSizeChanged((w, h) => {
|
|
26
|
+
proxy.updateSizeExternal(w, h, window.devicePixelRatio || 1)
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
const preparedInitOptions = deepPrepareForTransfer(initOptions, worker)
|
|
30
|
+
try {
|
|
31
|
+
proxy.init(preparedInitOptions, canvas.canvas)
|
|
32
|
+
} catch (err) {
|
|
33
|
+
findProblemTransfer(preparedInitOptions)
|
|
34
|
+
throw err
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const backendMethodsProxy = new Proxy({} as ThreeJsBackendMethods, {
|
|
38
|
+
get(_target, prop) {
|
|
39
|
+
if (typeof prop !== 'string') {
|
|
40
|
+
return undefined
|
|
41
|
+
}
|
|
42
|
+
return async (...args: any[]) => proxy.callBackendMethod(prop as any, ...args)
|
|
43
|
+
}
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
const backend: GraphicsBackend = {
|
|
47
|
+
id: 'threejs',
|
|
48
|
+
displayName: `three.js ${THREE.REVISION}`,
|
|
49
|
+
// startPanorama: proxy.startPanorama,
|
|
50
|
+
async startPanorama() { },
|
|
51
|
+
async startWorld(options) {
|
|
52
|
+
meshersSendMcData([worker], options.version, [...dynamicMcDataFiles, 'items', 'itemsArray', 'entitiesByName', 'blocksByStateId'])
|
|
53
|
+
|
|
54
|
+
options.inWorldRenderingConfig['__syncToWorker'] = true
|
|
55
|
+
|
|
56
|
+
if (options.playerStateReactive) {
|
|
57
|
+
options.playerStateReactive['__syncToWorker'] = true
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (options.rendererState) {
|
|
61
|
+
options.rendererState['__syncFromWorker'] = true
|
|
62
|
+
}
|
|
63
|
+
if (options.nonReactiveState) {
|
|
64
|
+
options.nonReactiveState['__syncFromWorker'] = true
|
|
65
|
+
}
|
|
66
|
+
options.nonReactiveState['__syncFromWorkerInterval'] = 200
|
|
67
|
+
const prepared = deepPrepareForTransfer(options, worker)
|
|
68
|
+
try {
|
|
69
|
+
await proxy.startWorld(structuredClone(prepared))
|
|
70
|
+
console.log('startWorld done')
|
|
71
|
+
} catch (err) {
|
|
72
|
+
findProblemTransfer(prepared)
|
|
73
|
+
throw err
|
|
74
|
+
}
|
|
75
|
+
proxy.updateSizeExternal(canvas.size.width, canvas.size.height, window.devicePixelRatio || 1)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
const fpsStat = addNewStat('fps')
|
|
79
|
+
setInterval(() => {
|
|
80
|
+
const { fps, avgRenderTime, worstRenderTime } = options.nonReactiveState
|
|
81
|
+
fpsStat.updateText(`FPS: ${fps.toFixed(0)} (${avgRenderTime.toFixed(0)}ms/${worstRenderTime.toFixed(0)}ms)`)
|
|
82
|
+
options.nonReactiveState.fps = 0
|
|
83
|
+
}, 1000)
|
|
84
|
+
},
|
|
85
|
+
disconnect() {
|
|
86
|
+
canvas.destroy()
|
|
87
|
+
proxy.disconnect()
|
|
88
|
+
worker.terminate()
|
|
89
|
+
},
|
|
90
|
+
setRendering(rendering) {
|
|
91
|
+
proxy.setRendering(rendering)
|
|
92
|
+
},
|
|
93
|
+
updateCamera(pos, yaw, pitch) {
|
|
94
|
+
proxy.updateCamera(pos ? { x: pos.x, y: pos.y, z: pos.z } : null, yaw, pitch)
|
|
95
|
+
},
|
|
96
|
+
soundSystem: undefined,
|
|
97
|
+
backendMethods: backendMethodsProxy
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return backend
|
|
101
|
+
}
|
|
102
|
+
createGraphicsBackendOffThread.id = 'threejs-off-thread'
|
|
103
|
+
|
|
104
|
+
export const isOffthreadRendererSupported = () => {
|
|
105
|
+
// check if toOffscreenCanvas is supported
|
|
106
|
+
return 'OffscreenCanvas' in window && 'transferControlToOffscreen' in HTMLCanvasElement.prototype && !process.env.SINGLE_FILE_BUILD_MODE
|
|
107
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import * as THREE from 'three'
|
|
2
|
+
import { loadSkinFromUsername, loadSkinImage } from '../lib/utils/skins'
|
|
3
|
+
import { steveTexture } from './entities'
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
export const getMyHand = async (image?: string, userName?: string) => {
|
|
7
|
+
let newMap: THREE.Texture
|
|
8
|
+
if (!image && !userName) {
|
|
9
|
+
newMap = await steveTexture
|
|
10
|
+
} else {
|
|
11
|
+
if (!image) {
|
|
12
|
+
image = await loadSkinFromUsername(userName!, 'skin')
|
|
13
|
+
}
|
|
14
|
+
if (!image) {
|
|
15
|
+
return
|
|
16
|
+
}
|
|
17
|
+
const { canvas } = await loadSkinImage(image)
|
|
18
|
+
newMap = new THREE.CanvasTexture(canvas)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
newMap.magFilter = THREE.NearestFilter
|
|
22
|
+
newMap.minFilter = THREE.NearestFilter
|
|
23
|
+
// right arm
|
|
24
|
+
const box = new THREE.BoxGeometry()
|
|
25
|
+
const material = new THREE.MeshStandardMaterial()
|
|
26
|
+
const slim = false
|
|
27
|
+
const mesh = new THREE.Mesh(box, material)
|
|
28
|
+
mesh.scale.x = slim ? 3 : 4
|
|
29
|
+
mesh.scale.y = 12
|
|
30
|
+
mesh.scale.z = 4
|
|
31
|
+
setSkinUVs(box, 40, 16, slim ? 3 : 4, 12, 4)
|
|
32
|
+
material.map = newMap
|
|
33
|
+
material.needsUpdate = true
|
|
34
|
+
const group = new THREE.Group()
|
|
35
|
+
group.add(mesh)
|
|
36
|
+
group.scale.set(0.1, 0.1, 0.1)
|
|
37
|
+
mesh.rotation.z = Math.PI
|
|
38
|
+
return group
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function setUVs (
|
|
42
|
+
box: THREE.BoxGeometry,
|
|
43
|
+
u: number,
|
|
44
|
+
v: number,
|
|
45
|
+
width: number,
|
|
46
|
+
height: number,
|
|
47
|
+
depth: number,
|
|
48
|
+
textureWidth: number,
|
|
49
|
+
textureHeight: number
|
|
50
|
+
): void {
|
|
51
|
+
const toFaceVertices = (x1: number, y1: number, x2: number, y2: number) => [
|
|
52
|
+
new THREE.Vector2(x1 / textureWidth, 1 - y2 / textureHeight),
|
|
53
|
+
new THREE.Vector2(x2 / textureWidth, 1 - y2 / textureHeight),
|
|
54
|
+
new THREE.Vector2(x2 / textureWidth, 1 - y1 / textureHeight),
|
|
55
|
+
new THREE.Vector2(x1 / textureWidth, 1 - y1 / textureHeight),
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
const top = toFaceVertices(u + depth, v, u + width + depth, v + depth)
|
|
59
|
+
const bottom = toFaceVertices(u + width + depth, v, u + width * 2 + depth, v + depth)
|
|
60
|
+
const left = toFaceVertices(u, v + depth, u + depth, v + depth + height)
|
|
61
|
+
const front = toFaceVertices(u + depth, v + depth, u + width + depth, v + depth + height)
|
|
62
|
+
const right = toFaceVertices(u + width + depth, v + depth, u + width + depth * 2, v + height + depth)
|
|
63
|
+
const back = toFaceVertices(u + width + depth * 2, v + depth, u + width * 2 + depth * 2, v + height + depth)
|
|
64
|
+
|
|
65
|
+
const uvAttr = box.attributes.uv as THREE.BufferAttribute
|
|
66
|
+
const uvRight = [right[3], right[2], right[0], right[1]]
|
|
67
|
+
const uvLeft = [left[3], left[2], left[0], left[1]]
|
|
68
|
+
const uvTop = [top[3], top[2], top[0], top[1]]
|
|
69
|
+
const uvBottom = [bottom[0], bottom[1], bottom[3], bottom[2]]
|
|
70
|
+
const uvFront = [front[3], front[2], front[0], front[1]]
|
|
71
|
+
const uvBack = [back[3], back[2], back[0], back[1]]
|
|
72
|
+
|
|
73
|
+
// Create a new array to hold the modified UV data
|
|
74
|
+
const newUVData = [] as number[]
|
|
75
|
+
|
|
76
|
+
// Iterate over the arrays and copy the data to uvData
|
|
77
|
+
for (const uvArray of [uvRight, uvLeft, uvTop, uvBottom, uvFront, uvBack]) {
|
|
78
|
+
for (const uv of uvArray) {
|
|
79
|
+
newUVData.push(uv.x, uv.y)
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
uvAttr.set(new Float32Array(newUVData))
|
|
84
|
+
uvAttr.needsUpdate = true
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function setSkinUVs (box: THREE.BoxGeometry, u: number, v: number, width: number, height: number, depth: number): void {
|
|
88
|
+
setUVs(box, u, v, width, height, depth, 64, 64)
|
|
89
|
+
}
|