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.
Files changed (187) hide show
  1. package/README.md +297 -0
  2. package/dist/index.html +83 -0
  3. package/dist/static/image/arrow.6f27b59f.png +0 -0
  4. package/dist/static/image/blocksAtlasLatest.7850afa3.png +0 -0
  5. package/dist/static/image/blocksAtlasLegacy.5c76823d.png +0 -0
  6. package/dist/static/image/itemsAtlasLatest.36036f95.png +0 -0
  7. package/dist/static/image/itemsAtlasLegacy.dcb1b58d.png +0 -0
  8. package/dist/static/image/tipped_arrow.6f27b59f.png +0 -0
  9. package/dist/static/js/365.f05233ab.js +8462 -0
  10. package/dist/static/js/365.f05233ab.js.LICENSE.txt +52 -0
  11. package/dist/static/js/async/738.efa27644.js +1 -0
  12. package/dist/static/js/index.092ec5be.js +56 -0
  13. package/dist/static/js/lib-polyfill.98986ac5.js +1 -0
  14. package/dist/static/js/lib-react.5c9129e0.js +2 -0
  15. package/dist/static/js/lib-react.5c9129e0.js.LICENSE.txt +39 -0
  16. package/package.json +104 -0
  17. package/src/assets/destroy_stage_0.png +0 -0
  18. package/src/assets/destroy_stage_1.png +0 -0
  19. package/src/assets/destroy_stage_2.png +0 -0
  20. package/src/assets/destroy_stage_3.png +0 -0
  21. package/src/assets/destroy_stage_4.png +0 -0
  22. package/src/assets/destroy_stage_5.png +0 -0
  23. package/src/assets/destroy_stage_6.png +0 -0
  24. package/src/assets/destroy_stage_7.png +0 -0
  25. package/src/assets/destroy_stage_8.png +0 -0
  26. package/src/assets/destroy_stage_9.png +0 -0
  27. package/src/examples/README.md +146 -0
  28. package/src/examples/appViewerExample.ts +205 -0
  29. package/src/examples/initialMenuStart.ts +161 -0
  30. package/src/graphicsBackend/appViewer.ts +297 -0
  31. package/src/graphicsBackend/config.ts +119 -0
  32. package/src/graphicsBackend/index.ts +10 -0
  33. package/src/graphicsBackend/playerState.ts +61 -0
  34. package/src/graphicsBackend/types.ts +143 -0
  35. package/src/index.ts +97 -0
  36. package/src/lib/DebugGui.ts +190 -0
  37. package/src/lib/animationController.ts +85 -0
  38. package/src/lib/buildSharedConfig.mjs +1 -0
  39. package/src/lib/cameraBobbing.ts +94 -0
  40. package/src/lib/canvas2DOverlay.example.ts +361 -0
  41. package/src/lib/canvas2DOverlay.quickstart.ts +242 -0
  42. package/src/lib/canvas2DOverlay.ts +381 -0
  43. package/src/lib/cleanupDecorator.ts +29 -0
  44. package/src/lib/createPlayerObject.ts +55 -0
  45. package/src/lib/frameTimingCollector.ts +164 -0
  46. package/src/lib/guiRenderer.ts +283 -0
  47. package/src/lib/items.ts +140 -0
  48. package/src/lib/mesherlogReader.ts +131 -0
  49. package/src/lib/moreBlockDataGenerated.json +714 -0
  50. package/src/lib/preflatMap.json +1741 -0
  51. package/src/lib/simpleUtils.ts +40 -0
  52. package/src/lib/smoothSwitcher.ts +168 -0
  53. package/src/lib/spiral.ts +29 -0
  54. package/src/lib/ui/newStats.ts +120 -0
  55. package/src/lib/utils/proxy.ts +23 -0
  56. package/src/lib/utils/skins.ts +63 -0
  57. package/src/lib/utils.ts +76 -0
  58. package/src/lib/workerProxy.ts +342 -0
  59. package/src/lib/worldrendererCommon.ts +1088 -0
  60. package/src/mesher/mesher.ts +253 -0
  61. package/src/mesher/models.ts +769 -0
  62. package/src/mesher/modelsGeometryCommon.ts +142 -0
  63. package/src/mesher/shared.ts +80 -0
  64. package/src/mesher/standaloneRenderer.ts +270 -0
  65. package/src/mesher/test/a.ts +3 -0
  66. package/src/mesher/test/mesherTester.ts +76 -0
  67. package/src/mesher/test/playground.ts +19 -0
  68. package/src/mesher/test/test-perf.ts +74 -0
  69. package/src/mesher/test/tests.test.ts +56 -0
  70. package/src/mesher/world.ts +294 -0
  71. package/src/mesher/worldConstants.ts +1 -0
  72. package/src/modules/index.ts +11 -0
  73. package/src/modules/starfield.ts +313 -0
  74. package/src/modules/types.ts +110 -0
  75. package/src/playerState/playerState.ts +78 -0
  76. package/src/playerState/types.ts +36 -0
  77. package/src/playground/allEntitiesDebug.ts +170 -0
  78. package/src/playground/baseScene.ts +587 -0
  79. package/src/playground/mobileControls.tsx +268 -0
  80. package/src/playground/playground.html +83 -0
  81. package/src/playground/playground.ts +11 -0
  82. package/src/playground/playgroundUi.tsx +140 -0
  83. package/src/playground/reactUtils.ts +71 -0
  84. package/src/playground/scenes/allEntities.ts +13 -0
  85. package/src/playground/scenes/entities.ts +37 -0
  86. package/src/playground/scenes/floorRandom.ts +33 -0
  87. package/src/playground/scenes/frequentUpdates.ts +148 -0
  88. package/src/playground/scenes/geometryExport.ts +142 -0
  89. package/src/playground/scenes/index.ts +12 -0
  90. package/src/playground/scenes/lightingStarfield.ts +40 -0
  91. package/src/playground/scenes/main.ts +313 -0
  92. package/src/playground/scenes/railsCobweb.ts +14 -0
  93. package/src/playground/scenes/rotationIssue.ts +7 -0
  94. package/src/playground/scenes/slabsOptimization.ts +16 -0
  95. package/src/playground/scenes/transparencyIssue.ts +11 -0
  96. package/src/playground/shared.ts +79 -0
  97. package/src/resourcesManager/index.ts +5 -0
  98. package/src/resourcesManager/resourcesManager.ts +314 -0
  99. package/src/shims/minecraftData.ts +41 -0
  100. package/src/sign-renderer/index.html +21 -0
  101. package/src/sign-renderer/index.ts +216 -0
  102. package/src/sign-renderer/noop.js +1 -0
  103. package/src/sign-renderer/playground.ts +38 -0
  104. package/src/sign-renderer/tests.test.ts +69 -0
  105. package/src/sign-renderer/vite.config.ts +10 -0
  106. package/src/three/appShared.ts +75 -0
  107. package/src/three/bannerRenderer.ts +275 -0
  108. package/src/three/cameraShake.ts +120 -0
  109. package/src/three/cinimaticScript.ts +350 -0
  110. package/src/three/documentRenderer.ts +491 -0
  111. package/src/three/entities.ts +1580 -0
  112. package/src/three/entity/EntityMesh.ts +707 -0
  113. package/src/three/entity/animations.js +171 -0
  114. package/src/three/entity/armorModels.json +204 -0
  115. package/src/three/entity/armorModels.ts +36 -0
  116. package/src/three/entity/entities.json +6230 -0
  117. package/src/three/entity/exportedModels.js +38 -0
  118. package/src/three/entity/externalTextures.json +1 -0
  119. package/src/three/entity/models/allay.obj +325 -0
  120. package/src/three/entity/models/arrow.obj +60 -0
  121. package/src/three/entity/models/axolotl.obj +509 -0
  122. package/src/three/entity/models/blaze.obj +601 -0
  123. package/src/three/entity/models/boat.obj +417 -0
  124. package/src/three/entity/models/camel.obj +1061 -0
  125. package/src/three/entity/models/cat.obj +509 -0
  126. package/src/three/entity/models/chicken.obj +371 -0
  127. package/src/three/entity/models/cod.obj +371 -0
  128. package/src/three/entity/models/creeper.obj +279 -0
  129. package/src/three/entity/models/dolphin.obj +371 -0
  130. package/src/three/entity/models/ender_dragon.obj +2993 -0
  131. package/src/three/entity/models/enderman.obj +325 -0
  132. package/src/three/entity/models/endermite.obj +187 -0
  133. package/src/three/entity/models/fox.obj +463 -0
  134. package/src/three/entity/models/frog.obj +739 -0
  135. package/src/three/entity/models/ghast.obj +463 -0
  136. package/src/three/entity/models/goat.obj +601 -0
  137. package/src/three/entity/models/guardian.obj +1015 -0
  138. package/src/three/entity/models/horse.obj +1061 -0
  139. package/src/three/entity/models/llama.obj +509 -0
  140. package/src/three/entity/models/minecart.obj +233 -0
  141. package/src/three/entity/models/parrot.obj +509 -0
  142. package/src/three/entity/models/piglin.obj +739 -0
  143. package/src/three/entity/models/pillager.obj +371 -0
  144. package/src/three/entity/models/rabbit.obj +555 -0
  145. package/src/three/entity/models/sheep.obj +555 -0
  146. package/src/three/entity/models/shulker.obj +141 -0
  147. package/src/three/entity/models/sniffer.obj +693 -0
  148. package/src/three/entity/models/spider.obj +509 -0
  149. package/src/three/entity/models/tadpole.obj +95 -0
  150. package/src/three/entity/models/turtle.obj +371 -0
  151. package/src/three/entity/models/vex.obj +325 -0
  152. package/src/three/entity/models/villager.obj +509 -0
  153. package/src/three/entity/models/warden.obj +463 -0
  154. package/src/three/entity/models/witch.obj +647 -0
  155. package/src/three/entity/models/wolf.obj +509 -0
  156. package/src/three/entity/models/zombie_villager.obj +463 -0
  157. package/src/three/entity/objModels.js +1 -0
  158. package/src/three/fireworks.ts +661 -0
  159. package/src/three/fireworksRenderer.ts +434 -0
  160. package/src/three/globals.d.ts +7 -0
  161. package/src/three/graphicsBackend.ts +274 -0
  162. package/src/three/graphicsBackendOffThread.ts +107 -0
  163. package/src/three/hand.ts +89 -0
  164. package/src/three/holdingBlock.ts +926 -0
  165. package/src/three/index.ts +20 -0
  166. package/src/three/itemMesh.ts +427 -0
  167. package/src/three/modules.d.ts +14 -0
  168. package/src/three/panorama.ts +308 -0
  169. package/src/three/panoramaShared.ts +1 -0
  170. package/src/three/renderSlot.ts +82 -0
  171. package/src/three/skyboxRenderer.ts +406 -0
  172. package/src/three/starField.ts +13 -0
  173. package/src/three/threeJsMedia.ts +731 -0
  174. package/src/three/threeJsMethods.ts +15 -0
  175. package/src/three/threeJsParticles.ts +160 -0
  176. package/src/three/threeJsSound.ts +95 -0
  177. package/src/three/threeJsUtils.ts +90 -0
  178. package/src/three/waypointSprite.ts +435 -0
  179. package/src/three/waypoints.ts +163 -0
  180. package/src/three/world/cursorBlock.ts +172 -0
  181. package/src/three/world/vr.ts +257 -0
  182. package/src/three/worldGeometryExport.ts +259 -0
  183. package/src/three/worldGeometryHandler.ts +279 -0
  184. package/src/three/worldRendererThree.ts +1381 -0
  185. package/src/worldView/index.ts +6 -0
  186. package/src/worldView/types.ts +66 -0
  187. package/src/worldView/worldView.ts +424 -0
