Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

release very soon #196

Merged
merged 9 commits into from
Sep 5, 2024
1 change: 1 addition & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<!DOCTYPE html>
<html>
<head>
<meta name="darkreader-lock">
<script>
window.startLoad = Date.now()
</script>
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
"esbuild-plugin-polyfill-node": "^0.3.0",
"express": "^4.18.2",
"filesize": "^10.0.12",
"flying-squid": "npm:@zardoy/flying-squid@^0.0.36",
"flying-squid": "npm:@zardoy/flying-squid@^0.0.38",
"fs-extra": "^11.1.1",
"google-drive-browserfs": "github:zardoy/browserfs#google-drive",
"jszip": "^3.10.1",
Expand Down
10 changes: 5 additions & 5 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,9 @@ import { disposeObject } from './threeJsUtils'

export const TWEEN_DURATION = 120

/**
* @param {string} username
*/
function getUsernameTexture(username, { fontFamily = 'sans-serif' }) {
type PlayerObjectType = PlayerObject & { animation?: PlayerAnimation }

function getUsernameTexture (username: string, { fontFamily = 'sans-serif' }: any) {
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
if (!ctx) throw new Error('Could not get 2d context')
Expand Down Expand Up @@ -64,7 +63,7 @@ const addNametag = (entity, options, mesh) => {
// todo cleanup
const nametags = {}

function getEntityMesh(entity, scene, options, overrides) {
function getEntityMesh (entity, scene, options, overrides) {
if (entity.name) {
try {
// https://github.com/PrismarineJS/prismarine-viewer/pull/410
Expand Down Expand Up @@ -94,34 +93,52 @@ function getEntityMesh(entity, scene, options, overrides) {
return cube
}

export type SceneEntity = THREE.Object3D & {
playerObject?: PlayerObject & {
animation?: PlayerAnimation
}
username?: string
additionalCleanup?: () => void
}

export class Entities extends EventEmitter {
constructor(scene) {
entities = {} as Record<string, SceneEntity>
entitiesOptions: {
fontFamily?: string
} = {}
debugMode: string
onSkinUpdate: () => void
clock = new THREE.Clock()
rendering = true
itemsTexture: THREE.Texture | null = null
getItemUv: undefined | ((idOrName: number | string) => {
texture: THREE.Texture;
u: number;
v: number;
su?: number;
sv?: number;
size?: number;
})

constructor (public scene: THREE.Scene) {
super()
/** @type {THREE.Scene} */
this.scene = scene
this.entities = {}
this.entitiesOptions = {}
this.debugMode = 'none'
this.onSkinUpdate = () => { }
this.clock = new THREE.Clock()
this.rendering = true
/** @type {THREE.Texture | null} */
this.itemsTexture = null
this.getItemUv = undefined
}

clear() {
clear () {
for (const mesh of Object.values(this.entities)) {
this.scene.remove(mesh)
disposeObject(mesh)
}
this.entities = {}
}

setDebugMode(mode, /** @type {THREE.Object3D?} */entity = null) {
setDebugMode (mode: string, entity: THREE.Object3D | null = null) {
this.debugMode = mode
for (const mesh of entity ? [entity] : Object.values(this.entities)) {
const boxHelper = mesh.children.find(c => c.name === 'debug')
const boxHelper = mesh.children.find(c => c.name === 'debug')!
boxHelper.visible = false
if (this.debugMode === 'basic') {
boxHelper.visible = true
Expand All @@ -130,7 +147,7 @@ export class Entities extends EventEmitter {
}
}

setRendering(rendering, /** @type {THREE.Object3D?} */entity = null) {
setRendering (rendering: boolean, entity: THREE.Object3D | null = null) {
this.rendering = rendering
for (const ent of entity ? [entity] : Object.values(this.entities)) {
if (rendering) {
Expand All @@ -141,7 +158,7 @@ export class Entities extends EventEmitter {
}
}

render() {
render () {
const dt = this.clock.getDelta()
for (const entityId of Object.keys(this.entities)) {
const playerObject = this.getPlayerObject(entityId)
Expand All @@ -151,17 +168,16 @@ export class Entities extends EventEmitter {
}
}

getPlayerObject(entityId) {
/** @type {(PlayerObject & { animation?: PlayerAnimation }) | undefined} */
const playerObject = this.entities[entityId]?.playerObject
getPlayerObject (entityId: string | number) {
const playerObject = this.entities[entityId]?.playerObject as PlayerObjectType | undefined
return playerObject
}

// fixme workaround
defaultSteveTexture

// true means use default skin url
updatePlayerSkin(entityId, username, /** @type {string | true} */skinUrl, /** @type {string | true | undefined} */capeUrl = undefined) {
updatePlayerSkin (entityId: string | number, username: string | undefined, skinUrl: string | true, capeUrl: string | true | undefined = undefined) {
let playerObject = this.getPlayerObject(entityId)
if (!playerObject) return
// const username = this.entities[entityId].username
Expand All @@ -188,7 +204,6 @@ export class Entities extends EventEmitter {
skinTexture.magFilter = THREE.NearestFilter
skinTexture.minFilter = THREE.NearestFilter
skinTexture.needsUpdate = true
//@ts-expect-error
playerObject.skin.map = skinTexture
playerObject.skin.modelType = inferModelType(skinTexture.image)

Expand Down Expand Up @@ -244,14 +259,14 @@ export class Entities extends EventEmitter {
playerObject.cape.map = null
}

function isCanvasBlank(canvas) {
function isCanvasBlank (canvas) {
return !canvas.getContext('2d')
.getImageData(0, 0, canvas.width, canvas.height).data
.some(channel => channel !== 0)
}
}

playAnimation(entityPlayerId, /** @type {'walking' | 'running' | 'oneSwing' | 'idle'} */animation) {
playAnimation (entityPlayerId, animation: 'walking' | 'running' | 'oneSwing' | 'idle') {
const playerObject = this.getPlayerObject(entityPlayerId)
if (!playerObject) return

Expand All @@ -271,7 +286,7 @@ export class Entities extends EventEmitter {

}

parseEntityLabel(jsonLike) {
parseEntityLabel (jsonLike) {
if (!jsonLike) return
try {
const parsed = typeof jsonLike === 'string' ? mojangson.simplify(mojangson.parse(jsonLike)) : nbt.simplify(jsonLike)
Expand All @@ -282,22 +297,24 @@ export class Entities extends EventEmitter {
}
}

getItemMesh(item) {
getItemMesh (item) {
const textureUv = this.getItemUv?.(item.itemId ?? item.blockId)
if (textureUv) {
// todo use geometry buffer uv instead!
const { u, v, size, su, sv, texture } = textureUv
const itemsTexture = texture.clone()
itemsTexture.flipY = true
itemsTexture.offset.set(u, 1 - v - (sv ?? size))
itemsTexture.repeat.set(su ?? size, sv ?? size)
const sizeY = (sv ?? size)!
const sizeX = (su ?? size)!
itemsTexture.offset.set(u, 1 - v - sizeY)
itemsTexture.repeat.set(sizeX, sizeY)
itemsTexture.needsUpdate = true
itemsTexture.magFilter = THREE.NearestFilter
itemsTexture.minFilter = THREE.NearestFilter
const itemsTextureFlipped = itemsTexture.clone()
itemsTextureFlipped.repeat.x *= -1
itemsTextureFlipped.needsUpdate = true
itemsTextureFlipped.offset.set(u + (su ?? size), 1 - v - (sv ?? size))
itemsTextureFlipped.offset.set(u + (sizeX), 1 - v - sizeY)
const material = new THREE.MeshStandardMaterial({
map: itemsTexture,
transparent: true,
Expand All @@ -322,7 +339,7 @@ export class Entities extends EventEmitter {
}
}

update(/** @type {import('prismarine-entity').Entity & {delete?, pos}} */entity, overrides) {
update (entity: import('prismarine-entity').Entity & { delete?; pos }, overrides) {
let isPlayerModel = entity.name === 'player'
if (entity.name === 'zombie' || entity.name === 'zombie_villager' || entity.name === 'husk') {
isPlayerModel = true
Expand All @@ -332,21 +349,20 @@ export class Entities extends EventEmitter {
const group = new THREE.Group()
let mesh
if (entity.name === 'item') {
/** @type {any} */
//@ts-expect-error
const item = entity.metadata?.find(m => typeof m === 'object' && m?.itemCount)
const item = entity.metadata?.find((m: any) => typeof m === 'object' && m?.itemCount)
if (item) {
const object = this.getItemMesh(item)
if (object) {
object.scale.set(0.5, 0.5, 0.5)
object.position.set(0, 0.2, 0)
mesh = object.mesh
mesh.scale.set(0.5, 0.5, 0.5)
mesh.position.set(0, 0.2, 0)
// set faces
// mesh.position.set(targetPos.x + 0.5 + 2, targetPos.y + 0.5, targetPos.z + 0.5)
// viewer.scene.add(mesh)
const clock = new THREE.Clock()
object.onBeforeRender = () => {
mesh.onBeforeRender = () => {
const delta = clock.getDelta()
object.rotation.y += delta
mesh.rotation.y += delta
}
//@ts-expect-error
group.additionalCleanup = () => {
Expand All @@ -359,8 +375,7 @@ export class Entities extends EventEmitter {
} else if (isPlayerModel) {
// CREATE NEW PLAYER ENTITY
const wrapper = new THREE.Group()
/** @type {PlayerObject & { animation?: PlayerAnimation }} */
const playerObject = new PlayerObject()
const playerObject = new PlayerObject() as PlayerObjectType
playerObject.position.set(0, 16, 0)

//@ts-expect-error
Expand Down Expand Up @@ -470,9 +485,7 @@ export class Entities extends EventEmitter {
}

if (e?.playerObject && overrides?.rotation?.head) {
/** @type {PlayerObject} */
// eslint-disable-next-line prefer-destructuring
const playerObject = e.playerObject
const playerObject = e.playerObject as PlayerObjectType
const headRotationDiff = overrides.rotation.head.y ? overrides.rotation.head.y - entity.yaw : 0
playerObject.skin.head.rotation.y = -headRotationDiff
playerObject.skin.head.rotation.x = overrides.rotation.head.x ? - overrides.rotation.head.x : 0
Expand All @@ -497,7 +510,7 @@ export class Entities extends EventEmitter {
}
}

handleDamageEvent(entityId, damageAmount) {
handleDamageEvent (entityId, damageAmount) {
const entityMesh = this.entities[entityId]?.children.find(c => c.name === 'mesh')
if (entityMesh) {
entityMesh.traverse((child) => {
Expand Down
10 changes: 7 additions & 3 deletions prismarine-viewer/viewer/lib/mesher/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@
}))
}

function renderLiquid (world: World, cursor: Vec3, texture: any | undefined, type: number, biome: string, water: boolean, attr: Record<string, any>) {

Check warning on line 129 in prismarine-viewer/viewer/lib/mesher/models.ts

View workflow job for this annotation

GitHub Actions / build-and-deploy

Function 'renderLiquid' has too many parameters (7). Maximum allowed is 4
const heights: number[] = []
for (let z = -1; z <= 1; z++) {
for (let x = -1; x <= 1; x++) {
Expand Down Expand Up @@ -198,7 +198,7 @@

let needRecompute = false

function renderElement (world: World, cursor: Vec3, element: BlockElement, doAO: boolean, attr: MesherGeometryOutput, globalMatrix: any, globalShift: any, block: Block, biome: string) {

Check warning on line 201 in prismarine-viewer/viewer/lib/mesher/models.ts

View workflow job for this annotation

GitHub Actions / build-and-deploy

Function 'renderElement' has too many parameters (9). Maximum allowed is 4
const position = cursor
// const key = `${position.x},${position.y},${position.z}`
// if (!globalThis.allowedBlocks.includes(key)) return
Expand Down Expand Up @@ -282,6 +282,7 @@

const aos: number[] = []
const neighborPos = position.plus(new Vec3(...dir))
// 10%
const baseLight = world.getLight(neighborPos, undefined, undefined, block.name) / 15
for (const pos of corners) {
let vertex = [
Expand All @@ -290,7 +291,7 @@
(pos[2] ? maxz : minz)
]

if (!needTiles) {
if (!needTiles) { // 10%
vertex = vecadd3(matmul3(localMatrix, vertex), localShift)
vertex = vecadd3(matmul3(globalMatrix, vertex), globalShift)
vertex = vertex.map(v => v / 16)
Expand Down Expand Up @@ -411,7 +412,7 @@
// todo this can be removed here
signs: {},
// isFull: true,
highestBlocks: {},
highestBlocks: {}, // todo migrate to map for 2% boost perf
hadErrors: false
}

Expand Down Expand Up @@ -449,7 +450,7 @@
}
const biome = block.biome.name

if (world.preflat) {
if (world.preflat) { // 10% perf
const patchProperties = preflatBlockCalculation(block, world, cursor)
if (patchProperties) {
block._originalProperties ??= block._properties
Expand Down Expand Up @@ -505,6 +506,7 @@
const model = modelVars[useVariant] ?? modelVars[0]
if (!model) continue

// #region 10%
let globalMatrix = null as any
let globalShift = null as any
for (const axis of ['x', 'y', 'z'] as const) {
Expand All @@ -518,6 +520,7 @@
globalShift = [8, 8, 8]
globalShift = vecsub3(globalShift, matmul3(globalMatrix, globalShift))
}
// #endregion

for (const element of model.elements ?? []) {
const ao = model.ao ?? true
Expand All @@ -527,6 +530,7 @@
renderElement(world, pos, element, ao, attr, globalMatrix, globalShift, block, biome)
})
} else {
// 60%
renderElement(world, cursor, element, ao, attr, globalMatrix, globalShift, block, biome)
}
}
Expand Down
4 changes: 0 additions & 4 deletions prismarine-viewer/viewer/lib/worldrendererThree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,6 @@ export class WorldRendererThree extends WorldRendererCommon {
super(config)
this.starField = new StarField(scene)
this.holdingBlock = new HoldingBlock(this.scene)
this.onHandItemSwitch({
name: 'furnace',
properties: {}
})

this.renderUpdateEmitter.on('textureDownloaded', () => {
if (this.holdingBlock.toBeRenderedItem) {
Expand Down
4 changes: 2 additions & 2 deletions src/entities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,10 @@ customEvents.on('gameLoaded', () => {
window.debugEntityMetadata ??= {}
window.debugEntityMetadata[e.username] = e
// todo entity spawn timing issue, check perf
if (viewer.entities.entities[e.id]?.playerObject) {
const playerObject = viewer.entities.entities[e.id]?.playerObject
if (playerObject) {
// todo throttle!
bot.tracker.trackEntity(e)
const { playerObject } = viewer.entities.entities[e.id]
playerObject.backEquipment = e.equipment.some((item) => item?.name === 'elytra') ? 'elytra' : 'cape'
if (playerObject.cape.map === null) {
playerObject.cape.visible = false
Expand Down
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ viewer.entities.getItemUv = (idOrName: number | string) => {
u: 0,
v: 0,
size: 16 / viewer.world.material.map!.image.width,
texture: viewer.world.material.map
texture: viewer.world.material.map!
}
}
}
Expand Down
Loading
Loading