pages235/src/entities.ts
2024-05-24 04:21:41 +03:00

141 lines
4.5 KiB
TypeScript

import { Entity } from 'prismarine-entity'
import tracker from '@nxg-org/mineflayer-tracker'
import { loader as autoJumpPlugin } from '@nxg-org/mineflayer-auto-jump'
import { subscribeKey } from 'valtio/utils'
import { options, watchValue } from './optionsStorage'
import { miscUiState } from './globalState'
const updateAutoJump = () => {
if (!bot?.autoJumper) return
const autoJump = options.autoParkour || (options.autoJump === 'auto' ? miscUiState.currentTouch && !miscUiState.usingGamepadInput : options.autoJump === 'always')
bot.autoJumper.setOpts({
jumpIntoWater: options.autoParkour,
jumpOnAllEdges: options.autoParkour,
// strictBlockCollision: true,
})
if (autoJump === bot.autoJumper.enabled) return
if (autoJump) {
bot.autoJumper.enable()
} else {
bot.autoJumper.disable()
}
}
subscribeKey(options, 'autoJump', () => {
updateAutoJump()
})
subscribeKey(options, 'autoParkour', () => {
updateAutoJump()
})
subscribeKey(miscUiState, 'usingGamepadInput', () => {
updateAutoJump()
})
subscribeKey(miscUiState, 'currentTouch', () => {
updateAutoJump()
})
customEvents.on('gameLoaded', () => {
bot.loadPlugin(tracker)
bot.loadPlugin(autoJumpPlugin)
updateAutoJump()
// todo cleanup (move to viewer, also shouldnt be used at all)
const playerPerAnimation = {} as Record<string, string>
const entityData = (e: Entity) => {
if (!e.username) return
window.debugEntityMetadata ??= {}
window.debugEntityMetadata[e.username] = e
// todo entity spawn timing issue, check perf
if (viewer.entities.entities[e.id]?.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
}
// todo (easy, important) elytra flying animation
// todo cleanup states
}
}
let lastCall = 0
bot.on('physicsTick', () => {
// throttle, tps: 6
if (Date.now() - lastCall < 166) return
lastCall = Date.now()
for (const [id, { tracking, info }] of Object.entries(bot.tracker.trackingData)) {
if (!tracking) continue
const e = bot.entities[id]
if (!e) continue
const speed = info.avgSpeed
const WALKING_SPEED = 0.03
const SPRINTING_SPEED = 0.18
const isWalking = Math.abs(speed.x) > WALKING_SPEED || Math.abs(speed.z) > WALKING_SPEED
const isSprinting = Math.abs(speed.x) > SPRINTING_SPEED || Math.abs(speed.z) > SPRINTING_SPEED
const newAnimation = isWalking ? (isSprinting ? 'running' : 'walking') : 'idle'
const username = e.username!
if (newAnimation !== playerPerAnimation[username]) {
viewer.entities.playAnimation(e.id, newAnimation)
playerPerAnimation[username] = newAnimation
}
}
})
bot.on('entitySwingArm', (e) => {
if (viewer.entities.entities[e.id]?.playerObject) {
viewer.entities.playAnimation(e.id, 'oneSwing')
}
})
const loadedSkinEntityIds = new Set<number>()
const playerRenderSkin = (e: Entity) => {
const mesh = viewer.entities.entities[e.id]
if (!mesh) return
if (!mesh.playerObject || !options.loadPlayerSkins) return
const MAX_DISTANCE_SKIN_LOAD = 128
const distance = e.position.distanceTo(bot.entity.position)
if (distance < MAX_DISTANCE_SKIN_LOAD && distance < (bot.settings.viewDistance as number) * 16) {
if (viewer.entities.entities[e.id]) {
if (loadedSkinEntityIds.has(e.id)) return
loadedSkinEntityIds.add(e.id)
viewer.entities.updatePlayerSkin(e.id, e.username, true, true)
}
}
}
viewer.entities.addListener('remove', (e) => {
loadedSkinEntityIds.delete(e.id)
playerPerAnimation[e.username] = ''
bot.tracker.stopTrackingEntity(e, true)
})
bot.on('entityMoved', (e) => {
playerRenderSkin(e)
entityData(e)
})
bot._client.on('entity_velocity', (packet) => {
const e = bot.entities[packet.entityId]
if (!e) return
entityData(e)
})
viewer.entities.addListener('add', (e) => {
if (!viewer.entities.entities[e.id]) throw new Error('mesh still not loaded')
playerRenderSkin(e)
})
for (const entity of Object.values(bot.entities)) {
if (entity !== bot.entity) {
entityData(entity)
}
}
bot.on('entitySpawn', entityData)
bot.on('entityUpdate', entityData)
bot.on('entityEquip', entityData)
watchValue(options, o => {
viewer.entities.setDebugMode(o.showChunkBorders ? 'basic' : 'none')
})
})