minecraft-renderer 0.1.31 → 0.1.32
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/dist/minecraft-renderer.js +57 -57
- package/dist/minecraft-renderer.js.meta.json +1 -1
- package/dist/threeWorker.js +419 -419
- package/package.json +1 -1
- package/src/graphicsBackend/config.ts +1 -0
- package/src/lib/worldrendererCommon.ts +1 -1
- package/src/three/hand.ts +103 -52
- package/src/three/handLegacy.ts +90 -0
- package/src/three/holdingBlock.ts +269 -335
- package/src/three/holdingBlockFactory.ts +16 -0
- package/src/three/holdingBlockLegacy.ts +957 -0
- package/src/three/holdingBlockTypes.ts +22 -0
- package/src/three/worldRendererThree.ts +26 -5
package/package.json
CHANGED
|
@@ -45,6 +45,7 @@ export const defaultWorldRendererConfig = {
|
|
|
45
45
|
// Camera visual related settings
|
|
46
46
|
showHand: false,
|
|
47
47
|
viewBobbing: false,
|
|
48
|
+
handRenderer: 'vanilla' as 'vanilla' | 'legacy',
|
|
48
49
|
renderEars: true,
|
|
49
50
|
highlightBlockColor: 'blue' as 'blue' | 'classic' | 'auto' | undefined,
|
|
50
51
|
|
|
@@ -288,7 +288,7 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
|
|
288
288
|
if (initial) {
|
|
289
289
|
callback(this.playerStateReactive[key])
|
|
290
290
|
}
|
|
291
|
-
subscribeKey(this.playerStateReactive, key, callback)
|
|
291
|
+
return subscribeKey(this.playerStateReactive, key, callback)
|
|
292
292
|
}
|
|
293
293
|
|
|
294
294
|
onReactiveConfigUpdated<T extends keyof typeof this.worldRendererConfig>(key: T, callback: (value: typeof this.worldRendererConfig[T]) => void) {
|
package/src/three/hand.ts
CHANGED
|
@@ -21,70 +21,121 @@ export const getMyHand = async (image?: string, userName?: string) => {
|
|
|
21
21
|
|
|
22
22
|
newMap.magFilter = THREE.NearestFilter
|
|
23
23
|
newMap.minFilter = THREE.NearestFilter
|
|
24
|
-
|
|
25
|
-
const box = new THREE.BoxGeometry()
|
|
26
|
-
const material = new THREE.MeshStandardMaterial()
|
|
24
|
+
|
|
27
25
|
const slim = false
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
26
|
+
const pixelWidth = slim ? 3 : 4
|
|
27
|
+
|
|
28
|
+
// Exact replica of vanilla's Cube: addBox(-3, -2, -2, 4, 12, 4) at texOffs(40, 16)
|
|
29
|
+
const box = createVanillaCubeGeometry(
|
|
30
|
+
40, 16,
|
|
31
|
+
slim ? -2 : -3, -2, -2,
|
|
32
|
+
pixelWidth, 12, 4,
|
|
33
|
+
64, 64
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
const material = new THREE.MeshStandardMaterial()
|
|
33
37
|
material.map = newMap
|
|
34
38
|
material.needsUpdate = true
|
|
39
|
+
|
|
40
|
+
const mesh = new THREE.Mesh(box, material)
|
|
41
|
+
|
|
35
42
|
const group = new THREE.Group()
|
|
36
43
|
group.add(mesh)
|
|
37
|
-
group.scale.set(0.1, 0.1, 0.1)
|
|
38
|
-
mesh.rotation.z = Math.PI
|
|
39
44
|
return group
|
|
40
45
|
}
|
|
41
46
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
47
|
+
/**
|
|
48
|
+
* Creates a BufferGeometry replicating vanilla Minecraft's ModelPart.Cube exactly.
|
|
49
|
+
* Vertices, face winding, normals, and UV mapping match the decompiled Java source.
|
|
50
|
+
* Position coordinates are in pixels, divided by 16 for block units.
|
|
51
|
+
*/
|
|
52
|
+
function createVanillaCubeGeometry (
|
|
53
|
+
texU: number, texV: number,
|
|
54
|
+
originX: number, originY: number, originZ: number,
|
|
55
|
+
sizeX: number, sizeY: number, sizeZ: number,
|
|
56
|
+
texWidth: number, texHeight: number,
|
|
57
|
+
mirror = false
|
|
58
|
+
): THREE.BufferGeometry {
|
|
59
|
+
let minX = originX / 16
|
|
60
|
+
let minY = originY / 16
|
|
61
|
+
let minZ = originZ / 16
|
|
62
|
+
let maxX = (originX + sizeX) / 16
|
|
63
|
+
let maxY = (originY + sizeY) / 16
|
|
64
|
+
let maxZ = (originZ + sizeZ) / 16
|
|
65
|
+
|
|
66
|
+
if (mirror) {
|
|
67
|
+
[minX, maxX] = [maxX, minX]
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// 8 corner vertices matching vanilla's Cube constructor
|
|
71
|
+
const V = [
|
|
72
|
+
[minX, minY, minZ], // 0
|
|
73
|
+
[maxX, minY, minZ], // 1
|
|
74
|
+
[maxX, maxY, minZ], // 2
|
|
75
|
+
[minX, maxY, minZ], // 3
|
|
76
|
+
[minX, minY, maxZ], // 4
|
|
77
|
+
[maxX, minY, maxZ], // 5
|
|
78
|
+
[maxX, maxY, maxZ], // 6
|
|
79
|
+
[minX, maxY, maxZ], // 7
|
|
57
80
|
]
|
|
58
81
|
|
|
59
|
-
|
|
60
|
-
const
|
|
61
|
-
const
|
|
62
|
-
const
|
|
63
|
-
const
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
const
|
|
67
|
-
const
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
82
|
+
// UV grid (pixel coords)
|
|
83
|
+
const u0 = texU
|
|
84
|
+
const u1 = texU + sizeZ
|
|
85
|
+
const u2 = texU + sizeZ + sizeX
|
|
86
|
+
const u3 = texU + sizeZ + sizeX + sizeX
|
|
87
|
+
const u4 = texU + sizeZ + sizeX + sizeZ
|
|
88
|
+
const u5 = texU + sizeZ + sizeX + sizeZ + sizeX
|
|
89
|
+
const v0 = texV
|
|
90
|
+
const v1 = texV + sizeZ
|
|
91
|
+
const v2 = texV + sizeZ + sizeY
|
|
92
|
+
|
|
93
|
+
// 6 faces: vanilla vertex order + UV rect + normal
|
|
94
|
+
const faces: { vi: number[]; uv: number[]; n: number[] }[] = [
|
|
95
|
+
{ vi: [5, 4, 0, 1], uv: [u1, v0, u2, v1], n: [0, -1, 0] }, // DOWN
|
|
96
|
+
{ vi: [2, 3, 7, 6], uv: [u2, v1, u3, v0], n: [0, 1, 0] }, // UP
|
|
97
|
+
{ vi: [0, 4, 7, 3], uv: [u0, v1, u1, v2], n: [-1, 0, 0] }, // WEST
|
|
98
|
+
{ vi: [1, 0, 3, 2], uv: [u1, v1, u2, v2], n: [0, 0, -1] }, // NORTH
|
|
99
|
+
{ vi: [5, 1, 2, 6], uv: [u2, v1, u4, v2], n: [1, 0, 0] }, // EAST
|
|
100
|
+
{ vi: [4, 5, 6, 7], uv: [u4, v1, u5, v2], n: [0, 0, 1] }, // SOUTH
|
|
101
|
+
]
|
|
102
|
+
|
|
103
|
+
const positions: number[] = []
|
|
104
|
+
const uvs: number[] = []
|
|
105
|
+
const normals: number[] = []
|
|
106
|
+
const indices: number[] = []
|
|
107
|
+
|
|
108
|
+
for (let fi = 0; fi < faces.length; fi++) {
|
|
109
|
+
const face = faces[fi]
|
|
110
|
+
const base = fi * 4
|
|
111
|
+
|
|
112
|
+
const [uL, vT, uR, vB] = face.uv
|
|
113
|
+
// Vanilla vertex UV order: top-right, top-left, bottom-left, bottom-right
|
|
114
|
+
const fUV = [
|
|
115
|
+
[uR / texWidth, 1 - vT / texHeight],
|
|
116
|
+
[uL / texWidth, 1 - vT / texHeight],
|
|
117
|
+
[uL / texWidth, 1 - vB / texHeight],
|
|
118
|
+
[uR / texWidth, 1 - vB / texHeight],
|
|
119
|
+
]
|
|
120
|
+
|
|
121
|
+
const order = mirror ? [3, 2, 1, 0] : [0, 1, 2, 3]
|
|
122
|
+
const nx = mirror ? -face.n[0] : face.n[0]
|
|
123
|
+
|
|
124
|
+
for (let i = 0; i < 4; i++) {
|
|
125
|
+
const vert = V[face.vi[order[i]]]
|
|
126
|
+
positions.push(vert[0], vert[1], vert[2])
|
|
127
|
+
uvs.push(fUV[i][0], fUV[i][1])
|
|
128
|
+
normals.push(nx, face.n[1], face.n[2])
|
|
81
129
|
}
|
|
130
|
+
|
|
131
|
+
indices.push(base, base + 1, base + 2, base, base + 2, base + 3)
|
|
82
132
|
}
|
|
83
133
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
134
|
+
const geometry = new THREE.BufferGeometry()
|
|
135
|
+
geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3))
|
|
136
|
+
geometry.setAttribute('uv', new THREE.Float32BufferAttribute(uvs, 2))
|
|
137
|
+
geometry.setAttribute('normal', new THREE.Float32BufferAttribute(normals, 3))
|
|
138
|
+
geometry.setIndex(indices)
|
|
87
139
|
|
|
88
|
-
|
|
89
|
-
setUVs(box, u, v, width, height, depth, 64, 64)
|
|
140
|
+
return geometry
|
|
90
141
|
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
//@ts-nocheck
|
|
2
|
+
import * as THREE from 'three'
|
|
3
|
+
import { loadSkinFromUsername, loadSkinImage } from '../lib/utils/skins'
|
|
4
|
+
import { steveTexture } from './entities'
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
export const getMyHand = async (image?: string, userName?: string) => {
|
|
8
|
+
let newMap: THREE.Texture
|
|
9
|
+
if (!image && !userName) {
|
|
10
|
+
newMap = await steveTexture
|
|
11
|
+
} else {
|
|
12
|
+
if (!image) {
|
|
13
|
+
image = await loadSkinFromUsername(userName!, 'skin')
|
|
14
|
+
}
|
|
15
|
+
if (!image) {
|
|
16
|
+
return
|
|
17
|
+
}
|
|
18
|
+
const { canvas } = await loadSkinImage(image)
|
|
19
|
+
newMap = new THREE.CanvasTexture(canvas)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
newMap.magFilter = THREE.NearestFilter
|
|
23
|
+
newMap.minFilter = THREE.NearestFilter
|
|
24
|
+
// right arm
|
|
25
|
+
const box = new THREE.BoxGeometry()
|
|
26
|
+
const material = new THREE.MeshStandardMaterial()
|
|
27
|
+
const slim = false
|
|
28
|
+
const mesh = new THREE.Mesh(box, material)
|
|
29
|
+
mesh.scale.x = slim ? 3 : 4
|
|
30
|
+
mesh.scale.y = 12
|
|
31
|
+
mesh.scale.z = 4
|
|
32
|
+
setSkinUVs(box, 40, 16, slim ? 3 : 4, 12, 4)
|
|
33
|
+
material.map = newMap
|
|
34
|
+
material.needsUpdate = true
|
|
35
|
+
const group = new THREE.Group()
|
|
36
|
+
group.add(mesh)
|
|
37
|
+
group.scale.set(0.1, 0.1, 0.1)
|
|
38
|
+
mesh.rotation.z = Math.PI
|
|
39
|
+
return group
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function setUVs (
|
|
43
|
+
box: THREE.BoxGeometry,
|
|
44
|
+
u: number,
|
|
45
|
+
v: number,
|
|
46
|
+
width: number,
|
|
47
|
+
height: number,
|
|
48
|
+
depth: number,
|
|
49
|
+
textureWidth: number,
|
|
50
|
+
textureHeight: number
|
|
51
|
+
): void {
|
|
52
|
+
const toFaceVertices = (x1: number, y1: number, x2: number, y2: number) => [
|
|
53
|
+
new THREE.Vector2(x1 / textureWidth, 1 - y2 / textureHeight),
|
|
54
|
+
new THREE.Vector2(x2 / textureWidth, 1 - y2 / textureHeight),
|
|
55
|
+
new THREE.Vector2(x2 / textureWidth, 1 - y1 / textureHeight),
|
|
56
|
+
new THREE.Vector2(x1 / textureWidth, 1 - y1 / textureHeight),
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
const top = toFaceVertices(u + depth, v, u + width + depth, v + depth)
|
|
60
|
+
const bottom = toFaceVertices(u + width + depth, v, u + width * 2 + depth, v + depth)
|
|
61
|
+
const left = toFaceVertices(u, v + depth, u + depth, v + depth + height)
|
|
62
|
+
const front = toFaceVertices(u + depth, v + depth, u + width + depth, v + depth + height)
|
|
63
|
+
const right = toFaceVertices(u + width + depth, v + depth, u + width + depth * 2, v + height + depth)
|
|
64
|
+
const back = toFaceVertices(u + width + depth * 2, v + depth, u + width * 2 + depth * 2, v + height + depth)
|
|
65
|
+
|
|
66
|
+
const uvAttr = box.attributes.uv as THREE.BufferAttribute
|
|
67
|
+
const uvRight = [right[3], right[2], right[0], right[1]]
|
|
68
|
+
const uvLeft = [left[3], left[2], left[0], left[1]]
|
|
69
|
+
const uvTop = [top[3], top[2], top[0], top[1]]
|
|
70
|
+
const uvBottom = [bottom[0], bottom[1], bottom[3], bottom[2]]
|
|
71
|
+
const uvFront = [front[3], front[2], front[0], front[1]]
|
|
72
|
+
const uvBack = [back[3], back[2], back[0], back[1]]
|
|
73
|
+
|
|
74
|
+
// Create a new array to hold the modified UV data
|
|
75
|
+
const newUVData = [] as number[]
|
|
76
|
+
|
|
77
|
+
// Iterate over the arrays and copy the data to uvData
|
|
78
|
+
for (const uvArray of [uvRight, uvLeft, uvTop, uvBottom, uvFront, uvBack]) {
|
|
79
|
+
for (const uv of uvArray) {
|
|
80
|
+
newUVData.push(uv.x, uv.y)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
uvAttr.set(new Float32Array(newUVData))
|
|
85
|
+
uvAttr.needsUpdate = true
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function setSkinUVs (box: THREE.BoxGeometry, u: number, v: number, width: number, height: number, depth: number): void {
|
|
89
|
+
setUVs(box, u, v, width, height, depth, 64, 64)
|
|
90
|
+
}
|