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,283 @@
1
+ // Import placeholders - replace with actual imports for your environment
2
+ import { ItemRenderer, Identifier, ItemStack, NbtString, Structure, StructureRenderer, ItemRendererResources, BlockDefinition, BlockModel, TextureAtlas, Resources, ItemModel } from 'deepslate'
3
+ import { AssetsParser } from 'mc-assets/dist/assetsParser'
4
+ import { getLoadedImage, versionToNumber } from 'mc-assets/dist/utils'
5
+ import { BlockModel as BlockModelMcAssets, AtlasParser } from 'mc-assets'
6
+ import { getLoadedBlockstatesStore, getLoadedModelsStore } from 'mc-assets/dist/stores'
7
+ import { makeTextureAtlas } from 'mc-assets/dist/atlasCreator'
8
+ import { proxy, ref } from 'valtio'
9
+ import { getItemDefinition } from 'mc-assets/dist/itemDefinitions'
10
+ import { AppViewer } from '@/graphicsBackend/appViewer'
11
+
12
+ export const getNonFullBlocksModels = (appViewer: AppViewer) => {
13
+ let version = appViewer.resourcesManager.currentResources!.version ?? 'latest'
14
+ if (versionToNumber(version) < versionToNumber('1.13')) version = '1.13'
15
+ const itemsDefinitions = appViewer.resourcesManager.currentResources!.itemsDefinitionsStore.data.latest
16
+ const blockModelsResolved = {} as Record<string, any>
17
+ const itemsModelsResolved = {} as Record<string, any>
18
+ const fullBlocksWithNonStandardDisplay = [] as string[]
19
+ const handledItemsWithDefinitions = new Set()
20
+ const assetsParser = new AssetsParser(version, getLoadedBlockstatesStore(appViewer.resourcesManager.currentResources!.blockstatesModels), getLoadedModelsStore(appViewer.resourcesManager.currentResources!.blockstatesModels))
21
+
22
+ const standardGuiDisplay = {
23
+ 'rotation': [
24
+ 30,
25
+ 225,
26
+ 0
27
+ ],
28
+ 'translation': [
29
+ 0,
30
+ 0,
31
+ 0
32
+ ],
33
+ 'scale': [
34
+ 0.625,
35
+ 0.625,
36
+ 0.625
37
+ ]
38
+ }
39
+
40
+ const arrEqual = (a: number[], b: number[]) => a.length === b.length && a.every((x, i) => x === b[i])
41
+ const addModelIfNotFullblock = (name: string, model: BlockModelMcAssets) => {
42
+ if (blockModelsResolved[name]) return
43
+ if (!model?.elements?.length) return
44
+ const isFullBlock = model.elements.length === 1 && arrEqual(model.elements[0].from, [0, 0, 0]) && arrEqual(model.elements[0].to, [16, 16, 16])
45
+ if (isFullBlock) return
46
+ const hasBetterPrerender = assetsParser.blockModelsStore.data.latest[`item/${name}`]?.textures?.['layer0']?.startsWith('invsprite_')
47
+ if (hasBetterPrerender) return
48
+ model['display'] ??= {}
49
+ model['display']['gui'] ??= standardGuiDisplay
50
+ blockModelsResolved[name] = model
51
+ }
52
+
53
+ for (const [name, definition] of Object.entries(itemsDefinitions)) {
54
+ const item = getItemDefinition(appViewer.resourcesManager.currentResources!.itemsDefinitionsStore, {
55
+ version,
56
+ name,
57
+ properties: {
58
+ 'minecraft:display_context': 'gui',
59
+ },
60
+ })
61
+ if (item) {
62
+ const { resolvedModel } = assetsParser.getResolvedModelsByModel((item.special ? name : item.model).replace('minecraft:', '')) ?? {}
63
+ if (resolvedModel) {
64
+ handledItemsWithDefinitions.add(name)
65
+ }
66
+ if (resolvedModel?.elements) {
67
+ let hasStandardDisplay = true
68
+ if (resolvedModel['display']?.gui) {
69
+ hasStandardDisplay =
70
+ arrEqual(resolvedModel['display'].gui.rotation, standardGuiDisplay.rotation)
71
+ && arrEqual(resolvedModel['display'].gui.translation, standardGuiDisplay.translation)
72
+ && arrEqual(resolvedModel['display'].gui.scale, standardGuiDisplay.scale)
73
+ }
74
+
75
+ addModelIfNotFullblock(name, resolvedModel)
76
+
77
+ if (!blockModelsResolved[name] && !hasStandardDisplay) {
78
+ fullBlocksWithNonStandardDisplay.push(name)
79
+ }
80
+ const notSideLight = resolvedModel['gui_light'] && resolvedModel['gui_light'] !== 'side'
81
+ if (!hasStandardDisplay || notSideLight) {
82
+ blockModelsResolved[name] = resolvedModel
83
+ }
84
+ }
85
+ if (!blockModelsResolved[name] && item.tints && resolvedModel) {
86
+ resolvedModel['tints'] = item.tints
87
+ if (resolvedModel.elements) {
88
+ blockModelsResolved[name] = resolvedModel
89
+ } else {
90
+ itemsModelsResolved[name] = resolvedModel
91
+ }
92
+ }
93
+ }
94
+ }
95
+
96
+ for (const [name, blockstate] of Object.entries(appViewer.resourcesManager.currentResources!.blockstatesModels.blockstates.latest)) {
97
+ if (handledItemsWithDefinitions.has(name)) {
98
+ continue
99
+ }
100
+ const resolvedModel = assetsParser.getResolvedModelFirst({ name: name.replace('minecraft:', ''), properties: {} }, true)
101
+ if (resolvedModel) {
102
+ addModelIfNotFullblock(name, resolvedModel[0])
103
+ }
104
+ }
105
+
106
+ return {
107
+ blockModelsResolved,
108
+ itemsModelsResolved
109
+ }
110
+ }
111
+
112
+ // customEvents.on('gameLoaded', () => {
113
+ // const res = getNonFullBlocksModels()
114
+ // })
115
+
116
+ const RENDER_SIZE = 64
117
+
118
+ const generateItemsGui = async (models: Record<string, BlockModelMcAssets>, isItems = false) => {
119
+ const { currentResources } = appViewer.resourcesManager
120
+ const imgBitmap = isItems ? currentResources!.itemsAtlasImage : currentResources!.blocksAtlasImage
121
+ const canvasTemp = document.createElement('canvas')
122
+ canvasTemp.width = imgBitmap.width
123
+ canvasTemp.height = imgBitmap.height
124
+ canvasTemp.style.imageRendering = 'pixelated'
125
+ const ctx = canvasTemp.getContext('2d')!
126
+ ctx.imageSmoothingEnabled = false
127
+ ctx.drawImage(imgBitmap, 0, 0)
128
+
129
+ const atlasParser = isItems ? appViewer.resourcesManager.itemsAtlasParser : appViewer.resourcesManager.blocksAtlasParser
130
+ const textureAtlas = new TextureAtlas(
131
+ ctx.getImageData(0, 0, imgBitmap.width, imgBitmap.height),
132
+ Object.fromEntries(Object.entries(atlasParser.atlas.latest.textures).map(([key, value]) => {
133
+ return [key, [
134
+ value.u,
135
+ value.v,
136
+ (value.u + (value.su ?? atlasParser.atlas.latest.suSv)),
137
+ (value.v + (value.sv ?? atlasParser.atlas.latest.suSv)),
138
+ ]] as [string, [number, number, number, number]]
139
+ }))
140
+ )
141
+
142
+ const PREVIEW_ID = Identifier.parse('preview:preview')
143
+ const PREVIEW_DEFINITION = new BlockDefinition({ '': { model: PREVIEW_ID.toString() } }, undefined)
144
+
145
+ let textureWasRequested = false
146
+ let modelData: any
147
+ let currentModelName: string | undefined
148
+ const resources: ItemRendererResources = {
149
+ getBlockModel(id) {
150
+ if (id.equals(PREVIEW_ID)) {
151
+ return BlockModel.fromJson(modelData ?? {})
152
+ }
153
+ return null
154
+ },
155
+ getTextureUV(texture) {
156
+ textureWasRequested = true
157
+ return textureAtlas.getTextureUV(texture.toString().replace('minecraft:', '').replace('block/', '').replace('item/', '').replace('blocks/', '').replace('items/', '') as any)
158
+ },
159
+ getTextureAtlas() {
160
+ return textureAtlas.getTextureAtlas()
161
+ },
162
+ getItemComponents(id) {
163
+ return new Map()
164
+ },
165
+ getItemModel(id) {
166
+ // const isSpecial = currentModelName === 'shield' || currentModelName === 'conduit' || currentModelName === 'trident'
167
+ const isSpecial = false
168
+ if (id.equals(PREVIEW_ID)) {
169
+ return ItemModel.fromJson({
170
+ type: isSpecial ? 'minecraft:special' : 'minecraft:model',
171
+ model: isSpecial ? {
172
+ type: currentModelName,
173
+ } : PREVIEW_ID.toString(),
174
+ base: PREVIEW_ID.toString(),
175
+ tints: modelData?.tints,
176
+ })
177
+ }
178
+ return null
179
+ },
180
+ }
181
+
182
+ const canvas = document.createElement('canvas')
183
+ canvas.width = RENDER_SIZE
184
+ canvas.height = RENDER_SIZE
185
+ const gl = canvas.getContext('webgl2', { preserveDrawingBuffer: true })
186
+ if (!gl) {
187
+ throw new Error('Cannot get WebGL2 context')
188
+ }
189
+
190
+ function resetGLContext(gl) {
191
+ gl.clearColor(0, 0, 0, 0)
192
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT)
193
+ }
194
+
195
+ // const includeOnly = ['powered_repeater', 'wooden_door']
196
+ const includeOnly = [] as string[]
197
+
198
+ const images: Record<string, HTMLImageElement> = {}
199
+ const item = new ItemStack(PREVIEW_ID, 1, new Map(Object.entries({
200
+ 'minecraft:item_model': new NbtString(PREVIEW_ID.toString()),
201
+ })))
202
+ const renderer = new ItemRenderer(gl, item, resources, { display_context: 'gui' })
203
+ const missingTextures = new Set()
204
+ for (const [modelName, model] of Object.entries(models)) {
205
+ textureWasRequested = false
206
+ if (includeOnly.length && !includeOnly.includes(modelName)) continue
207
+
208
+ const patchMissingTextures = () => {
209
+ for (const element of model.elements ?? []) {
210
+ for (const [faceName, face] of Object.entries(element.faces)) {
211
+ if (face.texture.startsWith('#')) {
212
+ missingTextures.add(`${modelName} ${faceName}: ${face.texture}`)
213
+ face.texture = 'block/unknown'
214
+ }
215
+ }
216
+ }
217
+ }
218
+ patchMissingTextures()
219
+ // TODO eggs
220
+
221
+ modelData = model
222
+ currentModelName = modelName
223
+ resetGLContext(gl)
224
+ if (!modelData) continue
225
+ renderer.setItem(item, { display_context: 'gui' })
226
+ renderer.drawItem()
227
+ if (!textureWasRequested) continue
228
+ const url = canvas.toDataURL()
229
+ // eslint-disable-next-line no-await-in-loop
230
+ const img = await getLoadedImage(url)
231
+ images[modelName] = img
232
+ }
233
+
234
+ if (missingTextures.size) {
235
+ console.warn(`[guiRenderer] Missing textures in ${[...missingTextures].join(', ')}`)
236
+ }
237
+
238
+ return images
239
+ }
240
+
241
+ /**
242
+ * @mainThread
243
+ */
244
+ const generateAtlas = async (images: Record<string, HTMLImageElement>) => {
245
+ const atlas = makeTextureAtlas({
246
+ input: Object.keys(images),
247
+ tileSize: RENDER_SIZE,
248
+ getLoadedImage(name) {
249
+ return {
250
+ image: images[name],
251
+ }
252
+ },
253
+ })
254
+
255
+ // const atlasParser = new AtlasParser({ latest: atlas.json }, atlas.canvas.toDataURL())
256
+ // const a = document.createElement('a')
257
+ // a.href = await atlasParser.createDebugImage(true)
258
+ // a.download = 'blocks_atlas.png'
259
+ // a.click()
260
+
261
+ appViewer.resourcesManager.currentResources!.guiAtlas = {
262
+ json: atlas.json,
263
+ image: await createImageBitmap(atlas.canvas),
264
+ }
265
+
266
+ return atlas
267
+ }
268
+
269
+ export const generateGuiAtlas = async () => {
270
+ console.trace('generateGuiAtlas')
271
+ const { blockModelsResolved, itemsModelsResolved } = getNonFullBlocksModels()
272
+
273
+ // Generate blocks atlas
274
+ console.time('generate blocks gui atlas')
275
+ const blockImages = await generateItemsGui(blockModelsResolved, false)
276
+ console.timeEnd('generate blocks gui atlas')
277
+ console.time('generate items gui atlas')
278
+ const itemImages = await generateItemsGui(itemsModelsResolved, true)
279
+ console.timeEnd('generate items gui atlas')
280
+ await generateAtlas({ ...blockImages, ...itemImages })
281
+ appViewer.resourcesManager.currentResources!.guiAtlasVersion++
282
+ // await generateAtlas(blockImages)
283
+ }
@@ -0,0 +1,140 @@
1
+ import mojangson from 'mojangson'
2
+ import nbt from 'prismarine-nbt'
3
+ import { fromFormattedString } from '@xmcl/text-component'
4
+ import { getItemSelector } from '@/playerState/playerState'
5
+ import { getItemDefinition } from 'mc-assets/dist/itemDefinitions'
6
+ import { ResourcesManagerCommon } from '@/resourcesManager'
7
+ import { ItemSpecificContextProperties } from '@/playerState/types'
8
+ import { PlayerStateRenderer } from '@/playerState/playerState'
9
+
10
+ type RenderSlotComponent = {
11
+ type: string,
12
+ data: any
13
+ // example
14
+ // {
15
+ // "type": "item_model",
16
+ // "data": "aa:ss"
17
+ // }
18
+ }
19
+ export type RenderItem = Pick<import('prismarine-item').Item, 'name' | 'displayName' | 'durabilityUsed' | 'maxDurability' | 'enchants' | 'nbt'> & {
20
+ components?: RenderSlotComponent[],
21
+ // componentMap?: Map<string, RenderSlotComponent>
22
+ }
23
+ export type GeneralInputItem = Pick<import('prismarine-item').Item, 'name' | 'nbt'> & {
24
+ components?: RenderSlotComponent[],
25
+ displayName?: string
26
+ modelResolved?: boolean
27
+ }
28
+
29
+ type JsonString = string
30
+ type PossibleItemProps = {
31
+ CustomModelData?: number
32
+ Damage?: number
33
+ display?: { Name?: JsonString } // {"text":"Knife","color":"white","italic":"true"}
34
+ }
35
+
36
+ export const getItemMetadata = (item: GeneralInputItem, resourcesManager: ResourcesManagerCommon) => {
37
+ let customText = undefined as string | any | undefined
38
+ let customModel = undefined as string | undefined
39
+
40
+ let itemId = item.name
41
+ if (!itemId.includes(':')) {
42
+ itemId = `minecraft:${itemId}`
43
+ }
44
+ const customModelDataDefinitions = resourcesManager.currentResources?.customItemModelNames[itemId]
45
+
46
+ if (item.components) {
47
+ const componentMap = new Map<string, RenderSlotComponent>()
48
+ for (const component of item.components) {
49
+ componentMap.set(component.type, component)
50
+ }
51
+
52
+ const customTextComponent = componentMap.get('custom_name') || componentMap.get('item_name')
53
+ if (customTextComponent) {
54
+ customText = typeof customTextComponent.data === 'string' ? customTextComponent.data : nbt.simplify(customTextComponent.data)
55
+ }
56
+ const customModelComponent = componentMap.get('item_model')
57
+ if (customModelComponent) {
58
+ customModel = customModelComponent.data
59
+ }
60
+ if (customModelDataDefinitions) {
61
+ const customModelDataComponent: any = componentMap.get('custom_model_data')
62
+ if (customModelDataComponent?.data) {
63
+ let customModelData: number | undefined
64
+ if (typeof customModelDataComponent.data === 'number') {
65
+ customModelData = customModelDataComponent.data
66
+ } else if (typeof customModelDataComponent.data === 'object'
67
+ && 'floats' in customModelDataComponent.data
68
+ && Array.isArray(customModelDataComponent.data.floats)
69
+ && customModelDataComponent.data.floats.length > 0) {
70
+ customModelData = customModelDataComponent.data.floats[0]
71
+ }
72
+ if (customModelData && customModelDataDefinitions[customModelData]) {
73
+ customModel = customModelDataDefinitions[customModelData]
74
+ }
75
+ }
76
+ }
77
+ const loreComponent = componentMap.get('lore')
78
+ if (loreComponent) {
79
+ customText ??= item.displayName ?? item.name
80
+ // todo test
81
+ customText += `\n${JSON.stringify(loreComponent.data)}`
82
+ }
83
+ }
84
+ if (item.nbt) {
85
+ const itemNbt: PossibleItemProps = nbt.simplify(item.nbt)
86
+ const customName = itemNbt.display?.Name
87
+ if (customName) {
88
+ customText = customName
89
+ }
90
+ if (customModelDataDefinitions && itemNbt.CustomModelData && customModelDataDefinitions[itemNbt.CustomModelData]) {
91
+ customModel = customModelDataDefinitions[itemNbt.CustomModelData]
92
+ }
93
+ }
94
+
95
+ return {
96
+ customText,
97
+ customModel
98
+ }
99
+ }
100
+
101
+
102
+ export const getItemNameRaw = (item: Pick<import('prismarine-item').Item, 'nbt'> | null, resourcesManager: ResourcesManagerCommon) => {
103
+ if (!item) return ''
104
+ const { customText } = getItemMetadata(item as GeneralInputItem, resourcesManager)
105
+ if (!customText) return
106
+ try {
107
+ if (typeof customText === 'object') {
108
+ return customText
109
+ }
110
+ const parsed = customText.startsWith('{') && customText.endsWith('}') ? mojangson.simplify(mojangson.parse(customText)) : fromFormattedString(customText)
111
+ if (parsed.extra) {
112
+ return parsed as Record<string, any>
113
+ } else {
114
+ return parsed as any
115
+ }
116
+ } catch (err) {
117
+ return {
118
+ text: JSON.stringify(customText)
119
+ }
120
+ }
121
+ }
122
+
123
+ export const getItemModelName = (item: GeneralInputItem, specificProps: ItemSpecificContextProperties, resourcesManager: ResourcesManagerCommon, playerState: PlayerStateRenderer) => {
124
+ let itemModelName = item.name
125
+ const { customModel } = getItemMetadata(item, resourcesManager)
126
+ if (customModel) {
127
+ itemModelName = customModel
128
+ }
129
+
130
+ const itemSelector = getItemSelector(playerState, {
131
+ ...specificProps
132
+ })
133
+ const modelFromDef = getItemDefinition(resourcesManager.currentResources!.itemsDefinitionsStore, {
134
+ name: itemModelName,
135
+ version: resourcesManager.currentResources!.version,
136
+ properties: itemSelector
137
+ })?.model
138
+ const model = (modelFromDef === 'minecraft:special' ? undefined : modelFromDef) ?? itemModelName
139
+ return model
140
+ }
@@ -0,0 +1,131 @@
1
+ /* eslint-disable no-await-in-loop */
2
+ import { Vec3 } from 'vec3'
3
+
4
+ // import log from '../../../../../Downloads/mesher (2).log'
5
+ import { WorldRendererCommon } from './worldrendererCommon'
6
+ const log = ''
7
+
8
+
9
+ export class MesherLogReader {
10
+ chunksToReceive: Array<{
11
+ x: number
12
+ z: number
13
+ chunkLength: number
14
+ }> = []
15
+ messagesQueue: Array<{
16
+ fromWorker: boolean
17
+ workerIndex: number
18
+ message: any
19
+ }> = []
20
+
21
+ sectionFinishedToReceive = null as {
22
+ messagesLeft: string[]
23
+ resolve: () => void
24
+ } | null
25
+ replayStarted = false
26
+
27
+ constructor (private readonly worldRenderer: WorldRendererCommon) {
28
+ this.parseMesherLog()
29
+ }
30
+
31
+ chunkReceived (x: number, z: number, chunkLength: number) {
32
+ // remove existing chunks with same x and z
33
+ const existingChunkIndex = this.chunksToReceive.findIndex(chunk => chunk.x === x && chunk.z === z)
34
+ if (existingChunkIndex === -1) {
35
+ // console.error('Chunk not found', x, z)
36
+ } else {
37
+ // warn if chunkLength is different
38
+ if (this.chunksToReceive[existingChunkIndex].chunkLength !== chunkLength) {
39
+ // console.warn('Chunk length mismatch', x, z, this.chunksToReceive[existingChunkIndex].chunkLength, chunkLength)
40
+ }
41
+ // remove chunk
42
+ this.chunksToReceive = this.chunksToReceive.filter((chunk, index) => chunk.x !== x || chunk.z !== z)
43
+ }
44
+ this.maybeStartReplay()
45
+ }
46
+
47
+ async maybeStartReplay () {
48
+ if (this.chunksToReceive.length !== 0 || this.replayStarted) return
49
+ const lines = log.split('\n')
50
+ console.log('starting replay')
51
+ this.replayStarted = true
52
+ const waitForWorkersMessages = async () => {
53
+ if (!this.sectionFinishedToReceive) return
54
+ await new Promise<void>(resolve => {
55
+ this.sectionFinishedToReceive!.resolve = resolve
56
+ })
57
+ }
58
+
59
+ for (const line of lines) {
60
+ if (line.includes('dispatchMessages dirty')) {
61
+ await waitForWorkersMessages()
62
+ this.worldRenderer.stopMesherMessagesProcessing = true
63
+ const message = JSON.parse(line.slice(line.indexOf('{'), line.lastIndexOf('}') + 1))
64
+ if (!message.value) continue
65
+ const index = line.split(' ')[1]
66
+ const type = line.split(' ')[3]
67
+ // console.log('sending message', message.x, message.y, message.z)
68
+ this.worldRenderer.forceCallFromMesherReplayer = true
69
+ this.worldRenderer.setSectionDirty(new Vec3(message.x, message.y, message.z), message.value)
70
+ this.worldRenderer.forceCallFromMesherReplayer = false
71
+ }
72
+ if (line.includes('-> blockUpdate')) {
73
+ await waitForWorkersMessages()
74
+ this.worldRenderer.stopMesherMessagesProcessing = true
75
+ const message = JSON.parse(line.slice(line.indexOf('{'), line.lastIndexOf('}') + 1))
76
+ this.worldRenderer.forceCallFromMesherReplayer = true
77
+ this.worldRenderer.setBlockStateIdInner(new Vec3(message.pos.x, message.pos.y, message.pos.z), message.stateId)
78
+ this.worldRenderer.forceCallFromMesherReplayer = false
79
+ }
80
+
81
+ if (line.includes(' sectionFinished ')) {
82
+ if (!this.sectionFinishedToReceive) {
83
+ console.log('starting worker message processing validating')
84
+ this.worldRenderer.stopMesherMessagesProcessing = false
85
+ this.sectionFinishedToReceive = {
86
+ messagesLeft: [],
87
+ resolve: () => {
88
+ this.sectionFinishedToReceive = null
89
+ }
90
+ }
91
+ }
92
+ const parts = line.split(' ')
93
+ const coordsPart = parts.find(part => part.split(',').length === 3)
94
+ if (!coordsPart) throw new Error(`no coords part found ${line}`)
95
+ const [x, y, z] = coordsPart.split(',').map(Number)
96
+ this.sectionFinishedToReceive.messagesLeft.push(`${x},${y},${z}`)
97
+ }
98
+ }
99
+ }
100
+
101
+ workerMessageReceived (type: string, message: any) {
102
+ if (type === 'sectionFinished') {
103
+ const { key } = message
104
+ if (!this.sectionFinishedToReceive) {
105
+ console.warn(`received sectionFinished message but no sectionFinishedToReceive ${key}`)
106
+ return
107
+ }
108
+
109
+ const idx = this.sectionFinishedToReceive.messagesLeft.indexOf(key)
110
+ if (idx === -1) {
111
+ console.warn(`received sectionFinished message for non-outstanding section ${key}`)
112
+ return
113
+ }
114
+ this.sectionFinishedToReceive.messagesLeft.splice(idx, 1)
115
+ if (this.sectionFinishedToReceive.messagesLeft.length === 0) {
116
+ this.sectionFinishedToReceive.resolve()
117
+ }
118
+ }
119
+ }
120
+
121
+ parseMesherLog () {
122
+ const lines = log.split('\n')
123
+ for (const line of lines) {
124
+ if (line.startsWith('-> chunk')) {
125
+ const chunk = JSON.parse(line.slice('-> chunk'.length))
126
+ this.chunksToReceive.push(chunk)
127
+ continue
128
+ }
129
+ }
130
+ }
131
+ }