@@ -0,0 +1,148 @@
1
+ //@ts-nocheck
2
+ import { Vec3 } from 'vec3'
3
+ import { BasePlaygroundScene } from '../baseScene'
4
+
5
+ export default class extends BasePlaygroundScene {
6
+ viewDistance = 5
7
+ continuousRender = true
8
+
9
+ override initGui (): void {
10
+ this.params = {
11
+ testActive: false,
12
+ testUpdatesPerSecond: 10,
13
+ testInitialUpdate: false,
14
+ stopGeometryUpdate: false,
15
+ manualTest: () => {
16
+ this.updateBlock()
17
+ },
18
+ testNeighborUpdates: () => {
19
+ this.testNeighborUpdates()
20
+ }
21
+ }
22
+
23
+ super.initGui()
24
+ }
25
+
26
+ lastUpdatedOffset = 0
27
+ lastUpdatedId = 2
28
+ updateBlock () {
29
+ const x = this.lastUpdatedOffset % 16
30
+ const z = Math.floor(this.lastUpdatedOffset / 16)
31
+ const y = 90
32
+ worldView!.setBlockStateId(new Vec3(x, y, z), this.lastUpdatedId++)
33
+ this.lastUpdatedOffset++
34
+ if (this.lastUpdatedOffset > 16 * 16) this.lastUpdatedOffset = 0
35
+ if (this.lastUpdatedId > 500) this.lastUpdatedId = 1
36
+ }
37
+
38
+ testNeighborUpdates () {
39
+ viewer.world.setBlockStateId(new Vec3(15, 95, 15), 1)
40
+ viewer.world.setBlockStateId(new Vec3(0, 95, 15), 1)
41
+ viewer.world.setBlockStateId(new Vec3(15, 95, 0), 1)
42
+ viewer.world.setBlockStateId(new Vec3(0, 95, 0), 1)
43
+
44
+ viewer.world.setBlockStateId(new Vec3(16, 95, 15), 1)
45
+ viewer.world.setBlockStateId(new Vec3(-1, 95, 15), 1)
46
+ viewer.world.setBlockStateId(new Vec3(15, 95, -1), 1)
47
+ viewer.world.setBlockStateId(new Vec3(-1, 95, 0), 1)
48
+ setTimeout(() => {
49
+ viewer.world.setBlockStateId(new Vec3(16, 96, 16), 1)
50
+ viewer.world.setBlockStateId(new Vec3(-1, 96, 16), 1)
51
+ viewer.world.setBlockStateId(new Vec3(16, 96, -1), 1)
52
+ viewer.world.setBlockStateId(new Vec3(-1, 96, -1), 1)
53
+ }, 3000)
54
+ }
55
+
56
+ setupTimer () {
57
+ // this.stopRender = true
58
+
59
+ let lastTime = 0
60
+ const tick = () => {
61
+ viewer.world.debugStopGeometryUpdate = this.params.stopGeometryUpdate
62
+ const updateEach = 1000 / this.params.testUpdatesPerSecond
63
+ requestAnimationFrame(tick)
64
+ if (!this.params.testActive) return
65
+ const updateCount = Math.floor(performance.now() - lastTime) / updateEach
66
+ for (let i = 0; i < updateCount; i++) {
67
+ this.updateBlock()
68
+ }
69
+ lastTime = performance.now()
70
+ }
71
+
72
+ requestAnimationFrame(tick)
73
+
74
+ // const limit = 1000
75
+ // const limit = 100
76
+ // const limit = 1
77
+ // const updatedChunks = new Set<string>()
78
+ // const updatedBlocks = new Set<string>()
79
+ // let lastSecond = 0
80
+ // setInterval(() => {
81
+ // const second = Math.floor(performance.now() / 1000)
82
+ // if (lastSecond !== second) {
83
+ // lastSecond = second
84
+ // updatedChunks.clear()
85
+ // updatedBlocks.clear()
86
+ // }
87
+ // const isEven = second % 2 === 0
88
+ // if (updatedBlocks.size > limit) {
89
+ // return
90
+ // }
91
+ // const changeBlock = (x, z) => {
92
+ // const chunkKey = `${Math.floor(x / 16)},${Math.floor(z / 16)}`
93
+ // const key = `${x},${z}`
94
+ // if (updatedBlocks.has(chunkKey)) return
95
+
96
+ // updatedChunks.add(chunkKey)
97
+ // worldView!.world.setBlock(this.targetPos.offset(x, 0, z), this.Block.fromStateId(isEven ? 2 : 3, 0))
98
+ // updatedBlocks.add(key)
99
+ // }
100
+ // const { squareSize } = this.params
101
+ // const xStart = -squareSize
102
+ // const zStart = -squareSize
103
+ // const xEnd = squareSize
104
+ // const zEnd = squareSize
105
+ // for (let x = xStart; x <= xEnd; x += 16) {
106
+ // for (let z = zStart; z <= zEnd; z += 16) {
107
+ // const key = `${x},${z}`
108
+ // if (updatedChunks.has(key)) continue
109
+ // changeBlock(x, z)
110
+ // return
111
+ // }
112
+ // }
113
+ // for (let x = xStart; x <= xEnd; x += 16) {
114
+ // for (let z = zStart; z <= zEnd; z += 16) {
115
+ // const key = `${x},${z}`
116
+ // if (updatedChunks.has(key)) continue
117
+ // changeBlock(x, z)
118
+ // return
119
+ // }
120
+ // }
121
+ // }, 1)
122
+ }
123
+
124
+ setupWorld () {
125
+ this.worldConfig.showChunkBorders = true
126
+
127
+ const maxSquareRadius = this.viewDistance * 16
128
+ // const fullBlocks = loadedData.blocksArray.map(x => x.name)
129
+ const squareSize = maxSquareRadius
130
+ for (let x = -squareSize; x <= squareSize; x++) {
131
+ for (let z = -squareSize; z <= squareSize; z++) {
132
+ const i = Math.abs(x + z) * squareSize
133
+ worldView!.world.setBlock(this.targetPos.offset(x, 0, z), this.Block.fromStateId(1, 0))
134
+ }
135
+ }
136
+ let done = false
137
+ viewer.world.renderUpdateEmitter.on('update', () => {
138
+ if (!viewer.world.allChunksFinished || done) return
139
+ done = true
140
+ this.setupTimer()
141
+ })
142
+ setTimeout(() => {
143
+ if (this.params.testInitialUpdate) {
144
+ this.updateBlock()
145
+ }
146
+ })
147
+ }
148
+ }
@@ -0,0 +1,142 @@
1
+ import * as THREE from 'three'
2
+ import { BasePlaygroundScene } from '../baseScene'
3
+ import {
4
+ downloadWorldGeometry,
5
+ loadWorldGeometryFromUrl,
6
+ type ExportedWorldGeometry
7
+ } from '../../three/worldGeometryExport'
8
+
9
+ type GeometryExportBackendMethods = {
10
+ loadGeometryExport?: (exportData: ExportedWorldGeometry) => Promise<number>
11
+ }
12
+
13
+ /**
14
+ * Scene for exporting/importing world geometry
15
+ *
16
+ * Usage:
17
+ * - Load normally: builds world from blocks, can export geometry
18
+ * - Load with ?geometryUrl=URL: loads pre-exported geometry from file (or default world-geometry.json)
19
+ */
20
+ export default class extends BasePlaygroundScene {
21
+ params = {
22
+ exportGeometry: () => this.exportGeometry(),
23
+ exportWithTexture: () => this.exportGeometry(true),
24
+ }
25
+
26
+ // Loaded geometry data (when loading from URL)
27
+ private loadedGeometry: ExportedWorldGeometry | null = null
28
+ private readonly geometryUrl: string | null
29
+
30
+ constructor() {
31
+ const qs = new URLSearchParams(window.location.search)
32
+ const geometryUrl = qs.get('geometryUrl') ?? 'world-geometry.json'
33
+
34
+ // If loading from URL, skip normal world setup (viewDistance 0 means no chunks loaded)
35
+ super({
36
+ viewDistance: geometryUrl ? 0 : 1,
37
+ continuousRender: false,
38
+ enableCameraOrbitControl: false,
39
+ })
40
+
41
+ this.geometryUrl = geometryUrl
42
+ }
43
+
44
+ // Override initData to load geometry after base initialization completes
45
+ override async initData() {
46
+ await super.initData()
47
+
48
+ // Now camera and worldRenderer are ready - load geometry if URL provided
49
+ if (this.geometryUrl) {
50
+ await this.loadFromUrl(this.geometryUrl)
51
+ }
52
+ }
53
+
54
+ setupWorld() {
55
+ if (this.geometryUrl) {
56
+ return
57
+ }
58
+ // Default world setup - add some blocks for testing
59
+ this.addWorldBlock(0, 0, 0, 'stone')
60
+ this.addWorldBlock(1, 0, 0, 'grass_block')
61
+ this.addWorldBlock(0, 0, 1, 'dirt')
62
+ this.addWorldBlock(1, 0, 1, 'cobblestone')
63
+ this.addWorldBlock(0, 1, 0, 'oak_log')
64
+ this.addWorldBlock(1, 1, 0, 'oak_planks')
65
+ }
66
+
67
+ private async loadFromUrl(url: string) {
68
+ try {
69
+ console.log('Loading geometry from:', url)
70
+ this.loadedGeometry = await loadWorldGeometryFromUrl(url)
71
+
72
+ // Restore camera position and rotation
73
+ const { camera: camData } = this.loadedGeometry
74
+ this.camera.position.set(camData.position.x, camData.position.y, camData.position.z)
75
+
76
+ // Apply rotation using lookAt direction
77
+ const { pitch, yaw } = camData.rotation
78
+ const forward = new THREE.Vector3(
79
+ -Math.sin(yaw) * Math.cos(pitch),
80
+ Math.sin(pitch),
81
+ -Math.cos(yaw) * Math.cos(pitch)
82
+ )
83
+ this.camera.lookAt(
84
+ camData.position.x + forward.x,
85
+ camData.position.y + forward.y,
86
+ camData.position.z + forward.z
87
+ )
88
+ this.controls?.update()
89
+ this.syncCameraToBackend()
90
+
91
+ const backendMethods = this.appViewer.backend?.backendMethods as GeometryExportBackendMethods | undefined
92
+ if (!backendMethods?.loadGeometryExport) {
93
+ console.warn('Three.js backend does not expose loadGeometryExport')
94
+ return
95
+ }
96
+
97
+ const geometryData = this.loadedGeometry
98
+ if (!geometryData) {
99
+ console.warn('No geometry data available after load')
100
+ return
101
+ }
102
+
103
+ const importedCount = await backendMethods.loadGeometryExport(geometryData)
104
+ console.log(`Loaded ${importedCount} sections from geometry file`)
105
+ this.requestRender()
106
+
107
+ } catch (err) {
108
+ console.error('Failed to load geometry:', err)
109
+ }
110
+ }
111
+
112
+ private exportGeometry(includeTexture = false) {
113
+ const { worldRenderer } = this
114
+ if (!worldRenderer) {
115
+ console.error('WorldRenderer not available')
116
+ return
117
+ }
118
+
119
+ // Get camera position and rotation
120
+ const cameraPosition = {
121
+ x: this.camera.position.x,
122
+ y: this.camera.position.y,
123
+ z: this.camera.position.z
124
+ }
125
+
126
+ // Extract yaw/pitch from camera quaternion
127
+ const forward = new THREE.Vector3(0, 0, -1)
128
+ forward.applyQuaternion(this.camera.quaternion)
129
+ const cameraRotation = {
130
+ yaw: Math.atan2(-forward.x, -forward.z),
131
+ pitch: Math.asin(forward.y)
132
+ }
133
+
134
+ // Generate filename with timestamp
135
+ const timestamp = new Date().toISOString().replaceAll(/[:.]/g, '-')
136
+ const filename = `world-geometry-${timestamp}.json`
137
+
138
+ downloadWorldGeometry(worldRenderer, cameraPosition, cameraRotation, filename, includeTexture)
139
+ console.log('Geometry exported to:', filename)
140
+ }
141
+
142
+ }
@@ -0,0 +1,12 @@
1
+ // export { default as rotation } from './rotation'
2
+ export { default as main } from './main'
3
+ export { default as railsCobweb } from './railsCobweb'
4
+ // export { default as floorRandom } from './floorRandom'
5
+ // export { default as lightingStarfield } from './lightingStarfield'
6
+ // export { default as transparencyIssue } from './transparencyIssue'
7
+ // export { default as rotationIssue } from './rotationIssue'
8
+ // export { default as entities } from './entities'
9
+ // export { default as frequentUpdates } from './frequentUpdates'
10
+ // export { default as slabsOptimization } from './slabsOptimization'
11
+ // export { default as allEntities } from './allEntities'
12
+ // export { default as geometryExport } from './geometryExport'
@@ -0,0 +1,40 @@
1
+ //@ts-nocheck
2
+ import * as THREE from 'three'
3
+ import { Vec3 } from 'vec3'
4
+ import { BasePlaygroundScene } from '../baseScene'
5
+ import { WorldRendererThree } from '../../viewer/three/worldrendererThree'
6
+
7
+ export default class extends BasePlaygroundScene {
8
+ continuousRender = true
9
+
10
+ override setupWorld (): void {
11
+ viewer.world.mesherConfig.enableLighting = true
12
+ viewer.world.mesherConfig.skyLight = 0
13
+ this.addWorldBlock(0, 0, 0, 'stone')
14
+ this.addWorldBlock(0, 0, 1, 'stone')
15
+ this.addWorldBlock(1, 0, 0, 'stone')
16
+ this.addWorldBlock(1, 0, 1, 'stone')
17
+ // chess like
18
+ worldView?.world.setBlockLight(this.targetPos.offset(0, 1, 0), 15)
19
+ worldView?.world.setBlockLight(this.targetPos.offset(0, 1, 1), 0)
20
+ worldView?.world.setBlockLight(this.targetPos.offset(1, 1, 0), 0)
21
+ worldView?.world.setBlockLight(this.targetPos.offset(1, 1, 1), 15)
22
+ }
23
+
24
+ override renderFinish (): void {
25
+ viewer.scene.background = new THREE.Color(0x00_00_00)
26
+ // starfield and test entities
27
+ ;(viewer.world as WorldRendererThree).starField.enabled = true
28
+ ;(viewer.world as WorldRendererThree).starField.addToScene()
29
+ viewer.entities.update({
30
+ id: 0,
31
+ name: 'player',
32
+ pos: this.targetPos.clone()
33
+ } as any, {})
34
+ viewer.entities.update({
35
+ id: 1,
36
+ name: 'creeper',
37
+ pos: this.targetPos.offset(1, 0, 0)
38
+ } as any, {})
39
+ }
40
+ }
@@ -0,0 +1,313 @@
1
+ // eslint-disable-next-line import/no-named-as-default
2
+ import GUI, { Controller } from 'lil-gui'
3
+ import * as THREE from 'three'
4
+ import { BasePlaygroundScene } from '../baseScene'
5
+ import { TWEEN_DURATION } from '@/three/entities'
6
+ import { EntityMesh } from '@/three/entity/EntityMesh'
7
+
8
+ const includedVersions = globalThis.includedVersions
9
+
10
+ class MainScene extends BasePlaygroundScene {
11
+ // eslint-disable-next-line @typescript-eslint/no-useless-constructor
12
+ constructor(...args) {
13
+ super(...args)
14
+ }
15
+
16
+ override initGui(): void {
17
+ // initial values
18
+ this.params = {
19
+ skipQs: '',
20
+ block: '',
21
+ metadata: 0,
22
+ supportBlock: false,
23
+ entity: '',
24
+ removeEntity() {
25
+ this.entity = ''
26
+ },
27
+ entityRotate: false,
28
+ camera: '',
29
+ playSound() { },
30
+ blockIsomorphicRenderBundle() { },
31
+ modelVariant: 0
32
+ }
33
+ this.metadataGui = this.gui.add(this.params, 'metadata')
34
+ this.paramOptions = {
35
+ version: {
36
+ options: includedVersions,
37
+ hide: false
38
+ },
39
+ block: {
40
+ options: this.mcData.blocksArray.map(b => b.name).sort((a, b) => a.localeCompare(b))
41
+ },
42
+ entity: {
43
+ options: this.mcData.entitiesArray.map(b => b.name).sort((a, b) => a.localeCompare(b))
44
+ },
45
+ camera: {
46
+ hide: true,
47
+ }
48
+ }
49
+ super.initGui()
50
+ }
51
+
52
+ blockProps = {}
53
+ metadataFolder: GUI | undefined
54
+ metadataGui: Controller | undefined
55
+
56
+ override onParamUpdate = {
57
+ version() {
58
+ // if (initialUpdate) return
59
+ // viewer.world.texturesVersion = params.version
60
+ // viewer.world.updateTexturesData()
61
+ // todo warning
62
+ },
63
+ block: () => {
64
+ this.blockProps = {}
65
+ this.metadataFolder?.destroy()
66
+ const block = this.mcData.blocksByName[this.params.block]
67
+ if (!block) return
68
+ console.log('block', block.name)
69
+ const props = new this.Block(block.id, 0, 0).getProperties()
70
+ const { states } = this.mcData.blocksByStateId[this.getBlock()?.minStateId] ?? {}
71
+ this.metadataFolder = this.gui.addFolder('metadata')
72
+ if (states) {
73
+ for (const state of states) {
74
+ let defaultValue: string | number | boolean
75
+ if (state.values) { // int, enum
76
+ defaultValue = state.values[0] as string | number | boolean
77
+ } else {
78
+ switch (state.type) {
79
+ case 'bool':
80
+ defaultValue = false
81
+ break
82
+ case 'int':
83
+ defaultValue = 0
84
+ break
85
+ case 'direction':
86
+ defaultValue = 'north'
87
+ break
88
+
89
+ default:
90
+ continue
91
+ }
92
+ }
93
+ this.blockProps[state.name] = defaultValue
94
+ if (state.values) {
95
+ this.metadataFolder.add(this.blockProps, state.name, state.values)
96
+ } else {
97
+ this.metadataFolder.add(this.blockProps, state.name)
98
+ }
99
+ }
100
+ } else {
101
+ for (const [name, value] of Object.entries(props)) {
102
+ this.blockProps[name] = value
103
+ this.metadataFolder.add(this.blockProps, name)
104
+ }
105
+ }
106
+ console.log('props', this.blockProps)
107
+ this.metadataFolder.open()
108
+ },
109
+ entity: () => {
110
+ this.continuousRender = this.params.entity === 'player'
111
+ this.entityUpdateShared()
112
+ if (!this.params.entity) return
113
+ if (this.params.entity === 'player') {
114
+ this.worldRenderer.entities.updatePlayerSkin('id', this.worldRenderer.entities.entities.id.username, undefined, true, true)
115
+ this.worldRenderer.entities.playAnimation('id', 'running')
116
+ }
117
+ // let prev = false
118
+ // setInterval(() => {
119
+ // viewer.entities.playAnimation('id', prev ? 'running' : 'idle')
120
+ // prev = !prev
121
+ // }, 1000)
122
+
123
+ EntityMesh.getStaticData(this.params.entity)
124
+ // entityRotationFolder.destroy()
125
+ // entityRotationFolder = gui.addFolder('entity metadata')
126
+ // entityRotationFolder.add(params, 'entityRotate')
127
+ // entityRotationFolder.open()
128
+ },
129
+ supportBlock: () => {
130
+ this.worldView!.setBlockStateId(this.targetPos.offset(0, -1, 0), this.params.supportBlock ? 1 : 0)
131
+ },
132
+ modelVariant: () => {
133
+ this.worldRenderer.worldRendererConfig.debugModelVariant = this.params.modelVariant === 0 ? undefined : [this.params.modelVariant]
134
+ }
135
+ }
136
+
137
+ entityUpdateShared() {
138
+ this.worldRenderer.entities.clear()
139
+ if (!this.params.entity) return
140
+ this.worldView!.emit('entity', {
141
+ id: 'id', name: this.params.entity, pos: this.targetPos.offset(0.5, 1, 0.5), width: 1, height: 1, username: localStorage.testUsername, yaw: Math.PI, pitch: 0
142
+ })
143
+ const enableSkeletonDebug = (obj) => {
144
+ const { children, isSkeletonHelper } = obj
145
+ if (!Array.isArray(children)) return
146
+ if (isSkeletonHelper) {
147
+ obj.visible = true
148
+ return
149
+ }
150
+ for (const child of children) {
151
+ if (typeof child === 'object') enableSkeletonDebug(child)
152
+ }
153
+ }
154
+ enableSkeletonDebug(this.worldRenderer.entities.entities['id'])
155
+ setTimeout(() => {
156
+ this.render()
157
+ }, TWEEN_DURATION)
158
+ }
159
+
160
+ getBlock() {
161
+ return this.mcData.blocksByName[this.params.block || 'air']
162
+ }
163
+
164
+ // applyChanges (metadataUpdate = false, skipQs = false) {
165
+ override onParamsUpdate(paramName: string, object: any) {
166
+ const metadataUpdate = paramName === 'metadata'
167
+
168
+ const blockId = this.getBlock()?.id
169
+ let block: import('prismarine-block').Block
170
+ if (metadataUpdate) {
171
+ block = new this.Block(blockId, 0, this.params.metadata)
172
+ Object.assign(this.blockProps, block.getProperties())
173
+ for (const _child of this.metadataFolder!.children) {
174
+ const child = _child as import('lil-gui').Controller
175
+ child.updateDisplay()
176
+ }
177
+ } else {
178
+ try {
179
+ block = this.Block.fromProperties(blockId ?? -1, this.blockProps, 0)
180
+ } catch (err) {
181
+ console.error(err)
182
+ block = this.Block.fromStateId(0, 0)
183
+ }
184
+ }
185
+
186
+ this.worldView!.setBlockStateId(this.targetPos, block.stateId ?? 0)
187
+ console.log('up stateId', block.stateId)
188
+ this.params.metadata = block.metadata
189
+ this.metadataGui?.updateDisplay()
190
+ }
191
+
192
+ override renderFinish() {
193
+ for (const update of Object.values(this.onParamUpdate)) {
194
+ // update(true)
195
+ update()
196
+ }
197
+ this.onParamsUpdate('', {})
198
+ this.gui.openAnimated()
199
+ }
200
+
201
+ blockIsomorphicRenderBundle() {
202
+ const { renderer } = this.worldRenderer
203
+
204
+ const canvas = renderer.domElement
205
+ const onlyCurrent = !confirm('Ok - render all blocks, Cancel - render only current one')
206
+ const sizeRaw = prompt('Size', '512')
207
+ if (!sizeRaw) return
208
+ const size = parseInt(sizeRaw, 10)
209
+ // const size = 512
210
+
211
+ canvas.width = size
212
+ canvas.height = size
213
+ renderer.setSize(size, size)
214
+
215
+ // Temporarily replace PerspectiveCamera with OrthographicCamera for block rendering
216
+ this.worldRenderer.camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 10) as any
217
+ this.worldRenderer.scene.background = null
218
+
219
+ const rad = THREE.MathUtils.degToRad(-120)
220
+ this.worldRenderer.directionalLight.position.set(
221
+ Math.cos(rad),
222
+ Math.sin(rad),
223
+ 0.2
224
+ ).normalize()
225
+ this.worldRenderer.directionalLight.intensity = 1
226
+
227
+ const cameraPos = this.targetPos.offset(2, 2, 2)
228
+ const pitch = THREE.MathUtils.degToRad(-30)
229
+ const yaw = THREE.MathUtils.degToRad(45)
230
+ this.worldRenderer.camera.rotation.set(pitch, yaw, 0, 'ZYX')
231
+ // this.worldRenderer!.camera.lookAt(center.x + 0.5, center.y + 0.5, center.z + 0.5)
232
+ this.worldRenderer.camera.position.set(cameraPos.x + 1, cameraPos.y + 0.5, cameraPos.z + 1)
233
+
234
+ const allBlocks = this.mcData.blocksArray.map(b => b.name)
235
+ // const allBlocks = ['stone', 'warped_slab']
236
+
237
+ let blockCount = 1
238
+ let blockName = allBlocks[0]
239
+
240
+ const updateBlock = () => {
241
+ // viewer.setBlockStateId(targetPos, mcData.blocksByName[blockName].minStateId)
242
+ this.params.block = blockName
243
+ // todo cleanup (introduce getDefaultState)
244
+ // TODO
245
+ // onUpdate.block()
246
+ // applyChanges(false, true)
247
+ }
248
+ void this.worldRenderer.waitForChunksToRender().then(async () => {
249
+ // wait for next macro task
250
+ await new Promise(resolve => {
251
+ setTimeout(resolve, 0)
252
+ })
253
+ if (onlyCurrent) {
254
+ this.render()
255
+ onWorldUpdate()
256
+ } else {
257
+ // will be called on every render update
258
+ this.worldRenderer.renderUpdateEmitter.addListener('update', onWorldUpdate)
259
+ updateBlock()
260
+ }
261
+ })
262
+
263
+ //@ts-ignore
264
+ const zip = new JSZip()
265
+ zip.file('description.txt', 'Generated with mcraft.fun/playground')
266
+
267
+ const end = async () => {
268
+ // download zip file
269
+
270
+ const a = document.createElement('a')
271
+ const blob = await zip.generateAsync({ type: 'blob' })
272
+ const dataUrlZip = URL.createObjectURL(blob)
273
+ a.href = dataUrlZip
274
+ a.download = 'blocks_render.zip'
275
+ a.click()
276
+ URL.revokeObjectURL(dataUrlZip)
277
+ console.log('end')
278
+
279
+ this.worldRenderer.renderUpdateEmitter.removeListener('update', onWorldUpdate)
280
+ }
281
+
282
+ async function onWorldUpdate() {
283
+ // await new Promise(resolve => {
284
+ // setTimeout(resolve, 50)
285
+ // })
286
+ const dataUrl = canvas.toDataURL('image/png')
287
+
288
+ zip.file(`${blockName}.png`, dataUrl.split(',')[1], { base64: true })
289
+
290
+ if (onlyCurrent) {
291
+ end()
292
+ } else {
293
+ nextBlock()
294
+ }
295
+ }
296
+ const nextBlock = async () => {
297
+ blockName = allBlocks[blockCount++]
298
+ console.log(allBlocks.length, '/', blockCount, blockName)
299
+ if (blockCount % 5 === 0) {
300
+ await new Promise(resolve => {
301
+ setTimeout(resolve, 100)
302
+ })
303
+ }
304
+ if (blockName) {
305
+ updateBlock()
306
+ } else {
307
+ end()
308
+ }
309
+ }
310
+ }
311
+ }
312
+
313
+ export default MainScene
@@ -0,0 +1,14 @@
1
+ import { BasePlaygroundScene } from '../baseScene'
2
+
3
+ export default class RailsCobwebScene extends BasePlaygroundScene {
4
+ setupWorld () {
5
+ this.addWorldBlock(0, 0, 0, 'cobweb')
6
+ this.addWorldBlock(0, -1, 0, 'cobweb')
7
+ this.addWorldBlock(1, -1, 0, 'cobweb')
8
+ this.addWorldBlock(1, 0, 0, 'cobweb')
9
+
10
+ this.addWorldBlock(0, 0, 1, 'powered_rail', { shape: 'north_south', waterlogged: false })
11
+ this.addWorldBlock(0, 0, 2, 'powered_rail', { shape: 'ascending_south', waterlogged: false })
12
+ this.addWorldBlock(0, 1, 3, 'powered_rail', { shape: 'north_south', waterlogged: false })
13
+ }
14
+ }
@@ -0,0 +1,7 @@
1
+ import { BasePlaygroundScene } from '../baseScene'
2
+
3
+ export default class RotationIssueScene extends BasePlaygroundScene {
4
+ setupWorld () {
5
+ // todo
6
+ }
7
+ }
@@ -0,0 +1,16 @@
1
+ import { BasePlaygroundScene } from '../baseScene'
2
+
3
+ export default class extends BasePlaygroundScene {
4
+ expectedNumberOfFaces = 30
5
+ enableCameraOrbitControl = false
6
+
7
+ setupWorld () {
8
+ this.addWorldBlock(0, 1, 0, 'stone_slab')
9
+ this.addWorldBlock(0, 0, 0, 'stone')
10
+ this.addWorldBlock(0, -1, 0, 'stone_slab', { type: 'top', waterlogged: false })
11
+ this.addWorldBlock(0, -1, -1, 'stone_slab', { type: 'top', waterlogged: false })
12
+ this.addWorldBlock(0, -1, 1, 'stone_slab', { type: 'top', waterlogged: false })
13
+ this.addWorldBlock(-1, -1, 0, 'stone_slab', { type: 'top', waterlogged: false })
14
+ this.addWorldBlock(1, -1, 0, 'stone_slab', { type: 'top', waterlogged: false })
15
+ }
16
+ }