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,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
|
+
}
|
package/src/lib/items.ts
ADDED
|
@@ -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
|
+
}
|