//@ts-nocheck import { EventEmitter } from 'events' import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest' import { Vec3 } from 'vec3' import { proxy } from 'valtio' import * as worldRendererModule from './worldrendererCommon' import { WorldRendererCommon } from './worldrendererCommon' import { defaultWorldRendererConfig } from '../graphicsBackend/config' import { defaultPerformanceInstabilityFactors } from '../performanceMonitor' import { getInitialPlayerState } from '../playerState/playerState' import type { DisplayWorldOptions, GraphicsInitOptions } from '../graphicsBackend/types' vi.mock('./ui/newStats', () => ({ addNewStat: vi.fn(() => ({ updateText: vi.fn(), setVisibility: vi.fn() })), updateStatText: vi.fn(), removeAllStats: vi.fn(), updatePanesVisibility: vi.fn(), MC_RENDERER_DEBUG_OVERLAY_CLASS: 'mc-renderer-debug-overlay', })) vi.mock('./utils/skins', () => ({ setSkinsConfig: vi.fn(), steveTexture: {}, stevePngUrl: '', })) function ensurePromiseWithResolvers() { if (!Promise.withResolvers) { Promise.withResolvers = function () { let resolve!: (value: T | PromiseLike) => void let reject!: (reason?: unknown) => void const promise = new Promise((res, rej) => { resolve = res reject = rej }) return { promise, resolve, reject } } } } class TestWorldRenderer extends WorldRendererCommon { outputFormat = 'threeJs' as const changeBackgroundColor() {} changeCardinalLight() {} handleWorkerMessage() {} updateCamera() {} render() {} updateShowChunksBorder() {} updatePlayerEntity() {} worldStop() {} } function createRenderer(workerCount = 2, worldView?: DisplayWorldOptions['worldView']) { const reloadLoadedChunks = vi.fn(async () => {}) const rendererState = proxy({ world: { chunksLoaded: {} as Record, heightmaps: {} as Record, allChunksLoaded: false, mesherWork: false, instabilityFactors: defaultPerformanceInstabilityFactors(), intersectMedia: null, }, renderer: '', preventEscapeMenu: false, }) const displayOptions: DisplayWorldOptions = { version: '1.21.1', worldView: (worldView ?? Object.assign(new EventEmitter(), { reloadLoadedChunks })) as DisplayWorldOptions['worldView'], inWorldRenderingConfig: proxy({ ...defaultWorldRendererConfig, mesherWorkers: workerCount }), playerStateReactive: getInitialPlayerState(), rendererState, nonReactiveState: { fps: 0, worstRenderTime: 0, avgRenderTime: 0, world: { chunksLoadedCount: 0, chunksTotalNumber: 0, chunksFullInfo: '', }, renderer: { timeline: { live: [], frozen: [], lastSecond: [] }, }, }, resourcesManager: { currentResources: { mcData: { version: {} }, blocksAtlasJson: {}, blockstatesModels: {}, }, } as DisplayWorldOptions['resourcesManager'], } const initOptions: GraphicsInitOptions = { config: { sceneBackground: '#000' }, rendererSpecificSettings: {}, callbacks: { displayCriticalError: vi.fn(), setRendererSpecificSettings: vi.fn(), fireCustomEvent: vi.fn(), }, } const renderer = new TestWorldRenderer(displayOptions.resourcesManager, displayOptions, initOptions) renderer.active = true renderer.workers = Array.from({ length: workerCount }, () => ({ postMessage: vi.fn(), terminate: vi.fn(), })) renderer['syncMesherPoolSnapshot']() renderer.viewDistance = 8 renderer.viewerChunkPosition = new Vec3(0, 64, 0) renderer.worldSizeParams = { minY: 0, worldHeight: 256 } return { renderer, reloadLoadedChunks } } describe('WorldRendererCommon.reconfigureMesherWorkers', () => { beforeEach(() => { ensurePromiseWithResolvers() vi.stubGlobal('location', { href: 'http://localhost/' }) vi.stubGlobal('Worker', class MockWorker { postMessage = vi.fn() terminate = vi.fn() addEventListener = vi.fn() onmessage: ((event: MessageEvent) => void) | null = null }) vi.spyOn(worldRendererModule, 'meshersSendMcData').mockImplementation(() => {}) }) afterEach(() => { vi.restoreAllMocks() vi.unstubAllGlobals() }) test('recreates workers with new count and reloads chunks', async () => { const { renderer, reloadLoadedChunks } = createRenderer(3) const terminated = renderer.workers.map((worker) => worker.terminate) renderer.worldRendererConfig.mesherWorkers = 1 await renderer.reconfigureMesherWorkers() for (const terminate of terminated) { expect(terminate).toHaveBeenCalled() } expect(renderer.workers).toHaveLength(1) expect(reloadLoadedChunks).toHaveBeenCalledTimes(1) }) test('recreates workers when mesher pipeline changes', async () => { const { renderer, reloadLoadedChunks } = createRenderer(2) const terminated = renderer.workers.map((worker) => worker.terminate) renderer.worldRendererConfig.wasmMesher = false await renderer.reconfigureMesherWorkers() for (const terminate of terminated) { expect(terminate).toHaveBeenCalled() } expect(renderer.workers).toHaveLength(2) expect(reloadLoadedChunks).toHaveBeenCalledTimes(1) }) test('watchMesherPoolConfig registers valtio unsubscribe functions', () => { const { renderer } = createRenderer(2) renderer['watchMesherPoolConfig']() expect(renderer['valtioUnsubs']).toHaveLength(3) for (const unsub of renderer['valtioUnsubs']) { expect(typeof unsub).toBe('function') } expect(() => { for (const unsub of renderer['valtioUnsubs']) unsub() renderer.destroy() }).not.toThrow() }) test('config watcher enqueues reconfigure when mesherWorkers changes', async () => { const enqueueSpy = vi.spyOn(TestWorldRenderer.prototype as any, 'enqueueMesherWorkersReconfigure') const { renderer } = createRenderer(2) renderer['watchMesherPoolConfig']() renderer.worldRendererConfig.mesherWorkers = 4 await vi.waitFor(() => { expect(enqueueSpy).toHaveBeenCalled() }) enqueueSpy.mockRestore() }) test('skips tail work when destroyed during bootstrap', async () => { const { renderer, reloadLoadedChunks } = createRenderer(2) vi.spyOn(renderer, 'updateAssetsData').mockImplementation(async () => { renderer.active = false }) await renderer.reconfigureMesherWorkers() expect(reloadLoadedChunks).not.toHaveBeenCalled() }) })