diff --git a/renderer/viewer/lib/worldrendererCommon.ts b/renderer/viewer/lib/worldrendererCommon.ts index 46e57ce2..aeba4d4c 100644 --- a/renderer/viewer/lib/worldrendererCommon.ts +++ b/renderer/viewer/lib/worldrendererCommon.ts @@ -3,27 +3,20 @@ import { EventEmitter } from 'events' import { Vec3 } from 'vec3' import * as THREE from 'three' import mcDataRaw from 'minecraft-data/data.js' // note: using alias -import blocksAtlases from 'mc-assets/dist/blocksAtlases.json' -import blocksAtlasLatest from 'mc-assets/dist/blocksAtlasLatest.png' -import blocksAtlasLegacy from 'mc-assets/dist/blocksAtlasLegacy.png' -import itemsAtlases from 'mc-assets/dist/itemsAtlases.json' -import itemsAtlasLatest from 'mc-assets/dist/itemsAtlasLatest.png' -import itemsAtlasLegacy from 'mc-assets/dist/itemsAtlasLegacy.png' -import { AtlasParser, getLoadedItemDefinitionsStore } from 'mc-assets' +import { AtlasParser } from 'mc-assets' import TypedEmitter from 'typed-emitter' import { LineMaterial } from 'three-stdlib' -import christmasPack from 'mc-assets/dist/textureReplacements/christmas' import { ItemsRenderer } from 'mc-assets/dist/itemsRenderer' -import itemDefinitionsJson from 'mc-assets/dist/itemDefinitions.json' import worldBlockProvider, { WorldBlockProvider } from 'mc-assets/dist/worldBlockProvider' import { dynamicMcDataFiles } from '../../buildMesherConfig.mjs' import { toMajorVersion } from '../../../src/utils' +import { ResourcesManager } from '../../../src/appViewer' import { buildCleanupDecorator } from './cleanupDecorator' import { defaultMesherConfig, HighestBlockInfo, MesherGeometryOutput, CustomBlockModels, BlockStateModelInfo } from './mesher/shared' import { chunkPos } from './simpleUtils' -import { HandItemBlock } from './holdingBlock' import { updateStatText } from './ui/newStats' -import { WorldRendererThree } from './worldrendererThree' + +const appViewer = undefined function mod (x, n) { return ((x % n) + n) % n @@ -93,8 +86,6 @@ export abstract class WorldRendererCommon renderUpdateEmitter = new EventEmitter() as unknown as TypedEmitter<{ dirty (pos: Vec3, value: boolean): void update (/* pos: Vec3, value: boolean */): void - textureDownloaded (): void - itemsTextureDownloaded (): void chunkFinished (key: string): void }> customTexturesDataUrl = undefined as string | undefined @@ -120,29 +111,16 @@ export abstract class WorldRendererCommon mesherConfig = defaultMesherConfig camera: THREE.PerspectiveCamera highestBlocks = new Map() - blockstatesModels: any customBlockStates: Record | undefined customModels: Record | undefined itemsAtlasParser: AtlasParser | undefined blocksAtlasParser: AtlasParser | undefined - sourceData = { - blocksAtlases, - itemsAtlases, - itemDefinitionsJson - } - customTextures: { - items?: CustomTexturesData - blocks?: CustomTexturesData - armor?: CustomTexturesData - } = {} - itemsDefinitionsStore = getLoadedItemDefinitionsStore(this.sourceData.itemDefinitionsJson) workersProcessAverageTime = 0 workersProcessAverageTimeCount = 0 maxWorkersProcessTime = 0 geometryReceiveCount = {} allLoadedIn: undefined | number - rendererDevice = '...' edgeChunks = {} as Record lastAddChunk = null as null | { @@ -154,14 +132,6 @@ export abstract class WorldRendererCommon lastChunkDistance = 0 debugStopGeometryUpdate = false - @worldCleanup() - freeFlyMode = false - @worldCleanup() - freeFlyState = { - yaw: 0, - pitch: 0, - position: new Vec3(0, 0, 0) - } @worldCleanup() itemsRenderer: ItemsRenderer | undefined @@ -175,7 +145,7 @@ export abstract class WorldRendererCommon abstract changeBackgroundColor (color: [number, number, number]): void - constructor (public config: WorldRendererConfig) { + constructor (private readonly resourcesManager: ResourcesManager, private readonly worldRendererConfig: WorldRendererConfig) { // this.initWorkers(1) // preload script on page load this.snapshotInitialValues() @@ -183,11 +153,15 @@ export abstract class WorldRendererCommon const loadedChunks = Object.keys(this.finishedChunks).length updateStatText('loaded-chunks', `${loadedChunks}/${this.chunksLength} chunks (${this.lastChunkDistance}/${this.viewDistance})`) }) + + this.resourcesManager.on('assetsTexturesUpdated', () => { + void this.updateAssetsData() + }) } snapshotInitialValues () { } - initWorkers (numWorkers = this.config.mesherWorkers) { + initWorkers (numWorkers = this.worldRendererConfig.mesherWorkers) { // init workers for (let i = 0; i < numWorkers + 1; i++) { // Node environment needs an absolute path, but browser needs the url of the file @@ -332,7 +306,6 @@ export abstract class WorldRendererCommon // new game load happens here async setVersion (version, texturesVersion = version) { - if (!this.blockstatesModels) throw new Error('Blockstates models is not loaded yet') this.version = version this.texturesVersion = texturesVersion this.resetWorld() @@ -342,7 +315,7 @@ export abstract class WorldRendererCommon this.mesherConfig.version = this.version! this.sendMesherMcData() - await this.updateAssetsData() + await this.resourcesManager.updateAssetsData() } sendMesherMcData () { @@ -359,38 +332,8 @@ export abstract class WorldRendererCommon } } - async updateAssetsData (resourcePackUpdate = false, prioritizeBlockTextures?: string[]) { - const blocksAssetsParser = new AtlasParser(this.sourceData.blocksAtlases, blocksAtlasLatest, blocksAtlasLegacy) - const itemsAssetsParser = new AtlasParser(this.sourceData.itemsAtlases, itemsAtlasLatest, itemsAtlasLegacy) - - const blockTexturesChanges = {} as Record - const date = new Date() - if ((date.getMonth() === 11 && date.getDate() >= 24) || (date.getMonth() === 0 && date.getDate() <= 6)) { - Object.assign(blockTexturesChanges, christmasPack) - } - - const customBlockTextures = Object.keys(this.customTextures.blocks?.textures ?? {}) - const customItemTextures = Object.keys(this.customTextures.items?.textures ?? {}) - console.time('createBlocksAtlas') - const { atlas: blocksAtlas, canvas: blocksCanvas } = await blocksAssetsParser.makeNewAtlas(this.texturesVersion ?? this.version ?? 'latest', (textureName) => { - const texture = this.customTextures?.blocks?.textures[textureName] - return blockTexturesChanges[textureName] ?? texture - }, /* this.customTextures?.blocks?.tileSize */undefined, prioritizeBlockTextures, customBlockTextures) - console.timeEnd('createBlocksAtlas') - console.time('createItemsAtlas') - const { atlas: itemsAtlas, canvas: itemsCanvas } = await itemsAssetsParser.makeNewAtlas(this.texturesVersion ?? this.version ?? 'latest', (textureName) => { - const texture = this.customTextures?.items?.textures[textureName] - if (!texture) return - return texture - }, this.customTextures?.items?.tileSize, undefined, customItemTextures) - console.timeEnd('createItemsAtlas') - this.blocksAtlasParser = new AtlasParser({ latest: blocksAtlas }, blocksCanvas.toDataURL()) - this.itemsAtlasParser = new AtlasParser({ latest: itemsAtlas }, itemsCanvas.toDataURL()) - - this.itemsRenderer = new ItemsRenderer(this.version!, this.blockstatesModels, this.itemsAtlasParser, this.blocksAtlasParser) - this.worldBlockProvider = worldBlockProvider(this.blockstatesModels, this.blocksAtlasParser.atlas, 'latest') - - const texture = await new THREE.TextureLoader().loadAsync(this.blocksAtlasParser.latestImage) + async updateAssetsData () { + const texture = await new THREE.TextureLoader().loadAsync(this.resourcesManager.blocksAtlasParser!.latestImage) texture.magFilter = THREE.NearestFilter texture.minFilter = THREE.NearestFilter texture.flipY = false @@ -399,39 +342,34 @@ export abstract class WorldRendererCommon this.mesherConfig.textureSize = this.material.map.image.width for (const [i, worker] of this.workers.entries()) { - const { blockstatesModels } = this - if (this.customBlockStates) { - // TODO! remove from other versions as well + const { blockstatesModels } = this.resourcesManager + if (this.resourcesManager.customBlockStates) { blockstatesModels.blockstates.latest = { ...blockstatesModels.blockstates.latest, - ...this.customBlockStates + ...this.resourcesManager.customBlockStates } } - if (this.customModels) { + if (this.resourcesManager.customModels) { blockstatesModels.models.latest = { ...blockstatesModels.models.latest, - ...this.customModels + ...this.resourcesManager.customModels } } worker.postMessage({ type: 'mesherData', workerIndex: i, blocksAtlas: { - latest: blocksAtlas + latest: this.resourcesManager.blocksAtlasParser!.atlas }, blockstatesModels, config: this.mesherConfig, }) } - const itemsTexture = await new THREE.TextureLoader().loadAsync(this.itemsAtlasParser.latestImage) + const itemsTexture = await new THREE.TextureLoader().loadAsync(this.resourcesManager.itemsAtlasParser!.latestImage) itemsTexture.magFilter = THREE.NearestFilter itemsTexture.minFilter = THREE.NearestFilter itemsTexture.flipY = false viewer.entities.itemsTexture = itemsTexture - - this.renderUpdateEmitter.emit('textureDownloaded') - this.renderUpdateEmitter.emit('itemsTextureDownloaded') - console.log('textures loaded') } async downloadDebugAtlas (isItems = false) { diff --git a/renderer/viewer/lib/worldrendererThree.ts b/renderer/viewer/lib/worldrendererThree.ts index 6a8fa75d..ab9e17b3 100644 --- a/renderer/viewer/lib/worldrendererThree.ts +++ b/renderer/viewer/lib/worldrendererThree.ts @@ -17,6 +17,8 @@ import { IPlayerState } from './basePlayerState' import { getMesh } from './entity/EntityMesh' import { armorModel } from './entity/armorModels' +const appViewer = undefined + export class WorldRendererThree extends WorldRendererCommon { interactionLines: null | { blockPos; mesh } = null outputFormat = 'threeJs' as const @@ -38,15 +40,15 @@ export class WorldRendererThree extends WorldRendererCommon { return Object.values(this.sectionObjects).reduce((acc, obj) => acc + (obj as any).blocksCount, 0) } - constructor (public scene: THREE.Scene, public renderer: THREE.WebGLRenderer, public worldOptionsHolder: DisplayWorldOptions) { - super(worldOptionsHolder.inWorldRenderingConfig) - const { playerState } = worldOptionsHolder + constructor (public scene: THREE.Scene, public renderer: THREE.WebGLRenderer, public options: DisplayWorldOptions) { + super(options.resourcesManager, options.inWorldRenderingConfig) + const { playerState, inWorldRenderingConfig: config } = options this.starField = new StarField(scene) - this.holdingBlock = new HoldingBlock(playerState, this.config) - this.holdingBlockLeft = new HoldingBlock(playerState, this.config, true) + this.holdingBlock = new HoldingBlock(playerState, config) + this.holdingBlockLeft = new HoldingBlock(playerState, config, true) - this.renderUpdateEmitter.on('itemsTextureDownloaded', () => { + this.options.resourcesManager.on('assetsTexturesUpdated', () => { this.holdingBlock.ready = true this.holdingBlock.updateItem() this.holdingBlockLeft.ready = true @@ -168,7 +170,7 @@ export class WorldRendererThree extends WorldRendererCommon { object.name = 'chunk'; (object as any).tilesCount = data.geometry.positions.length / 3 / 4; (object as any).blocksCount = data.geometry.blocksCount - if (!this.config.showChunkBorders) { + if (!this.options.inWorldRenderingConfig.showChunkBorders) { boxHelper.visible = false } // should not compute it once @@ -225,15 +227,15 @@ export class WorldRendererThree extends WorldRendererCommon { } updateCamera (pos: Vec3 | null, yaw: number, pitch: number): void { - if (this.freeFlyMode) { - pos = this.freeFlyState.position - pitch = this.freeFlyState.pitch - yaw = this.freeFlyState.yaw - } + // if (this.freeFlyMode) { + // pos = this.freeFlyState.position + // pitch = this.freeFlyState.pitch + // yaw = this.freeFlyState.yaw + // } if (pos) { new tweenJs.Tween(this.camera.position).to({ x: pos.x, y: pos.y, z: pos.z }, 50).start() - this.freeFlyState.position = pos + // this.freeFlyState.position = pos } this.camera.rotation.set(pitch, yaw, this.cameraRoll, 'ZYX') } @@ -243,7 +245,7 @@ export class WorldRendererThree extends WorldRendererCommon { // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style const cam = this.camera instanceof THREE.Group ? this.camera.children.find(child => child instanceof THREE.PerspectiveCamera) as THREE.PerspectiveCamera : this.camera this.renderer.render(this.scene, cam) - if (this.config.showHand && !this.freeFlyMode) { + if (this.options.inWorldRenderingConfig.showHand/* && !this.freeFlyMode */) { this.holdingBlock.render(this.camera, this.renderer, viewer.ambientLight, viewer.directionalLight) this.holdingBlockLeft.render(this.camera, this.renderer, viewer.ambientLight, viewer.directionalLight) } @@ -347,7 +349,7 @@ export class WorldRendererThree extends WorldRendererCommon { } updateShowChunksBorder (value: boolean) { - this.config.showChunkBorders = value + this.options.inWorldRenderingConfig.showChunkBorders = value for (const object of Object.values(this.sectionObjects)) { for (const child of object.children) { if (child.name === 'helper') { diff --git a/renderer/viewer/three/graphicsBackend.ts b/renderer/viewer/three/graphicsBackend.ts index 7633b8dd..0bd3144e 100644 --- a/renderer/viewer/three/graphicsBackend.ts +++ b/renderer/viewer/three/graphicsBackend.ts @@ -1,5 +1,6 @@ import * as THREE from 'three' import { Vec3 } from 'vec3' +import { proxy } from 'valtio' import { GraphicsBackendLoader, GraphicsBackend, GraphicsBackendOptions, DisplayWorldOptions } from '../../../src/appViewer' import { ProgressReporter } from '../../../src/core/progressReporter' import { ThreeJsWorldRenderer } from '../lib/viewer' @@ -18,6 +19,11 @@ const createGraphicsBackend: GraphicsBackendLoader = (options: GraphicsBackendOp let panoramaRenderer: PanoramaRenderer | null = null let worldRenderer: ThreeJsWorldRenderer | null = null + const worldState = proxy({ + chunksLoaded: 0, + chunksTotal: 0 + }) + const startPanorama = () => { if (worldRenderer) return if (!panoramaRenderer) { @@ -28,7 +34,6 @@ const createGraphicsBackend: GraphicsBackendLoader = (options: GraphicsBackendOp let version = '' const updateResources = async (ver: string, progressReporter: ProgressReporter): Promise => { - // Implementation for updating resources will be added here version = ver } @@ -49,7 +54,6 @@ const createGraphicsBackend: GraphicsBackendLoader = (options: GraphicsBackendOp if (documentRenderer) { documentRenderer.dispose() } - if (worldRenderer) { worldRenderer.dispose() worldRenderer = null @@ -77,7 +81,8 @@ const createGraphicsBackend: GraphicsBackendLoader = (options: GraphicsBackendOp }, setRoll (roll: number) { worldRenderer?.setCameraRoll(roll) - } + }, + worldState } return backend diff --git a/src/appViewer.ts b/src/appViewer.ts index 1ee4635c..bfd38371 100644 --- a/src/appViewer.ts +++ b/src/appViewer.ts @@ -1,14 +1,33 @@ +import { EventEmitter } from 'events' import { WorldDataEmitter } from 'renderer/viewer/lib/worldDataEmitter' import { IPlayerState } from 'renderer/viewer/lib/basePlayerState' import { subscribeKey } from 'valtio/utils' import { defaultWorldRendererConfig, WorldRendererConfig } from 'renderer/viewer/lib/worldrendererCommon' import { Vec3 } from 'vec3' +import { proxy } from 'valtio' +import blocksAtlases from 'mc-assets/dist/blocksAtlases.json' +import itemsAtlases from 'mc-assets/dist/itemsAtlases.json' +import itemDefinitionsJson from 'mc-assets/dist/itemDefinitions.json' +import blocksAtlasLatest from 'mc-assets/dist/blocksAtlasLatest.png' +import blocksAtlasLegacy from 'mc-assets/dist/blocksAtlasLegacy.png' +import itemsAtlasLatest from 'mc-assets/dist/itemsAtlasLatest.png' +import itemsAtlasLegacy from 'mc-assets/dist/itemsAtlasLegacy.png' +import christmasPack from 'mc-assets/dist/textureReplacements/christmas' +import { AtlasParser, getLoadedItemDefinitionsStore } from 'mc-assets' +import TypedEmitter from 'typed-emitter' +import { ItemsRenderer } from 'mc-assets/dist/itemsRenderer' +import worldBlockProvider, { WorldBlockProvider } from 'mc-assets/dist/worldBlockProvider' import { playerState, PlayerStateManager } from './mineflayer/playerState' import { createNotificationProgressReporter, ProgressReporter } from './core/progressReporter' import { setLoadingScreenStatus } from './appStatus' import { activeModalStack, miscUiState } from './globalState' import { options } from './optionsStorage' +export interface WorldReactiveState { + chunksLoaded: number + chunksTotal: number +} + export interface GraphicsBackendConfig { fpsLimit?: number powerPreference?: 'high-performance' | 'low-power' @@ -41,23 +60,17 @@ export interface GraphicsBackend { updateResources: (version: string, progressReporter: ProgressReporter) => Promise startWorld: (options: DisplayWorldOptions) => void disconnect: () => void - setRendering: (rendering: boolean) => void - getRenderer: () => string - getDebugOverlay: () => { - entitiesString?: string - right?: Record - left?: Record - } + getDebugOverlay: () => Record updateCamera: (pos: Vec3 | null, yaw: number, pitch: number) => void setRoll: (roll: number) => void + worldState: WorldReactiveState } export class AppViewer { - resourcesManager: ResourcesManager + resourcesManager: ResourcesManager = new ResourcesManager() worldView: WorldDataEmitter - // playerState: IPlayerState readonly config: GraphicsBackendConfig = { ...defaultGraphicsBackendConfig, powerPreference: options.gpuPreference === 'default' ? undefined : options.gpuPreference @@ -105,14 +118,14 @@ export class AppViewer { async updateResources (version: string, progressReporter: ProgressReporter) { if (this.backend) { - await this.backend.updateResources(version, progressReporter) + // await this.backend.updateResources(version, progressReporter) } } - startWorld (world, renderDistance, startPosition) { + async startWorld (world, renderDistance, startPosition) { this.worldView = new WorldDataEmitter(world, renderDistance, startPosition) window.worldView = this.worldView - // this.playerState = new PlayerStateManager() + if (this.backend) { this.backend.startWorld({ resourcesManager: this.resourcesManager, @@ -133,12 +146,123 @@ export class AppViewer { } } +export interface UpdateAssetsRequest { + includeOnlyBlocks?: string[] +} + +type ResourceManagerEvents = { + assetsTexturesUpdated: () => void +} + +export class ResourcesManager extends (EventEmitter as new () => TypedEmitter) { + // Source data (imported, not changing) + sourceBlockStatesModels: any = null + sourceBlocksAtlases: any = blocksAtlases + sourceItemsAtlases: any = itemsAtlases + sourceItemDefinitionsJson: any = itemDefinitionsJson + itemsDefinitionsStore = getLoadedItemDefinitionsStore(this.sourceItemDefinitionsJson) + + // Atlas parsers + itemsAtlasParser: AtlasParser | undefined + blocksAtlasParser: AtlasParser | undefined + + // User data (specific to current resourcepack/version) + customBlockStates?: Record + customModels?: Record + customTextures: { + items?: { tileSize: number | undefined, textures: Record } + blocks?: { tileSize: number | undefined, textures: Record } + armor?: { tileSize: number | undefined, textures: Record } + } = {} + + // Moved from WorldRendererCommon + itemsRenderer: ItemsRenderer | undefined + worldBlockProvider: WorldBlockProvider | undefined + blockstatesModels: any = null + + version?: string + texturesVersion?: string + + async updateAssetsData (request: UpdateAssetsRequest = {}) { + const blocksAssetsParser = new AtlasParser(this.sourceBlocksAtlases, blocksAtlasLatest, blocksAtlasLegacy) + const itemsAssetsParser = new AtlasParser(this.sourceItemsAtlases, itemsAtlasLatest, itemsAtlasLegacy) + + const blockTexturesChanges = {} as Record + const date = new Date() + if ((date.getMonth() === 11 && date.getDate() >= 24) || (date.getMonth() === 0 && date.getDate() <= 6)) { + Object.assign(blockTexturesChanges, christmasPack) + } + + const customBlockTextures = Object.keys(this.customTextures.blocks?.textures ?? {}) + const customItemTextures = Object.keys(this.customTextures.items?.textures ?? {}) + + console.time('createBlocksAtlas') + const { atlas: blocksAtlas, canvas: blocksCanvas } = await blocksAssetsParser.makeNewAtlas( + this.texturesVersion ?? this.version ?? 'latest', + (textureName) => { + if (request.includeOnlyBlocks && !request.includeOnlyBlocks.includes(textureName)) return false + const texture = this.customTextures?.blocks?.textures[textureName] + return blockTexturesChanges[textureName] ?? texture + }, + undefined, + undefined, + customBlockTextures + ) + console.timeEnd('createBlocksAtlas') + + console.time('createItemsAtlas') + const { atlas: itemsAtlas, canvas: itemsCanvas } = await itemsAssetsParser.makeNewAtlas( + this.texturesVersion ?? this.version ?? 'latest', + (textureName) => { + const texture = this.customTextures?.items?.textures[textureName] + if (!texture) return + return texture + }, + this.customTextures?.items?.tileSize, + undefined, + customItemTextures + ) + console.timeEnd('createItemsAtlas') + + this.blocksAtlasParser = new AtlasParser({ latest: blocksAtlas }, blocksCanvas.toDataURL()) + this.itemsAtlasParser = new AtlasParser({ latest: itemsAtlas }, itemsCanvas.toDataURL()) + + // Initialize ItemsRenderer and WorldBlockProvider + if (this.version && this.blockstatesModels && this.itemsAtlasParser && this.blocksAtlasParser) { + this.itemsRenderer = new ItemsRenderer( + this.version, + this.blockstatesModels, + this.itemsAtlasParser, + this.blocksAtlasParser + ) + this.worldBlockProvider = worldBlockProvider( + this.blockstatesModels, + this.blocksAtlasParser.atlas, + 'latest' + ) + } + + // Emit event that textures were updated + this.emit('assetsTexturesUpdated') + + return { + blocksAtlas, + itemsAtlas, + blocksCanvas, + itemsCanvas + } + } + + async setVersion (version: string, texturesVersion?: string) { + this.version = version + this.texturesVersion = texturesVersion + await this.updateAssetsData() + } +} + export const appViewer = new AppViewer() window.appViewer = appViewer -class ResourcesManager { -} - const modalStackUpdate = () => { if (activeModalStack.length === 0 && !miscUiState.gameLoaded) { // tood reset backend diff --git a/src/index.ts b/src/index.ts index c2552a5b..884f8594 100644 --- a/src/index.ts +++ b/src/index.ts @@ -372,7 +372,7 @@ export async function connect (connectOptions: ConnectOptions) { await progress.executeWithMessage( 'Loading minecraft models', async () => { - // viewer.world.blockstatesModels = await import('mc-assets/dist/blockStatesModels.json') + appViewer.resourcesManager.sourceBlockStatesModels ??= await import('mc-assets/dist/blockStatesModels.json') // void viewer.setVersion(version, options.useVersionsTextures === 'latest' ? version : options.useVersionsTextures) void appViewer.updateResources(version, createConsoleLogProgressReporter()) miscUiState.loadedDataVersion = version @@ -699,14 +699,14 @@ export async function connect (connectOptions: ConnectOptions) { const start = Date.now() let worldWasReady = false - void viewer.world.renderUpdateEmitter.on('update', () => { - // todo might not emit as servers simply don't send chunk if it's empty - if (!viewer.world.allChunksFinished || worldWasReady) return - worldWasReady = true - console.log('All chunks done and ready! Time from renderer open to ready', (Date.now() - start) / 1000, 's') - viewer.render() // ensure the last state is rendered - document.dispatchEvent(new Event('cypress-world-ready')) - }) + // void viewer.world.renderUpdateEmitter.on('update', () => { + // // todo might not emit as servers simply don't send chunk if it's empty + // if (!viewer.world.allChunksFinished || worldWasReady) return + // worldWasReady = true + // console.log('All chunks done and ready! Time from renderer open to ready', (Date.now() - start) / 1000, 's') + // viewer.render() // ensure the last state is rendered + // document.dispatchEvent(new Event('cypress-world-ready')) + // }) const spawnEarlier = !singleplayer && !p2pMultiplayer // don't use spawn event, player can be dead diff --git a/src/inventoryWindows.ts b/src/inventoryWindows.ts index be583130..353426cf 100644 --- a/src/inventoryWindows.ts +++ b/src/inventoryWindows.ts @@ -41,7 +41,7 @@ export const onGameLoad = (onLoad) => { version = bot.version const checkIfLoaded = () => { - if (!viewer.world.itemsAtlasParser) return + if (!appViewer.resourcesManager.itemsAtlasParser) return if (!allImagesLoadedState.value) { onLoad?.() } @@ -50,7 +50,7 @@ export const onGameLoad = (onLoad) => { allImagesLoadedState.value = true }, 0) } - viewer.world.renderUpdateEmitter.on('textureDownloaded', checkIfLoaded) + appViewer.resourcesManager.on('assetsTexturesUpdated', checkIfLoaded) checkIfLoaded() PrismarineItem = PItem(version) diff --git a/src/mineflayer/plugins/mouse.ts b/src/mineflayer/plugins/mouse.ts index e5b5e283..1953d7e4 100644 --- a/src/mineflayer/plugins/mouse.ts +++ b/src/mineflayer/plugins/mouse.ts @@ -143,7 +143,7 @@ export default (bot: Bot) => { bot.loadPlugin(createMouse({})) domListeners(bot) - createDisplayManager(bot, viewer.scene, viewer.renderer) + // createDisplayManager(bot, viewer.scene, viewer.renderer) otherListeners() } diff --git a/src/react/HotbarRenderApp.tsx b/src/react/HotbarRenderApp.tsx index af7d1387..3f1325c7 100644 --- a/src/react/HotbarRenderApp.tsx +++ b/src/react/HotbarRenderApp.tsx @@ -110,7 +110,7 @@ const HotbarInner = () => { inv.canvas.style.pointerEvents = 'auto' container.current.appendChild(inv.canvas) const upHotbarItems = () => { - if (!viewer.world.currentTextureImage || !allImagesLoadedState.value) return + if (!appViewer.resourcesManager.itemsAtlasParser || !allImagesLoadedState.value) return upInventoryItems(true, inv) } @@ -124,7 +124,7 @@ const HotbarInner = () => { upHotbarItems() bot.inventory.on('updateSlot', upHotbarItems) - viewer.world.renderUpdateEmitter.on('textureDownloaded', upHotbarItems) + appViewer.resourcesManager.on('assetsTexturesUpdated', upHotbarItems) const unsub2 = subscribe(allImagesLoadedState, () => { upHotbarItems() }) @@ -197,7 +197,7 @@ const HotbarInner = () => { inv.destroy() controller.abort() unsub2() - viewer.world.renderUpdateEmitter.off('textureDownloaded', upHotbarItems) + appViewer.resourcesManager.off('assetsTexturesUpdated', upHotbarItems) } }, []) diff --git a/src/resourcePack.ts b/src/resourcePack.ts index 6e9c28a4..a5921be9 100644 --- a/src/resourcePack.ts +++ b/src/resourcePack.ts @@ -14,6 +14,7 @@ import { appReplacableResources, resourcesContentOriginal } from './generated/re import { gameAdditionalState, miscUiState } from './globalState' import { watchUnloadForCleanup } from './gameUnload' import { createConsoleLogProgressReporter, createFullScreenProgressReporter, ProgressReporter } from './core/progressReporter' +import { appViewer } from './appViewer' export const resourcePackState = proxy({ resourcePackInstalled: false, @@ -312,8 +313,8 @@ export const getResourcepackTiles = async (type: 'blocks' | 'items' | 'armor', e } const prepareBlockstatesAndModels = async (progressReporter: ProgressReporter) => { - viewer.world.customBlockStates = {} - viewer.world.customModels = {} + appViewer.resourcesManager.customBlockStates = {} + appViewer.resourcesManager.customModels = {} const usedBlockTextures = new Set() const usedItemTextures = new Set() const basePath = await getActiveResourcepackBasePath() @@ -360,9 +361,9 @@ const prepareBlockstatesAndModels = async (progressReporter: ProgressReporter) = const blockModelsPath = `${basePath}/assets/${namespaceDir}/models/block` const itemModelsPath = `${basePath}/assets/${namespaceDir}/models/item` - Object.assign(viewer.world.customBlockStates!, await readModelData(blockstatesPath, 'blockstates', namespaceDir)) - Object.assign(viewer.world.customModels!, await readModelData(blockModelsPath, 'models', namespaceDir)) - Object.assign(viewer.world.customModels!, await readModelData(itemModelsPath, 'models', namespaceDir)) + Object.assign(appViewer.resourcesManager.customBlockStates!, await readModelData(blockstatesPath, 'blockstates', namespaceDir)) + Object.assign(appViewer.resourcesManager.customModels!, await readModelData(blockModelsPath, 'models', namespaceDir)) + Object.assign(appViewer.resourcesManager.customModels!, await readModelData(itemModelsPath, 'models', namespaceDir)) } try { @@ -372,8 +373,8 @@ const prepareBlockstatesAndModels = async (progressReporter: ProgressReporter) = } } catch (err) { console.error('Failed to read some of resource pack blockstates and models', err) - viewer.world.customBlockStates = undefined - viewer.world.customModels = undefined + appViewer.resourcesManager.customBlockStates = undefined + appViewer.resourcesManager.customModels = undefined } return { usedBlockTextures, @@ -523,38 +524,39 @@ const repeatArr = (arr, i) => Array.from({ length: i }, () => arr) const updateTextures = async (progressReporter = createConsoleLogProgressReporter()) => { currentErrors = [] - const origBlocksFiles = Object.keys(viewer.world.sourceData.blocksAtlases.latest.textures) - const origItemsFiles = Object.keys(viewer.world.sourceData.itemsAtlases.latest.textures) + const origBlocksFiles = Object.keys(appViewer.resourcesManager.sourceBlocksAtlases.latest.textures) + const origItemsFiles = Object.keys(appViewer.resourcesManager.sourceItemsAtlases.latest.textures) const origArmorFiles = Object.keys(armorTextures) const { usedBlockTextures, usedItemTextures } = await prepareBlockstatesAndModels(progressReporter) ?? {} const blocksData = await getResourcepackTiles('blocks', [...origBlocksFiles, ...usedBlockTextures ?? []], progressReporter) const itemsData = await getResourcepackTiles('items', [...origItemsFiles, ...usedItemTextures ?? []], progressReporter) const armorData = await getResourcepackTiles('armor', origArmorFiles, progressReporter) await updateAllReplacableTextures() - viewer.world.customTextures = {} + appViewer.resourcesManager.customTextures = {} + if (blocksData) { - viewer.world.customTextures.blocks = { + appViewer.resourcesManager.customTextures.blocks = { tileSize: blocksData.firstTextureSize, textures: blocksData.textures } } if (itemsData) { - viewer.world.customTextures.items = { + appViewer.resourcesManager.customTextures.items = { tileSize: itemsData.firstTextureSize, textures: itemsData.textures } } if (armorData) { - viewer.world.customTextures.armor = { + appViewer.resourcesManager.customTextures.armor = { tileSize: armorData.firstTextureSize, textures: armorData.textures } } - if (viewer.world.active) { - await viewer.world.updateAssetsData() - if (viewer.world instanceof WorldRendererThree) { - viewer.world.rerenderAllChunks?.() + if (appViewer.backend) { + await appViewer.resourcesManager.updateAssetsData() + if (appViewer.backend instanceof WorldRendererThree) { + appViewer.backend.rerenderAllChunks?.() } } }