minecraft-renderer 0.1.79 → 0.1.81
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 +66 -26
- package/dist/mesher.js +36 -36
- package/dist/mesher.js.map +4 -4
- package/dist/mesherWasm.js +217 -217
- package/dist/minecraft-renderer.js +66 -66
- package/dist/minecraft-renderer.js.meta.json +1 -1
- package/dist/threeWorker.js +450 -450
- package/package.json +5 -2
- package/src/bundler/bundlePrepare.ts +3 -8
- package/src/graphicsBackend/appViewer.ts +10 -7
- package/src/graphicsBackend/config.ts +1 -5
- package/src/graphicsBackend/playerState.ts +35 -34
- package/src/graphicsBackend/preloadWorkers.ts +43 -41
- package/src/graphicsBackend/rendererDefaultOptions.ts +68 -70
- package/src/graphicsBackend/rendererOptionsSync.ts +24 -50
- package/src/graphicsBackend/types.ts +2 -2
- package/src/index.ts +6 -27
- package/src/lib/DebugGui.ts +34 -31
- package/src/lib/animationController.ts +9 -9
- package/src/lib/bakeLegacyLight.ts +1 -6
- package/src/lib/bindAbortableListener.test.ts +32 -12
- package/src/lib/bindAbortableListener.ts +14 -6
- package/src/lib/blockEntityLightRegistry.ts +11 -20
- package/src/lib/blockEntityLighting.test.ts +1 -6
- package/src/lib/blockEntityLighting.ts +5 -5
- package/src/lib/buildSharedConfig.mjs +4 -4
- package/src/lib/buildWorkerMcDataIndexes.test.ts +4 -4
- package/src/lib/buildWorkerMcDataIndexes.ts +11 -19
- package/src/lib/cameraBobbing.ts +1 -1
- package/src/lib/canvas2DOverlay.example.ts +13 -33
- package/src/lib/canvas2DOverlay.quickstart.ts +24 -54
- package/src/lib/canvas2DOverlay.ts +28 -47
- package/src/lib/cleanupDecorator.ts +2 -2
- package/src/lib/createPlayerObject.test.ts +2 -7
- package/src/lib/createPlayerObject.ts +18 -25
- package/src/lib/frameTimingCollector.ts +2 -5
- package/src/lib/guiRenderer.ts +57 -42
- package/src/lib/items.ts +15 -9
- package/src/lib/mesherlogReader.ts +5 -6
- package/src/lib/simpleUtils.ts +5 -5
- package/src/lib/skyLight.ts +3 -3
- package/src/lib/smoothSwitcher.ts +11 -18
- package/src/lib/ui/newStats.ts +10 -12
- package/src/lib/utils/proxy.ts +7 -1
- package/src/lib/utils/skins.ts +4 -4
- package/src/lib/utils.ts +1 -1
- package/src/lib/workerMessageSanitize.ts +5 -12
- package/src/lib/workerProxy.ts +52 -42
- package/src/lib/workerSyncOps.test.ts +58 -41
- package/src/lib/worldrendererCommon.reconfigure.test.ts +24 -21
- package/src/lib/worldrendererCommon.removeColumn.test.ts +11 -13
- package/src/lib/worldrendererCommon.ts +349 -211
- package/src/mesher-legacy/mesher.ts +9 -4
- package/src/mesher-legacy/test/a.ts +1 -1
- package/src/mesher-legacy/test/mesherTester.ts +2 -2
- package/src/mesher-legacy/test/playground.ts +1 -1
- package/src/mesher-legacy/test/run/test-js.ts +1 -1
- package/src/mesher-legacy/test/snapshotUtils.ts +3 -8
- package/src/mesher-legacy/test/test-perf.ts +1 -1
- package/src/mesher-legacy/test/tests.test.ts +2 -2
- package/src/mesher-shared/blockEntityMetadata.test.ts +7 -5
- package/src/mesher-shared/blockEntityMetadata.ts +28 -19
- package/src/mesher-shared/blockPropertiesForMeshing.ts +2 -2
- package/src/mesher-shared/computeHeightmap.ts +2 -4
- package/src/mesher-shared/exportedGeometryTypes.ts +3 -3
- package/src/mesher-shared/faceOcclusion.ts +324 -0
- package/src/mesher-shared/models.ts +80 -131
- package/src/mesher-shared/modelsGeometryCommon.ts +30 -15
- package/src/mesher-shared/shared.ts +46 -46
- package/src/mesher-shared/standaloneRenderer.ts +40 -44
- package/src/mesher-shared/tests/faceOcclusion.test.ts +179 -0
- package/src/mesher-shared/tests/liquidQuadInvariant.test.ts +12 -8
- package/src/mesher-shared/vertexShading.ts +2 -11
- package/src/mesher-shared/world.ts +19 -19
- package/src/mesher-shared/worldLighting.test.ts +2 -2
- package/src/performanceMonitor/PerformanceMonitor.ts +4 -13
- package/src/performanceMonitor/formatPerformanceFactorsDebug.ts +2 -2
- package/src/performanceMonitor/index.ts +1 -5
- package/src/performanceMonitor/types.ts +1 -1
- package/src/playerState/playerState.ts +55 -50
- package/src/playerState/types.ts +2 -8
- package/src/playground/allEntitiesDebug.ts +19 -16
- package/src/playground/baseScene.ts +29 -32
- package/src/playground/mobileControls.tsx +133 -129
- package/src/playground/playground.html +76 -73
- package/src/playground/playground.ts +14 -1
- package/src/playground/playgroundUi.tsx +100 -74
- package/src/playground/reactUtils.ts +3 -7
- package/src/playground/scenes/entities.ts +10 -7
- package/src/playground/scenes/frequentUpdates.ts +5 -5
- package/src/playground/scenes/geometryExport.ts +6 -20
- package/src/playground/scenes/highPosEntityUpdates.ts +2 -10
- package/src/playground/scenes/index.ts +1 -1
- package/src/playground/scenes/lightingStarfield.ts +18 -12
- package/src/playground/scenes/main.ts +15 -11
- package/src/playground/scenes/partialBlockCulling.ts +31 -0
- package/src/playground/scenes/railsCobweb.ts +1 -1
- package/src/playground/scenes/rotationIssue.ts +1 -1
- package/src/playground/scenes/slabsOptimization.ts +1 -2
- package/src/playground/scenes/transparencyIssue.ts +1 -1
- package/src/playground/shared.ts +2 -2
- package/src/resourcesManager/resourcesManager.ts +29 -54
- package/src/resourcesManager/resourcesManager.worker.test.ts +6 -10
- package/src/shims/minecraftData.ts +70 -24
- package/src/sign-renderer/index.html +10 -12
- package/src/sign-renderer/index.ts +29 -29
- package/src/sign-renderer/playground.ts +22 -15
- package/src/sign-renderer/tests.test.ts +16 -13
- package/src/sign-renderer/vite.config.ts +2 -2
- package/src/three/appShared.ts +46 -25
- package/src/three/bannerRenderer.ts +33 -61
- package/src/three/cameraCollisionBlockCache.ts +156 -0
- package/src/three/cameraCollisionSolidity.ts +50 -0
- package/src/three/cameraShake.ts +15 -6
- package/src/three/chunkMeshManager.ts +223 -390
- package/src/three/cinimaticScript.ts +26 -15
- package/src/three/cubeDrawSpans.ts +27 -37
- package/src/three/cubeMultiDraw.ts +9 -22
- package/src/three/documentRenderer.ts +15 -18
- package/src/three/entities.ts +175 -150
- package/src/three/entity/EntityMesh.ts +114 -108
- package/src/three/entity/animations.js +3 -3
- package/src/three/entity/armorModels.ts +15 -15
- package/src/three/entity/gltfAnimationUtils.ts +2 -5
- package/src/three/fireworks.ts +34 -32
- package/src/three/fireworksRenderer.ts +32 -29
- package/src/three/globalBlockBuffer.ts +167 -100
- package/src/three/globalLegacyBuffer.ts +248 -264
- package/src/three/graphicsBackendBase.ts +19 -25
- package/src/three/graphicsBackendOffThread.ts +12 -15
- package/src/three/hand.ts +21 -21
- package/src/three/handLegacy.ts +3 -13
- package/src/three/holdingBlock.ts +116 -79
- package/src/three/holdingBlockFactory.ts +1 -4
- package/src/three/holdingBlockItemIdentity.test.ts +25 -17
- package/src/three/holdingBlockItemIdentity.ts +9 -6
- package/src/three/holdingBlockLegacy.ts +113 -132
- package/src/three/itemMesh.ts +20 -29
- package/src/three/legacyMultiDraw.ts +10 -16
- package/src/three/legacySectionCull.ts +8 -14
- package/src/three/menuBackground/activeView.ts +1 -4
- package/src/three/menuBackground/assetUrl.ts +1 -1
- package/src/three/menuBackground/classic.ts +4 -12
- package/src/three/menuBackground/gpuPreference.ts +1 -3
- package/src/three/menuBackground/index.ts +2 -11
- package/src/three/menuBackground/renderer.ts +1 -5
- package/src/three/menuBackground/types.ts +1 -4
- package/src/three/menuBackground/v2.ts +196 -96
- package/src/three/menuBackground/v2Meta.ts +3 -3
- package/src/three/menuBackground/worldBlocks.ts +37 -35
- package/src/three/modules/blockBreakParticles.ts +59 -28
- package/src/three/modules/cameraBobbing.ts +3 -6
- package/src/three/modules/index.ts +1 -1
- package/src/three/modules/rain.ts +10 -23
- package/src/three/modules/sciFiWorldReveal.ts +11 -25
- package/src/three/modules/starfield.ts +7 -13
- package/src/three/renderSlot.ts +28 -16
- package/src/three/rendererModuleSystem.ts +1 -3
- package/src/three/sceneOrigin.ts +96 -33
- package/src/three/sectionRaycastAabb.ts +24 -110
- package/src/three/shaderCubeMesh.ts +6 -17
- package/src/three/shaders/cubeBlockShader.ts +85 -96
- package/src/three/shaders/legacyBlockShader.ts +21 -43
- package/src/three/shaders/textureIndexMapping.ts +89 -95
- package/src/three/shaders/tintPalette.ts +156 -170
- package/src/three/signTextureCache.ts +9 -12
- package/src/three/skyboxRenderer.ts +62 -70
- package/src/three/tests/chunkMeshManagerLegacy.test.ts +34 -64
- package/src/three/tests/cubeDrawSpans.test.ts +55 -25
- package/src/three/tests/globalBlockBuffer.test.ts +217 -0
- package/src/three/tests/globalLegacyBuffer.test.ts +300 -41
- package/src/three/tests/legacyMultiDraw.test.ts +8 -29
- package/src/three/tests/pr3PerFrameCpuCuts.test.ts +106 -29
- package/src/three/tests/signTextureCache.test.ts +4 -4
- package/src/three/thirdPersonVoxelRaycast.ts +120 -0
- package/src/three/threeJsMedia.ts +55 -72
- package/src/three/threeJsParticles.ts +32 -41
- package/src/three/threeJsSound.ts +3 -3
- package/src/three/threeJsUtils.ts +3 -3
- package/src/three/threeWorker.ts +2 -2
- package/src/three/waypointSprite.ts +55 -82
- package/src/three/waypoints.ts +20 -23
- package/src/three/world/cursorBlock.ts +25 -12
- package/src/three/world/vr.ts +11 -17
- package/src/three/worldGeometryExport.ts +15 -34
- package/src/three/worldRendererThree.ts +144 -166
- package/src/wasm-mesher/bridge/convertChunk.ts +3 -9
- package/src/wasm-mesher/bridge/render-from-wasm.ts +204 -229
- package/src/wasm-mesher/bridge/shaderCubeBridge.ts +26 -67
- package/src/wasm-mesher/tests/cameraCollisionBlockCache.test.ts +82 -0
- package/src/wasm-mesher/tests/cullingRegression.test.ts +307 -0
- package/src/wasm-mesher/tests/heightmapParity.test.ts +8 -18
- package/src/wasm-mesher/tests/mesherWasmConversionCache.test.ts +2 -2
- package/src/wasm-mesher/tests/sectionRaycastAabb.test.ts +1 -93
- package/src/wasm-mesher/tests/shaderCubeInstances.test.ts +103 -141
- package/src/wasm-mesher/tests/splitColumnWasmOutput.test.ts +14 -22
- package/src/wasm-mesher/tests/thirdPersonVoxelRaycast.test.ts +63 -0
- package/src/wasm-mesher/worker/mesherWasm.ts +150 -141
- package/src/wasm-mesher/worker/mesherWasmConversionCache.ts +2 -8
- package/src/wasm-mesher/worker/mesherWasmLightDirty.test.ts +1 -3
- package/src/wasm-mesher/worker/mesherWasmLightDirty.ts +1 -5
- package/src/wasm-mesher/worker/mesherWasmRequestTracker.ts +42 -42
- package/src/worldView/worldView.spiral.test.ts +1 -1
- package/src/worldView/worldView.ts +34 -39
- package/src/worldView/worldViewWorkerBridge.test.ts +4 -4
|
@@ -5,31 +5,38 @@ import { renderSign } from '.'
|
|
|
5
5
|
const PrismarineChat = PrismarineChatLoader({ language: {} } as any)
|
|
6
6
|
|
|
7
7
|
const img = new Image()
|
|
8
|
-
img.src =
|
|
8
|
+
img.src =
|
|
9
|
+
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAMCAYAAAB4MH11AAABbElEQVR4AY3BQY6cMBBA0Q+yQZZVi+ndcJVcKGfMgegdvShKVtuokzGSWwwiUd7rfv388Vst0UgMXCobmgsSA5VaQmKgUks0EgNHji8SA9W8GJCQwVNpLhzJ4KFs4B1HEgPVvBiQkMFTaS44tYTEQDXdIkfiHbuyobmguaDPFzIWGrWExEA13SJH4h1uzS/WbPyvroM1v6jWbFRrNv7GfX5EdmXjzTvUEjJ4zjQXjiQGdmXjzTvUEjJ4HF/UEt/kQqW5UEkMzIshY08jg6dRS3yTC5XmgpsXY7pFztQSEgPNJCNv3lGpJVSfTLfImVpCYsB1HdwfxpU1G9eeNF0H94dxZc2G+/yI7MoG3vEv82LI2NNIDLyVDbzjzFE2mnkxZOy5IoNnkpFGc2FXNpp5MWTsOXJ4h1qikrGnkhjYlY1m1icy9lQSA+TCzjvUEpWMPZXEwK5suPvDOFuzcdZ1sOYX1ZqNas3GlTUbzR+jQbEAcs8ZQAAAAABJRU5ErkJggg=='
|
|
9
10
|
|
|
10
11
|
await new Promise<void>(resolve => {
|
|
11
12
|
img.onload = () => resolve()
|
|
12
13
|
})
|
|
13
14
|
|
|
14
15
|
const blockEntity = {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
GlowingText: 0,
|
|
17
|
+
Color: 'black',
|
|
18
|
+
Text4: '{"text":""}',
|
|
19
|
+
Text3: '{"text":""}',
|
|
20
|
+
Text2: '{"text":""}',
|
|
21
|
+
Text1: '{"extra":[{"color":"dark_green","text":"Minecraft "},{"text":"Tools"}],"text":""}'
|
|
21
22
|
} as const
|
|
22
23
|
|
|
23
24
|
await document.fonts.load('1em mojangles')
|
|
24
25
|
|
|
25
|
-
const canvas = renderSign(
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
26
|
+
const canvas = renderSign(
|
|
27
|
+
blockEntity,
|
|
28
|
+
false,
|
|
29
|
+
PrismarineChat,
|
|
30
|
+
ctx => {
|
|
31
|
+
ctx.drawImage(img, 0, 0, ctx.canvas.width, ctx.canvas.height)
|
|
32
|
+
},
|
|
33
|
+
(width, height) => {
|
|
34
|
+
const canvas = document.createElement('canvas')
|
|
35
|
+
canvas.width = width
|
|
36
|
+
canvas.height = height
|
|
37
|
+
return canvas as unknown as OffscreenCanvas
|
|
38
|
+
}
|
|
39
|
+
) as unknown as HTMLCanvasElement
|
|
33
40
|
|
|
34
41
|
if (canvas) {
|
|
35
42
|
canvas.style.imageRendering = 'pixelated'
|
|
@@ -14,14 +14,16 @@ globalThis.document = {
|
|
|
14
14
|
fillText(text, x, y) {
|
|
15
15
|
ctxTexts.push({ text, x, y })
|
|
16
16
|
},
|
|
17
|
-
measureText() {
|
|
17
|
+
measureText() {
|
|
18
|
+
return 0
|
|
19
|
+
}
|
|
18
20
|
}
|
|
19
21
|
}
|
|
20
22
|
}
|
|
21
23
|
}
|
|
22
24
|
} as any
|
|
23
25
|
|
|
24
|
-
const render =
|
|
26
|
+
const render = entity => {
|
|
25
27
|
ctxTexts = []
|
|
26
28
|
renderSign(entity, true, PrismarineChat)
|
|
27
29
|
return ctxTexts.map(({ text, y }) => [y / 64, text])
|
|
@@ -29,12 +31,12 @@ const render = (entity) => {
|
|
|
29
31
|
|
|
30
32
|
test('sign renderer', () => {
|
|
31
33
|
let blockEntity = {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
GlowingText: 0,
|
|
35
|
+
Color: 'black',
|
|
36
|
+
Text4: '{"text":""}',
|
|
37
|
+
Text3: '{"text":""}',
|
|
38
|
+
Text2: '{"text":""}',
|
|
39
|
+
Text1: '{"extra":[{"color":"dark_green","text":"Minecraft "},{"text":"Tools"}],"text":""}'
|
|
38
40
|
} as any
|
|
39
41
|
expect(render(blockEntity)).toMatchInlineSnapshot(`
|
|
40
42
|
[
|
|
@@ -49,11 +51,12 @@ test('sign renderer', () => {
|
|
|
49
51
|
]
|
|
50
52
|
`)
|
|
51
53
|
|
|
52
|
-
blockEntity = {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
blockEntity = {
|
|
55
|
+
// pre flatenning
|
|
56
|
+
Text1: 'Welcome to',
|
|
57
|
+
Text2: '',
|
|
58
|
+
Text3: 'null',
|
|
59
|
+
Text4: '"Version 2.1"'
|
|
57
60
|
} as const
|
|
58
61
|
expect(render(blockEntity)).toMatchInlineSnapshot(`
|
|
59
62
|
[
|
package/src/three/appShared.ts
CHANGED
|
@@ -6,37 +6,55 @@ import { GeneralInputItem, getItemModelName } from '../lib/items'
|
|
|
6
6
|
import { ResourcesManagerTransferred } from '../resourcesManager'
|
|
7
7
|
import { renderSlot } from './renderSlot'
|
|
8
8
|
|
|
9
|
-
export const getItemUv = (
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
9
|
+
export const getItemUv = (
|
|
10
|
+
item: Record<string, any>,
|
|
11
|
+
specificProps: ItemSpecificContextProperties,
|
|
12
|
+
resourcesManager: ResourcesManagerTransferred,
|
|
13
|
+
playerState: PlayerStateRenderer
|
|
14
|
+
):
|
|
15
|
+
| {
|
|
16
|
+
u: number
|
|
17
|
+
v: number
|
|
18
|
+
su: number
|
|
19
|
+
sv: number
|
|
20
|
+
renderInfo?: ReturnType<typeof renderSlot>
|
|
21
|
+
// texture: ImageBitmap
|
|
22
|
+
modelName: string
|
|
23
|
+
}
|
|
24
|
+
| {
|
|
25
|
+
resolvedModel: BlockModel
|
|
26
|
+
modelName: string
|
|
27
|
+
} => {
|
|
21
28
|
const resources = resourcesManager.currentResources
|
|
22
29
|
if (!resources) throw new Error('Resources not loaded')
|
|
23
30
|
const idOrName = item.itemId ?? item.blockId ?? item.name
|
|
24
31
|
const { blockState } = item
|
|
25
32
|
try {
|
|
26
|
-
const name =
|
|
27
|
-
blockState
|
|
28
|
-
|
|
29
|
-
|
|
33
|
+
const name = blockState
|
|
34
|
+
? globalThis.loadedData.blocksByStateId[blockState]?.name
|
|
35
|
+
: typeof idOrName === 'number'
|
|
36
|
+
? globalThis.loadedData.items[idOrName]?.name
|
|
37
|
+
: idOrName
|
|
30
38
|
if (!name) throw new Error(`Item not found: ${idOrName}`)
|
|
31
39
|
|
|
32
|
-
const model = getItemModelName(
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
40
|
+
const model = getItemModelName(
|
|
41
|
+
{
|
|
42
|
+
...item,
|
|
43
|
+
name
|
|
44
|
+
} as GeneralInputItem,
|
|
45
|
+
specificProps,
|
|
46
|
+
resourcesManager,
|
|
47
|
+
playerState
|
|
48
|
+
)
|
|
36
49
|
|
|
37
|
-
const renderInfo = renderSlot(
|
|
38
|
-
|
|
39
|
-
|
|
50
|
+
const renderInfo = renderSlot(
|
|
51
|
+
{
|
|
52
|
+
modelName: model
|
|
53
|
+
},
|
|
54
|
+
resourcesManager,
|
|
55
|
+
false,
|
|
56
|
+
true
|
|
57
|
+
)
|
|
40
58
|
|
|
41
59
|
if (!renderInfo) throw new Error(`Failed to get render info for item ${name}`)
|
|
42
60
|
|
|
@@ -51,9 +69,12 @@ export const getItemUv = (item: Record<string, any>, specificProps: ItemSpecific
|
|
|
51
69
|
if (renderInfo.slice) {
|
|
52
70
|
// Get slice coordinates from either block or item texture
|
|
53
71
|
const [x, y, w, h] = renderInfo.slice
|
|
54
|
-
const [u, v, su, sv] = [x / img.width, y / img.height,
|
|
72
|
+
const [u, v, su, sv] = [x / img.width, y / img.height, w / img.width, h / img.height]
|
|
55
73
|
return {
|
|
56
|
-
u,
|
|
74
|
+
u,
|
|
75
|
+
v,
|
|
76
|
+
su,
|
|
77
|
+
sv,
|
|
57
78
|
renderInfo,
|
|
58
79
|
// texture: img,
|
|
59
80
|
modelName: renderInfo.modelName!
|
|
@@ -18,22 +18,22 @@ const BANNER_HEIGHT = 40
|
|
|
18
18
|
|
|
19
19
|
// Map banner block names to base color IDs
|
|
20
20
|
const BANNER_NAME_TO_COLOR: Record<string, number> = {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
21
|
+
white_banner: 15,
|
|
22
|
+
orange_banner: 14,
|
|
23
|
+
magenta_banner: 13,
|
|
24
|
+
light_blue_banner: 12,
|
|
25
|
+
yellow_banner: 11,
|
|
26
|
+
lime_banner: 10,
|
|
27
|
+
pink_banner: 9,
|
|
28
|
+
gray_banner: 8,
|
|
29
|
+
light_gray_banner: 7,
|
|
30
|
+
cyan_banner: 6,
|
|
31
|
+
purple_banner: 5,
|
|
32
|
+
blue_banner: 4,
|
|
33
|
+
brown_banner: 3,
|
|
34
|
+
green_banner: 2,
|
|
35
|
+
red_banner: 1,
|
|
36
|
+
black_banner: 0
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
// Basic Minecraft banner colors (DyeColor enum values)
|
|
@@ -53,7 +53,7 @@ const BANNER_COLORS: Record<number, string> = {
|
|
|
53
53
|
12: '#3ab3da', // light_blue
|
|
54
54
|
13: '#c74ebd', // magenta
|
|
55
55
|
14: '#f9801d', // orange
|
|
56
|
-
15: '#f9fffe'
|
|
56
|
+
15: '#f9fffe' // white
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
// Extract base color from banner block name
|
|
@@ -64,15 +64,7 @@ function getBannerBaseColor(blockName: string): number {
|
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
// Basic pattern rendering (simplified - just solid colors for now)
|
|
67
|
-
const renderPattern = (
|
|
68
|
-
ctx: OffscreenCanvasRenderingContext2D,
|
|
69
|
-
pattern: string,
|
|
70
|
-
color: string,
|
|
71
|
-
x: number,
|
|
72
|
-
y: number,
|
|
73
|
-
width: number,
|
|
74
|
-
height: number
|
|
75
|
-
) => {
|
|
67
|
+
const renderPattern = (ctx: OffscreenCanvasRenderingContext2D, pattern: string, color: string, x: number, y: number, width: number, height: number) => {
|
|
76
68
|
ctx.fillStyle = color
|
|
77
69
|
// For now, just render basic patterns as solid colors
|
|
78
70
|
// TODO: Implement actual pattern shapes (stripes, crosses, etc.)
|
|
@@ -84,19 +76,19 @@ const renderPattern = (
|
|
|
84
76
|
ctx.fillRect(x, y, width / 3, height)
|
|
85
77
|
break
|
|
86
78
|
case 'rs': // Right stripe
|
|
87
|
-
ctx.fillRect(x + (width * 2 / 3
|
|
79
|
+
ctx.fillRect(x + (width * 2) / 3, y, width / 3, height)
|
|
88
80
|
break
|
|
89
81
|
case 'ts': // Top stripe
|
|
90
82
|
ctx.fillRect(x, y, width, height / 3)
|
|
91
83
|
break
|
|
92
84
|
case 'ms': // Middle stripe
|
|
93
|
-
ctx.fillRect(x, y +
|
|
85
|
+
ctx.fillRect(x, y + height / 3, width, height / 3)
|
|
94
86
|
break
|
|
95
87
|
case 'drs': // Down-right stripe
|
|
96
88
|
ctx.fillRect(x, y, width / 2, height / 2)
|
|
97
89
|
break
|
|
98
90
|
case 'dls': // Down-left stripe
|
|
99
|
-
ctx.fillRect(x +
|
|
91
|
+
ctx.fillRect(x + width / 2, y, width / 2, height / 2)
|
|
100
92
|
break
|
|
101
93
|
case 'ss': // Small stripes
|
|
102
94
|
for (let i = 0; i < width; i += 2) {
|
|
@@ -104,12 +96,12 @@ const renderPattern = (
|
|
|
104
96
|
}
|
|
105
97
|
break
|
|
106
98
|
case 'cr': // Cross
|
|
107
|
-
ctx.fillRect(x, y +
|
|
108
|
-
ctx.fillRect(x +
|
|
99
|
+
ctx.fillRect(x, y + height / 3, width, height / 3)
|
|
100
|
+
ctx.fillRect(x + width / 3, y, width / 3, height)
|
|
109
101
|
break
|
|
110
102
|
case 'sc': // Straight cross
|
|
111
|
-
ctx.fillRect(x, y +
|
|
112
|
-
ctx.fillRect(x +
|
|
103
|
+
ctx.fillRect(x, y + height / 2 - 1, width, 2)
|
|
104
|
+
ctx.fillRect(x + width / 2 - 1, y, 2, height)
|
|
113
105
|
break
|
|
114
106
|
default:
|
|
115
107
|
// Default: fill entire area
|
|
@@ -118,7 +110,7 @@ const renderPattern = (
|
|
|
118
110
|
}
|
|
119
111
|
|
|
120
112
|
// Create a cache key from banner content (base color + patterns)
|
|
121
|
-
function createBannerCacheKey(baseColor: number, patterns: Array<{ Color?: number
|
|
113
|
+
function createBannerCacheKey(baseColor: number, patterns: Array<{ Color?: number; Pattern?: string }> | undefined): string {
|
|
122
114
|
if (!patterns || patterns.length === 0) {
|
|
123
115
|
return `banner_${baseColor}_empty`
|
|
124
116
|
}
|
|
@@ -159,30 +151,17 @@ export const renderBanner = (
|
|
|
159
151
|
const color = BANNER_COLORS[colorId] || BANNER_COLORS[0]
|
|
160
152
|
|
|
161
153
|
// Render each pattern on top of previous ones
|
|
162
|
-
renderPattern(
|
|
163
|
-
ctx,
|
|
164
|
-
pattern,
|
|
165
|
-
color,
|
|
166
|
-
0,
|
|
167
|
-
0,
|
|
168
|
-
BANNER_WIDTH * scale,
|
|
169
|
-
BANNER_HEIGHT * scale
|
|
170
|
-
)
|
|
154
|
+
renderPattern(ctx, pattern, color, 0, 0, BANNER_WIDTH * scale, BANNER_HEIGHT * scale)
|
|
171
155
|
}
|
|
172
156
|
}
|
|
173
157
|
|
|
174
158
|
return canvas
|
|
175
159
|
}
|
|
176
160
|
|
|
177
|
-
|
|
178
161
|
// Banner texture cache with reference counting
|
|
179
|
-
const bannerTextureCache = new Map<string, { texture: THREE.Texture
|
|
162
|
+
const bannerTextureCache = new Map<string, { texture: THREE.Texture; refCount: number }>()
|
|
180
163
|
|
|
181
|
-
export function getBannerTexture(
|
|
182
|
-
worldRenderer: WorldRendererThree,
|
|
183
|
-
blockName: string,
|
|
184
|
-
blockEntity: any
|
|
185
|
-
): THREE.Texture | undefined {
|
|
164
|
+
export function getBannerTexture(worldRenderer: WorldRendererThree, blockName: string, blockEntity: any): THREE.Texture | undefined {
|
|
186
165
|
// Extract base color from block name
|
|
187
166
|
const baseColor = getBannerBaseColor(blockName)
|
|
188
167
|
|
|
@@ -232,8 +211,8 @@ export function createBannerMesh(
|
|
|
232
211
|
texture: THREE.Texture,
|
|
233
212
|
blockLightNorm = 0,
|
|
234
213
|
skyLightNorm = 1,
|
|
235
|
-
skyLevel = 1
|
|
236
|
-
): THREE.Group & { bannerTexture?: THREE.Texture
|
|
214
|
+
skyLevel = 1
|
|
215
|
+
): THREE.Group & { bannerTexture?: THREE.Texture; bannerMaterial?: THREE.MeshBasicMaterial } {
|
|
237
216
|
const bannerWidth = 13.6 / 16
|
|
238
217
|
const bannerHeight = 28 / 16
|
|
239
218
|
const clothXOffset = 0
|
|
@@ -256,10 +235,7 @@ export function createBannerMesh(
|
|
|
256
235
|
|
|
257
236
|
const material = new THREE.MeshBasicMaterial({ map: texture, transparent: true })
|
|
258
237
|
tintBannerMaterial(material, blockLightNorm, skyLightNorm, skyLevel)
|
|
259
|
-
const mesh = new THREE.Mesh(
|
|
260
|
-
new THREE.PlaneGeometry(bannerWidth, bannerHeight),
|
|
261
|
-
material,
|
|
262
|
-
)
|
|
238
|
+
const mesh = new THREE.Mesh(new THREE.PlaneGeometry(bannerWidth, bannerHeight), material)
|
|
263
239
|
mesh.renderOrder = 999
|
|
264
240
|
|
|
265
241
|
const thickness = 0.5 / 16
|
|
@@ -274,11 +250,7 @@ export function createBannerMesh(
|
|
|
274
250
|
bannerTexture?: THREE.Texture
|
|
275
251
|
bannerMaterial?: THREE.MeshBasicMaterial
|
|
276
252
|
}
|
|
277
|
-
group.rotation.set(
|
|
278
|
-
0,
|
|
279
|
-
-THREE.MathUtils.degToRad(rotation * (isWall ? 90 : 45 / 2)),
|
|
280
|
-
0
|
|
281
|
-
)
|
|
253
|
+
group.rotation.set(0, -THREE.MathUtils.degToRad(rotation * (isWall ? 90 : 45 / 2)), 0)
|
|
282
254
|
group.add(mesh)
|
|
283
255
|
group.bannerTexture = texture
|
|
284
256
|
group.bannerMaterial = material
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
//@ts-nocheck
|
|
2
|
+
import Chunks from 'prismarine-chunk'
|
|
3
|
+
import { Vec3 } from 'vec3'
|
|
4
|
+
import { getCameraCollisionSolidityTable, isStateIdSolidForCameraCollision } from './cameraCollisionSolidity'
|
|
5
|
+
|
|
6
|
+
/** 16³ blocks per section; 1 bit per block. */
|
|
7
|
+
const WORDS_PER_SECTION = 128
|
|
8
|
+
export const CAMERA_COLLISION_BYTES_PER_SECTION = WORDS_PER_SECTION * 4
|
|
9
|
+
|
|
10
|
+
type SectionBitset = Uint32Array
|
|
11
|
+
|
|
12
|
+
const sectionKey = (sx: number, sy: number, sz: number) => `${sx},${sy},${sz}`
|
|
13
|
+
|
|
14
|
+
const alignSection = (coord: number) => Math.floor(coord / 16) * 16
|
|
15
|
+
|
|
16
|
+
const localCoord = (coord: number) => ((coord % 16) + 16) % 16
|
|
17
|
+
|
|
18
|
+
const blockBitIndex = (lx: number, ly: number, lz: number) => lx + lz * 16 + ly * 256
|
|
19
|
+
|
|
20
|
+
const getBit = (bits: SectionBitset, idx: number) => {
|
|
21
|
+
const word = idx >>> 5
|
|
22
|
+
return (bits[word]! & (1 << (idx & 31))) !== 0
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const setBit = (bits: SectionBitset, idx: number, value: boolean) => {
|
|
26
|
+
const word = idx >>> 5
|
|
27
|
+
const mask = 1 << (idx & 31)
|
|
28
|
+
if (value) bits[word]! |= mask
|
|
29
|
+
else bits[word]! &= ~mask
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const isBitsetEmpty = (bits: SectionBitset) => {
|
|
33
|
+
for (let i = 0; i < WORDS_PER_SECTION; i++) {
|
|
34
|
+
if (bits[i]!) return false
|
|
35
|
+
}
|
|
36
|
+
return true
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Sparse 1-bit-per-block solidity cache for third-person voxel DDA.
|
|
41
|
+
* Allocates a 512-byte section bitset only when it contains ≥1 solid block.
|
|
42
|
+
*/
|
|
43
|
+
export class CameraCollisionBlockCache {
|
|
44
|
+
private readonly sections = new Map<string, SectionBitset>()
|
|
45
|
+
private Chunk: ReturnType<typeof Chunks>
|
|
46
|
+
private solidityTable: Uint8Array
|
|
47
|
+
private worldMinY = 0
|
|
48
|
+
private worldMaxY = 256
|
|
49
|
+
|
|
50
|
+
constructor(version: string) {
|
|
51
|
+
this.Chunk = Chunks(version) as ReturnType<typeof Chunks>
|
|
52
|
+
this.solidityTable = getCameraCollisionSolidityTable(version)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
setVersion(version: string) {
|
|
56
|
+
this.Chunk = Chunks(version) as ReturnType<typeof Chunks>
|
|
57
|
+
this.solidityTable = getCameraCollisionSolidityTable(version)
|
|
58
|
+
this.sections.clear()
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
setWorldBounds(minY: number, worldHeight: number) {
|
|
62
|
+
if (this.worldMinY === minY && this.worldMaxY === worldHeight) return
|
|
63
|
+
this.worldMinY = minY
|
|
64
|
+
this.worldMaxY = worldHeight
|
|
65
|
+
this.sections.clear()
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
clear() {
|
|
69
|
+
this.sections.clear()
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** Allocated 16³ section bitsets (512 bytes each). */
|
|
73
|
+
getAllocatedSectionCount(): number {
|
|
74
|
+
return this.sections.size
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
getAllocatedBytes(): number {
|
|
78
|
+
return this.sections.size * CAMERA_COLLISION_BYTES_PER_SECTION
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
removeColumn(chunkX: number, chunkZ: number) {
|
|
82
|
+
const syStart = alignSection(this.worldMinY)
|
|
83
|
+
for (let sy = syStart; sy < this.worldMaxY; sy += 16) {
|
|
84
|
+
this.sections.delete(sectionKey(chunkX, sy, chunkZ))
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
ingestColumn(chunkX: number, chunkZ: number, chunkJson: unknown) {
|
|
89
|
+
const chunk = this.Chunk.fromJson(chunkJson as Parameters<ReturnType<typeof Chunks>['fromJson']>[0]) as unknown as {
|
|
90
|
+
getBlockStateId: (pos: Vec3) => number
|
|
91
|
+
}
|
|
92
|
+
const pos = new Vec3(0, 0, 0)
|
|
93
|
+
|
|
94
|
+
for (let y = this.worldMinY; y < this.worldMaxY; y++) {
|
|
95
|
+
pos.y = y
|
|
96
|
+
const sy = alignSection(y)
|
|
97
|
+
const ly = y - sy
|
|
98
|
+
for (let lz = 0; lz < 16; lz++) {
|
|
99
|
+
pos.z = lz
|
|
100
|
+
const wz = chunkZ + lz
|
|
101
|
+
const sz = alignSection(wz)
|
|
102
|
+
const lzLocal = wz - sz
|
|
103
|
+
for (let lx = 0; lx < 16; lx++) {
|
|
104
|
+
pos.x = lx
|
|
105
|
+
const stateId = chunk.getBlockStateId(pos) || 0
|
|
106
|
+
if (!isStateIdSolidForCameraCollision(stateId, this.solidityTable)) continue
|
|
107
|
+
|
|
108
|
+
const wx = chunkX + lx
|
|
109
|
+
const sx = alignSection(wx)
|
|
110
|
+
const key = sectionKey(sx, sy, sz)
|
|
111
|
+
let bits = this.sections.get(key)
|
|
112
|
+
if (!bits) {
|
|
113
|
+
bits = new Uint32Array(WORDS_PER_SECTION)
|
|
114
|
+
this.sections.set(key, bits)
|
|
115
|
+
}
|
|
116
|
+
setBit(bits, blockBitIndex(wx - sx, ly, lzLocal), true)
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
setBlockStateId(x: number, y: number, z: number, stateId: number) {
|
|
123
|
+
if (y < this.worldMinY || y >= this.worldMaxY) return
|
|
124
|
+
|
|
125
|
+
const sx = alignSection(x)
|
|
126
|
+
const sy = alignSection(y)
|
|
127
|
+
const sz = alignSection(z)
|
|
128
|
+
const key = sectionKey(sx, sy, sz)
|
|
129
|
+
const idx = blockBitIndex(localCoord(x), y - sy, localCoord(z))
|
|
130
|
+
const solid = isStateIdSolidForCameraCollision(stateId, this.solidityTable)
|
|
131
|
+
|
|
132
|
+
if (solid) {
|
|
133
|
+
let bits = this.sections.get(key)
|
|
134
|
+
if (!bits) {
|
|
135
|
+
bits = new Uint32Array(WORDS_PER_SECTION)
|
|
136
|
+
this.sections.set(key, bits)
|
|
137
|
+
}
|
|
138
|
+
setBit(bits, idx, true)
|
|
139
|
+
return
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const bits = this.sections.get(key)
|
|
143
|
+
if (!bits) return
|
|
144
|
+
setBit(bits, idx, false)
|
|
145
|
+
if (isBitsetEmpty(bits)) this.sections.delete(key)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
isSolidBlock(x: number, y: number, z: number): boolean {
|
|
149
|
+
if (y < this.worldMinY || y >= this.worldMaxY) return false
|
|
150
|
+
|
|
151
|
+
const bits = this.sections.get(sectionKey(alignSection(x), alignSection(y), alignSection(z)))
|
|
152
|
+
if (!bits) return false
|
|
153
|
+
|
|
154
|
+
return getBit(bits, blockBitIndex(localCoord(x), y - alignSection(y), localCoord(z)))
|
|
155
|
+
}
|
|
156
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
//@ts-nocheck
|
|
2
|
+
import MinecraftData from 'minecraft-data'
|
|
3
|
+
import PrismarineBlockLoader from 'prismarine-block'
|
|
4
|
+
import moreBlockDataGeneratedJson from '../lib/moreBlockDataGenerated.json'
|
|
5
|
+
|
|
6
|
+
const solidityCache = new Map<string, Uint8Array>()
|
|
7
|
+
|
|
8
|
+
const PASS_THROUGH_NAMES = new Set(['water', 'flowing_water', 'lava', 'flowing_lava', 'grass', 'short_grass', 'tall_grass'])
|
|
9
|
+
|
|
10
|
+
/** 1 = blocks third-person camera DDA; 0 = pass-through (air, plants, fluids). */
|
|
11
|
+
export function getCameraCollisionSolidityTable(version: string): Uint8Array {
|
|
12
|
+
const cached = solidityCache.get(version)
|
|
13
|
+
if (cached) return cached
|
|
14
|
+
|
|
15
|
+
const mcData = MinecraftData(version)
|
|
16
|
+
const Block = PrismarineBlockLoader(version)
|
|
17
|
+
const noOcclusionsSet = new Set(Object.keys(moreBlockDataGeneratedJson.noOcclusions))
|
|
18
|
+
const invisibleNames = new Set(mcData.blocksArray.filter(b => moreBlockDataGeneratedJson.invisibleBlocks[b.name]).map(b => b.name))
|
|
19
|
+
|
|
20
|
+
let maxStateId = 0
|
|
21
|
+
for (const idStr of Object.keys((mcData as { blocksByStateId: Record<string, unknown> }).blocksByStateId)) {
|
|
22
|
+
maxStateId = Math.max(maxStateId, Number(idStr))
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const table = new Uint8Array(maxStateId + 1)
|
|
26
|
+
for (const idStr of Object.keys((mcData as { blocksByStateId: Record<string, unknown> }).blocksByStateId)) {
|
|
27
|
+
const stateId = Number(idStr)
|
|
28
|
+
if (!stateId) continue
|
|
29
|
+
|
|
30
|
+
const block = (
|
|
31
|
+
Block as { fromStateId: (id: number, y: number) => { name: string; transparent: boolean; boundingBox: string; shapes?: number[][] } | null }
|
|
32
|
+
).fromStateId(stateId, 0)
|
|
33
|
+
if (!block) continue
|
|
34
|
+
if (invisibleNames.has(block.name)) continue
|
|
35
|
+
if (noOcclusionsSet.has(block.name)) continue
|
|
36
|
+
if (PASS_THROUGH_NAMES.has(block.name)) continue
|
|
37
|
+
if (block.boundingBox === 'empty') continue
|
|
38
|
+
if (block.transparent && block.boundingBox !== 'block') continue
|
|
39
|
+
if (!block.shapes || block.shapes.length === 0) continue
|
|
40
|
+
|
|
41
|
+
table[stateId] = 1
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
solidityCache.set(version, table)
|
|
45
|
+
return table
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function isStateIdSolidForCameraCollision(stateId: number, solidityTable: Uint8Array): boolean {
|
|
49
|
+
return stateId > 0 && stateId < solidityTable.length && solidityTable[stateId] === 1
|
|
50
|
+
}
|
package/src/three/cameraShake.ts
CHANGED
|
@@ -5,9 +5,13 @@ import { WorldRendererThree } from './worldRendererThree'
|
|
|
5
5
|
|
|
6
6
|
export class CameraShake {
|
|
7
7
|
private rollAngle = 0
|
|
8
|
-
private get damageRollAmount() {
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
private get damageRollAmount() {
|
|
9
|
+
return 5
|
|
10
|
+
}
|
|
11
|
+
private get damageAnimDuration() {
|
|
12
|
+
return 200
|
|
13
|
+
}
|
|
14
|
+
private rollAnimation?: { startTime: number; startRoll: number; targetRoll: number; duration: number; returnToZero?: boolean }
|
|
11
15
|
private basePitch = 0
|
|
12
16
|
private baseYaw = 0
|
|
13
17
|
private cameraBobInput: CameraBobInput | null = null
|
|
@@ -16,7 +20,10 @@ export class CameraShake {
|
|
|
16
20
|
this.cameraBobInput = input
|
|
17
21
|
}
|
|
18
22
|
|
|
19
|
-
constructor(
|
|
23
|
+
constructor(
|
|
24
|
+
public worldRenderer: WorldRendererThree,
|
|
25
|
+
public onRenderCallbacks: Array<(deltaTime: number) => void>
|
|
26
|
+
) {
|
|
20
27
|
onRenderCallbacks.push(() => {
|
|
21
28
|
this.update()
|
|
22
29
|
})
|
|
@@ -133,10 +140,12 @@ export class CameraShake {
|
|
|
133
140
|
const normalizedAngle = ((angle % (Math.PI * 2)) + Math.PI * 2) % (Math.PI * 2)
|
|
134
141
|
const tolerance = 0.01 // Tolerance for considering an angle "ideal"
|
|
135
142
|
|
|
136
|
-
if (
|
|
143
|
+
if (
|
|
144
|
+
Math.abs(normalizedAngle) < tolerance ||
|
|
137
145
|
Math.abs(normalizedAngle - Math.PI / 2) < tolerance ||
|
|
138
146
|
Math.abs(normalizedAngle - Math.PI) < tolerance ||
|
|
139
|
-
Math.abs(normalizedAngle - 3 * Math.PI / 2) < tolerance
|
|
147
|
+
Math.abs(normalizedAngle - (3 * Math.PI) / 2) < tolerance
|
|
148
|
+
) {
|
|
140
149
|
return angle + offset
|
|
141
150
|
}
|
|
142
151
|
|