quake2ts 0.0.621 → 0.0.629

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.
@@ -2317,99 +2317,280 @@ function createMockImage(width = 100, height = 100, src = "") {
2317
2317
  return img;
2318
2318
  }
2319
2319
 
2320
- // src/engine/mocks/webgpu.ts
2321
- import { vi as vi12 } from "vitest";
2322
- function createMockGPUAdapter() {
2323
- return {
2324
- features: /* @__PURE__ */ new Set(),
2325
- limits: {
2326
- maxTextureDimension2D: 8192,
2327
- maxBindGroups: 4,
2328
- maxUniformBufferBindingSize: 65536,
2329
- maxStorageBufferBindingSize: 134217728
2330
- },
2331
- requestDevice: vi12.fn().mockResolvedValue(createMockGPUDevice())
2332
- };
2333
- }
2334
- function createMockGPUDevice() {
2320
+ // ../../node_modules/.pnpm/webgpu@0.3.8/node_modules/webgpu/index.js
2321
+ import { dirname, join } from "path";
2322
+ import { fileURLToPath } from "url";
2323
+ import { createRequire } from "module";
2324
+ var require2 = createRequire(import.meta.url);
2325
+ var isMac = process.platform === "darwin";
2326
+ var __dirname = dirname(fileURLToPath(import.meta.url));
2327
+ var arch = isMac ? "universal" : process.arch;
2328
+ var dawnNodePath = join(__dirname, "dist", `${process.platform}-${arch}.dawn.node`);
2329
+ var { create, globals } = require2(dawnNodePath);
2330
+
2331
+ // src/setup/webgpu.ts
2332
+ async function initHeadlessWebGPU(options) {
2333
+ if (typeof process === "undefined" || process.release?.name !== "node") {
2334
+ throw new Error("initHeadlessWebGPU should only be called in a Node.js environment");
2335
+ }
2336
+ if (!globalThis.navigator) {
2337
+ globalThis.navigator = {};
2338
+ }
2339
+ if (!globalThis.navigator.gpu) {
2340
+ const gpu = create([]);
2341
+ try {
2342
+ Object.defineProperty(globalThis.navigator, "gpu", {
2343
+ value: gpu,
2344
+ writable: true,
2345
+ configurable: true
2346
+ });
2347
+ } catch (e) {
2348
+ console.warn("Could not define navigator.gpu, trying direct assignment");
2349
+ globalThis.navigator.gpu = gpu;
2350
+ }
2351
+ Object.assign(globalThis, globals);
2352
+ }
2353
+ const adapter = await navigator.gpu.requestAdapter({
2354
+ powerPreference: options?.powerPreference || "high-performance"
2355
+ });
2356
+ if (!adapter) {
2357
+ throw new Error("Failed to create WebGPU adapter");
2358
+ }
2359
+ const device = await adapter.requestDevice({
2360
+ requiredFeatures: options?.requiredFeatures || []
2361
+ });
2362
+ if (!device) {
2363
+ throw new Error("Failed to create WebGPU device");
2364
+ }
2335
2365
  return {
2336
- features: /* @__PURE__ */ new Set(),
2337
- limits: {
2338
- maxTextureDimension2D: 8192
2339
- },
2340
- lost: new Promise(() => {
2341
- }),
2342
- // Pending promise
2343
- createShaderModule: vi12.fn(),
2344
- createBindGroupLayout: vi12.fn(),
2345
- createPipelineLayout: vi12.fn(),
2346
- createRenderPipeline: vi12.fn(),
2347
- createCommandEncoder: vi12.fn().mockReturnValue({
2348
- copyTextureToBuffer: vi12.fn(),
2349
- finish: vi12.fn()
2350
- }),
2351
- createBuffer: vi12.fn(),
2352
- createTexture: vi12.fn().mockReturnValue({
2353
- createView: vi12.fn()
2354
- }),
2355
- queue: {
2356
- submit: vi12.fn(),
2357
- writeBuffer: vi12.fn(),
2358
- writeTexture: vi12.fn()
2366
+ adapter,
2367
+ device,
2368
+ cleanup: async () => {
2369
+ device.destroy();
2359
2370
  }
2360
2371
  };
2361
2372
  }
2362
- function createMockGPUCanvasContext() {
2373
+ async function createHeadlessTestContext() {
2374
+ const { adapter, device } = await initHeadlessWebGPU();
2363
2375
  return {
2364
- configure: vi12.fn(),
2365
- getCurrentTexture: vi12.fn()
2376
+ adapter,
2377
+ device,
2378
+ queue: device.queue
2366
2379
  };
2367
2380
  }
2381
+
2382
+ // src/engine/mocks/webgpu.ts
2383
+ import { vi as vi12 } from "vitest";
2368
2384
  function setupWebGPUMocks() {
2369
- const mockAdapter = createMockGPUAdapter();
2385
+ Object.assign(globalThis, globals);
2370
2386
  const mockGpu = {
2371
- requestAdapter: vi12.fn().mockResolvedValue(mockAdapter),
2387
+ requestAdapter: vi12.fn(),
2372
2388
  getPreferredCanvasFormat: vi12.fn().mockReturnValue("bgra8unorm")
2373
2389
  };
2374
- Object.defineProperty(global, "navigator", {
2375
- value: {
2376
- ...global.navigator,
2377
- gpu: mockGpu
2378
- },
2379
- writable: true
2380
- });
2381
- if (typeof GPUTextureUsage === "undefined") {
2382
- global.GPUTextureUsage = {
2383
- COPY_SRC: 1,
2384
- COPY_DST: 2,
2385
- TEXTURE_BINDING: 4,
2386
- STORAGE_BINDING: 8,
2387
- RENDER_ATTACHMENT: 16
2388
- };
2389
- }
2390
- if (typeof GPUBufferUsage === "undefined") {
2391
- global.GPUBufferUsage = {
2392
- MAP_READ: 1,
2393
- MAP_WRITE: 2,
2394
- COPY_SRC: 4,
2395
- COPY_DST: 8,
2396
- INDEX: 16,
2397
- VERTEX: 32,
2398
- UNIFORM: 64,
2399
- STORAGE: 128,
2400
- INDIRECT: 256,
2401
- QUERY_RESOLVE: 512
2402
- };
2390
+ const mockAdapter = createMockGPUAdapter();
2391
+ const mockDevice = createMockGPUDevice();
2392
+ mockGpu.requestAdapter.mockResolvedValue(mockAdapter);
2393
+ mockAdapter.requestDevice.mockResolvedValue(mockDevice);
2394
+ if (!globalThis.navigator) {
2395
+ globalThis.navigator = {};
2403
2396
  }
2404
- if (typeof GPUMapMode === "undefined") {
2405
- global.GPUMapMode = {
2406
- READ: 1,
2407
- WRITE: 2
2408
- };
2397
+ try {
2398
+ Object.defineProperty(globalThis.navigator, "gpu", {
2399
+ value: mockGpu,
2400
+ writable: true,
2401
+ configurable: true
2402
+ });
2403
+ } catch (e) {
2404
+ globalThis.navigator.gpu = mockGpu;
2409
2405
  }
2410
2406
  return {
2411
2407
  mockGpu,
2412
- mockAdapter
2408
+ mockAdapter,
2409
+ mockDevice
2410
+ };
2411
+ }
2412
+ function createMockGPUAdapter(options = {}) {
2413
+ return {
2414
+ features: /* @__PURE__ */ new Set(),
2415
+ limits: {},
2416
+ isFallbackAdapter: false,
2417
+ requestDevice: vi12.fn().mockResolvedValue(createMockGPUDevice()),
2418
+ requestAdapterInfo: vi12.fn().mockResolvedValue({}),
2419
+ ...options
2420
+ };
2421
+ }
2422
+ function createMockGPUDevice(features = /* @__PURE__ */ new Set()) {
2423
+ const queue = createMockQueue();
2424
+ return {
2425
+ features,
2426
+ limits: {},
2427
+ queue,
2428
+ destroy: vi12.fn(),
2429
+ createBuffer: vi12.fn((descriptor) => createMockGPUBuffer(descriptor)),
2430
+ createTexture: vi12.fn((descriptor) => createMockGPUTexture(descriptor)),
2431
+ createSampler: vi12.fn(() => createMockSampler()),
2432
+ createBindGroupLayout: vi12.fn(() => ({ label: "mock-bind-group-layout" })),
2433
+ createPipelineLayout: vi12.fn(() => ({ label: "mock-pipeline-layout" })),
2434
+ createBindGroup: vi12.fn(() => ({ label: "mock-bind-group" })),
2435
+ createShaderModule: vi12.fn((descriptor) => createMockShaderModule(descriptor)),
2436
+ createComputePipeline: vi12.fn(() => createMockComputePipeline()),
2437
+ createRenderPipeline: vi12.fn(() => createMockRenderPipeline()),
2438
+ createComputePipelineAsync: vi12.fn().mockResolvedValue(createMockComputePipeline()),
2439
+ createRenderPipelineAsync: vi12.fn().mockResolvedValue(createMockRenderPipeline()),
2440
+ createCommandEncoder: vi12.fn(() => createMockCommandEncoder()),
2441
+ createQuerySet: vi12.fn(() => ({ label: "mock-query-set" })),
2442
+ pushErrorScope: vi12.fn(),
2443
+ popErrorScope: vi12.fn().mockResolvedValue(null),
2444
+ addEventListener: vi12.fn(),
2445
+ removeEventListener: vi12.fn(),
2446
+ dispatchEvent: vi12.fn(),
2447
+ onuncapturederror: null,
2448
+ label: "",
2449
+ lost: Promise.resolve({ reason: "destroyed", message: "Device lost" })
2450
+ };
2451
+ }
2452
+ function createMockQueue() {
2453
+ return {
2454
+ submit: vi12.fn(),
2455
+ onSubmittedWorkDone: vi12.fn().mockResolvedValue(void 0),
2456
+ writeBuffer: vi12.fn(),
2457
+ writeTexture: vi12.fn(),
2458
+ copyExternalImageToTexture: vi12.fn(),
2459
+ label: ""
2460
+ };
2461
+ }
2462
+ function createMockGPUBuffer(descriptor) {
2463
+ return {
2464
+ size: descriptor.size,
2465
+ usage: descriptor.usage,
2466
+ mapState: "unmapped",
2467
+ mapAsync: vi12.fn().mockResolvedValue(void 0),
2468
+ getMappedRange: vi12.fn(() => new ArrayBuffer(descriptor.size)),
2469
+ unmap: vi12.fn(),
2470
+ destroy: vi12.fn(),
2471
+ label: descriptor.label || ""
2472
+ };
2473
+ }
2474
+ function createMockGPUTexture(descriptor) {
2475
+ const size = descriptor.size;
2476
+ let width = 0;
2477
+ let height = 0;
2478
+ let depthOrArrayLayers = 1;
2479
+ if (Array.isArray(size) || size instanceof Float32Array || size instanceof Uint32Array) {
2480
+ const arr = Array.from(size);
2481
+ width = arr[0] || 0;
2482
+ height = arr[1] || 1;
2483
+ depthOrArrayLayers = arr[2] || 1;
2484
+ } else if (typeof size === "object") {
2485
+ const dict = size;
2486
+ width = dict.width;
2487
+ height = dict.height || 1;
2488
+ depthOrArrayLayers = dict.depthOrArrayLayers || 1;
2489
+ }
2490
+ return {
2491
+ width,
2492
+ height,
2493
+ depthOrArrayLayers,
2494
+ mipLevelCount: descriptor.mipLevelCount || 1,
2495
+ sampleCount: descriptor.sampleCount || 1,
2496
+ dimension: descriptor.dimension || "2d",
2497
+ format: descriptor.format,
2498
+ usage: descriptor.usage,
2499
+ createView: vi12.fn(() => createMockTextureView()),
2500
+ destroy: vi12.fn(),
2501
+ label: descriptor.label || ""
2502
+ };
2503
+ }
2504
+ function createMockTextureView() {
2505
+ return {
2506
+ label: ""
2507
+ };
2508
+ }
2509
+ function createMockSampler() {
2510
+ return {
2511
+ label: ""
2512
+ };
2513
+ }
2514
+ function createMockShaderModule(descriptor) {
2515
+ return {
2516
+ getCompilationInfo: vi12.fn().mockResolvedValue({ messages: [] }),
2517
+ label: descriptor.label || ""
2518
+ };
2519
+ }
2520
+ function createMockComputePipeline() {
2521
+ return {
2522
+ getBindGroupLayout: vi12.fn(() => ({ label: "mock-bind-group-layout" })),
2523
+ label: ""
2524
+ };
2525
+ }
2526
+ function createMockRenderPipeline() {
2527
+ return {
2528
+ getBindGroupLayout: vi12.fn(() => ({ label: "mock-bind-group-layout" })),
2529
+ label: ""
2530
+ };
2531
+ }
2532
+ function createMockCommandEncoder() {
2533
+ return {
2534
+ beginRenderPass: vi12.fn(() => createMockRenderPassEncoder()),
2535
+ beginComputePass: vi12.fn(() => createMockComputePassEncoder()),
2536
+ copyBufferToBuffer: vi12.fn(),
2537
+ copyBufferToTexture: vi12.fn(),
2538
+ copyTextureToBuffer: vi12.fn(),
2539
+ copyTextureToTexture: vi12.fn(),
2540
+ clearBuffer: vi12.fn(),
2541
+ writeTimestamp: vi12.fn(),
2542
+ resolveQuerySet: vi12.fn(),
2543
+ finish: vi12.fn(() => ({ label: "mock-command-buffer" })),
2544
+ pushDebugGroup: vi12.fn(),
2545
+ popDebugGroup: vi12.fn(),
2546
+ insertDebugMarker: vi12.fn(),
2547
+ label: ""
2548
+ };
2549
+ }
2550
+ function createMockRenderPassEncoder() {
2551
+ return {
2552
+ setPipeline: vi12.fn(),
2553
+ setIndexBuffer: vi12.fn(),
2554
+ setVertexBuffer: vi12.fn(),
2555
+ setBindGroup: vi12.fn(),
2556
+ setViewport: vi12.fn(),
2557
+ setScissorRect: vi12.fn(),
2558
+ setBlendConstant: vi12.fn(),
2559
+ setStencilReference: vi12.fn(),
2560
+ beginOcclusionQuery: vi12.fn(),
2561
+ endOcclusionQuery: vi12.fn(),
2562
+ executeBundles: vi12.fn(),
2563
+ draw: vi12.fn(),
2564
+ drawIndexed: vi12.fn(),
2565
+ drawIndirect: vi12.fn(),
2566
+ drawIndexedIndirect: vi12.fn(),
2567
+ end: vi12.fn(),
2568
+ pushDebugGroup: vi12.fn(),
2569
+ popDebugGroup: vi12.fn(),
2570
+ insertDebugMarker: vi12.fn(),
2571
+ label: ""
2572
+ };
2573
+ }
2574
+ function createMockComputePassEncoder() {
2575
+ return {
2576
+ setPipeline: vi12.fn(),
2577
+ setBindGroup: vi12.fn(),
2578
+ dispatchWorkgroups: vi12.fn(),
2579
+ dispatchWorkgroupsIndirect: vi12.fn(),
2580
+ end: vi12.fn(),
2581
+ pushDebugGroup: vi12.fn(),
2582
+ popDebugGroup: vi12.fn(),
2583
+ insertDebugMarker: vi12.fn(),
2584
+ label: ""
2585
+ };
2586
+ }
2587
+ function createMockWebGPUContext() {
2588
+ const adapter = createMockGPUAdapter();
2589
+ const device = createMockGPUDevice();
2590
+ return {
2591
+ adapter,
2592
+ device,
2593
+ queue: device.queue
2413
2594
  };
2414
2595
  }
2415
2596
 
@@ -2813,20 +2994,140 @@ function createMockSkyboxPipeline(overrides) {
2813
2994
  };
2814
2995
  }
2815
2996
 
2816
- // src/engine/rendering.ts
2997
+ // src/engine/mocks/assets.ts
2817
2998
  import { vi as vi14 } from "vitest";
2999
+ function createMockAssetManager(overrides) {
3000
+ return {
3001
+ textures: {
3002
+ get: vi14.fn(),
3003
+ set: vi14.fn(),
3004
+ has: vi14.fn(),
3005
+ clear: vi14.fn(),
3006
+ memoryUsage: 0
3007
+ },
3008
+ audio: {
3009
+ load: vi14.fn(),
3010
+ get: vi14.fn(),
3011
+ clearAll: vi14.fn()
3012
+ },
3013
+ loadTexture: vi14.fn().mockResolvedValue({}),
3014
+ registerTexture: vi14.fn(),
3015
+ loadSound: vi14.fn().mockResolvedValue({}),
3016
+ loadMd2Model: vi14.fn().mockResolvedValue({}),
3017
+ getMd2Model: vi14.fn(),
3018
+ loadMd3Model: vi14.fn().mockResolvedValue({}),
3019
+ getMd3Model: vi14.fn(),
3020
+ loadSprite: vi14.fn().mockResolvedValue({}),
3021
+ loadMap: vi14.fn().mockResolvedValue({}),
3022
+ getMap: vi14.fn(),
3023
+ loadPalette: vi14.fn().mockResolvedValue(void 0),
3024
+ isAssetLoaded: vi14.fn().mockReturnValue(true),
3025
+ listFiles: vi14.fn().mockReturnValue([]),
3026
+ resetForLevelChange: vi14.fn(),
3027
+ getMemoryUsage: vi14.fn().mockReturnValue({ textures: 0, audio: 0 }),
3028
+ clearCache: vi14.fn(),
3029
+ preloadAssets: vi14.fn().mockResolvedValue(void 0),
3030
+ queueLoad: vi14.fn().mockImplementation((path2) => Promise.resolve({})),
3031
+ ...overrides
3032
+ };
3033
+ }
3034
+ function createMockTexture(width = 1, height = 1, data) {
3035
+ return {
3036
+ width,
3037
+ height,
3038
+ data: data || new Uint8Array(width * height * 4).fill(255),
3039
+ format: 0,
3040
+ // RGBA
3041
+ name: "mock_texture",
3042
+ uploaded: false
3043
+ };
3044
+ }
3045
+ function createMockMd2Model(overrides) {
3046
+ return {
3047
+ header: {
3048
+ skinWidth: 0,
3049
+ skinHeight: 0,
3050
+ frameSize: 0,
3051
+ numSkins: 0,
3052
+ numVertices: 0,
3053
+ numSt: 0,
3054
+ numTriangles: 0,
3055
+ numGlCmds: 0,
3056
+ numFrames: 0,
3057
+ offsetSkins: 0,
3058
+ offsetSt: 0,
3059
+ offsetTriangles: 0,
3060
+ offsetFrames: 0,
3061
+ offsetGlCmds: 0,
3062
+ offsetEnd: 0
3063
+ },
3064
+ skins: [],
3065
+ texCoords: [],
3066
+ triangles: [],
3067
+ frames: [],
3068
+ glCommands: new Int32Array(0),
3069
+ ...overrides
3070
+ };
3071
+ }
3072
+ function createMockMd3Model(overrides) {
3073
+ return {
3074
+ header: {
3075
+ ident: 0,
3076
+ version: 0,
3077
+ name: "",
3078
+ flags: 0,
3079
+ numFrames: 0,
3080
+ numTags: 0,
3081
+ numSurfaces: 0,
3082
+ numSkins: 0,
3083
+ offsetFrames: 0,
3084
+ offsetTags: 0,
3085
+ offsetSurfaces: 0,
3086
+ offsetEnd: 0
3087
+ },
3088
+ frames: [],
3089
+ tags: [],
3090
+ surfaces: [],
3091
+ ...overrides
3092
+ };
3093
+ }
3094
+ function createMockBspMap(overrides) {
3095
+ return {
3096
+ version: 38,
3097
+ entities: [],
3098
+ planes: [],
3099
+ vertices: [],
3100
+ visibility: new Uint8Array(0),
3101
+ nodes: [],
3102
+ texInfo: [],
3103
+ faces: [],
3104
+ lightmaps: [],
3105
+ leafs: [],
3106
+ leafFaces: [],
3107
+ leafBrushes: [],
3108
+ edges: [],
3109
+ faceEdges: [],
3110
+ models: [],
3111
+ brushes: [],
3112
+ brushSides: [],
3113
+ ...overrides
3114
+ };
3115
+ }
3116
+
3117
+ // src/engine/rendering.ts
3118
+ import { vi as vi15 } from "vitest";
2818
3119
  function createMockRenderingContext() {
2819
3120
  const gl = createMockWebGL2Context();
2820
3121
  const camera = {
2821
- update: vi14.fn(),
2822
- getViewMatrix: vi14.fn().mockReturnValue(new Float32Array(16)),
2823
- getProjectionMatrix: vi14.fn().mockReturnValue(new Float32Array(16)),
2824
- getViewProjectionMatrix: vi14.fn().mockReturnValue(new Float32Array(16)),
2825
- getPosition: vi14.fn().mockReturnValue([0, 0, 0]),
2826
- getForward: vi14.fn().mockReturnValue([0, 0, -1]),
2827
- getRight: vi14.fn().mockReturnValue([1, 0, 0]),
2828
- getUp: vi14.fn().mockReturnValue([0, 1, 0]),
2829
- extractFrustumPlanes: vi14.fn(),
3122
+ update: vi15.fn(),
3123
+ getViewMatrix: vi15.fn().mockReturnValue(new Float32Array(16)),
3124
+ getProjectionMatrix: vi15.fn().mockReturnValue(new Float32Array(16)),
3125
+ getViewProjectionMatrix: vi15.fn().mockReturnValue(new Float32Array(16)),
3126
+ getPosition: vi15.fn().mockReturnValue([0, 0, 0]),
3127
+ getForward: vi15.fn().mockReturnValue([0, 0, -1]),
3128
+ getRight: vi15.fn().mockReturnValue([1, 0, 0]),
3129
+ getUp: vi15.fn().mockReturnValue([0, 1, 0]),
3130
+ extractFrustumPlanes: vi15.fn(),
2830
3131
  transform: {
2831
3132
  origin: [0, 0, 0],
2832
3133
  angles: [0, 0, 0],
@@ -2834,29 +3135,29 @@ function createMockRenderingContext() {
2834
3135
  }
2835
3136
  };
2836
3137
  const md2 = {
2837
- render: vi14.fn(),
2838
- init: vi14.fn(),
2839
- resize: vi14.fn()
3138
+ render: vi15.fn(),
3139
+ init: vi15.fn(),
3140
+ resize: vi15.fn()
2840
3141
  };
2841
3142
  const bsp = {
2842
- render: vi14.fn(),
2843
- init: vi14.fn(),
2844
- resize: vi14.fn()
3143
+ render: vi15.fn(),
3144
+ init: vi15.fn(),
3145
+ resize: vi15.fn()
2845
3146
  };
2846
3147
  const sprite = {
2847
- render: vi14.fn(),
2848
- init: vi14.fn(),
2849
- resize: vi14.fn()
3148
+ render: vi15.fn(),
3149
+ init: vi15.fn(),
3150
+ resize: vi15.fn()
2850
3151
  };
2851
3152
  const poly = {
2852
- render: vi14.fn(),
2853
- init: vi14.fn(),
2854
- resize: vi14.fn()
3153
+ render: vi15.fn(),
3154
+ init: vi15.fn(),
3155
+ resize: vi15.fn()
2855
3156
  };
2856
3157
  const particle = {
2857
- render: vi14.fn(),
2858
- init: vi14.fn(),
2859
- resize: vi14.fn()
3158
+ render: vi15.fn(),
3159
+ init: vi15.fn(),
3160
+ resize: vi15.fn()
2860
3161
  };
2861
3162
  return {
2862
3163
  gl,
@@ -3009,6 +3310,207 @@ function captureAudioEvents(context) {
3009
3310
  return [];
3010
3311
  }
3011
3312
 
3313
+ // src/engine/helpers/webgpu-rendering.ts
3314
+ async function createRenderTestSetup(width = 256, height = 256) {
3315
+ const setup = await initHeadlessWebGPU();
3316
+ const { device } = setup;
3317
+ const renderTarget = device.createTexture({
3318
+ size: { width, height, depthOrArrayLayers: 1 },
3319
+ format: "rgba8unorm",
3320
+ usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC
3321
+ });
3322
+ const renderTargetView = renderTarget.createView();
3323
+ const commandEncoder = device.createCommandEncoder();
3324
+ const context = {
3325
+ adapter: setup.adapter,
3326
+ device: setup.device,
3327
+ queue: setup.device.queue
3328
+ };
3329
+ return {
3330
+ context,
3331
+ renderTarget,
3332
+ renderTargetView,
3333
+ commandEncoder,
3334
+ width,
3335
+ height,
3336
+ cleanup: async () => {
3337
+ renderTarget.destroy();
3338
+ await setup.cleanup();
3339
+ }
3340
+ };
3341
+ }
3342
+ async function renderAndCapture(setup, renderFn) {
3343
+ const { device, queue } = setup.context;
3344
+ const { renderTargetView, commandEncoder, width, height } = setup;
3345
+ const passEncoder = commandEncoder.beginRenderPass({
3346
+ colorAttachments: [
3347
+ {
3348
+ view: renderTargetView,
3349
+ clearValue: { r: 0, g: 0, b: 0, a: 0 },
3350
+ loadOp: "clear",
3351
+ storeOp: "store"
3352
+ }
3353
+ ]
3354
+ });
3355
+ renderFn(passEncoder);
3356
+ passEncoder.end();
3357
+ const bytesPerPixel = 4;
3358
+ const unpaddedBytesPerRow = width * bytesPerPixel;
3359
+ const align = 256;
3360
+ const paddedBytesPerRow = Math.max(
3361
+ bytesPerPixel * width,
3362
+ Math.ceil(bytesPerPixel * width / align) * align
3363
+ );
3364
+ const bufferSize = paddedBytesPerRow * height;
3365
+ const readbackBuffer = device.createBuffer({
3366
+ size: bufferSize,
3367
+ usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ
3368
+ });
3369
+ commandEncoder.copyTextureToBuffer(
3370
+ {
3371
+ texture: setup.renderTarget
3372
+ },
3373
+ {
3374
+ buffer: readbackBuffer,
3375
+ bytesPerRow: paddedBytesPerRow
3376
+ },
3377
+ {
3378
+ width,
3379
+ height,
3380
+ depthOrArrayLayers: 1
3381
+ }
3382
+ );
3383
+ queue.submit([commandEncoder.finish()]);
3384
+ await readbackBuffer.mapAsync(GPUMapMode.READ);
3385
+ const arrayBuffer = readbackBuffer.getMappedRange();
3386
+ const output = new Uint8ClampedArray(width * height * 4);
3387
+ const srcBytes = new Uint8Array(arrayBuffer);
3388
+ for (let y = 0; y < height; y++) {
3389
+ const srcOffset = y * paddedBytesPerRow;
3390
+ const dstOffset = y * unpaddedBytesPerRow;
3391
+ output.set(srcBytes.subarray(srcOffset, srcOffset + unpaddedBytesPerRow), dstOffset);
3392
+ }
3393
+ readbackBuffer.unmap();
3394
+ readbackBuffer.destroy();
3395
+ return output;
3396
+ }
3397
+ async function createComputeTestSetup(outputSize) {
3398
+ const setup = await initHeadlessWebGPU();
3399
+ const { device } = setup;
3400
+ const outputBuffer = device.createBuffer({
3401
+ size: outputSize,
3402
+ usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC
3403
+ });
3404
+ const commandEncoder = device.createCommandEncoder();
3405
+ const context = {
3406
+ adapter: setup.adapter,
3407
+ device: setup.device,
3408
+ queue: setup.device.queue
3409
+ };
3410
+ return {
3411
+ context,
3412
+ outputBuffer,
3413
+ commandEncoder,
3414
+ outputSize,
3415
+ cleanup: async () => {
3416
+ outputBuffer.destroy();
3417
+ await setup.cleanup();
3418
+ }
3419
+ };
3420
+ }
3421
+ async function runComputeAndReadback(setup, computeFn) {
3422
+ const { device, queue } = setup.context;
3423
+ const { outputBuffer, commandEncoder, outputSize } = setup;
3424
+ const passEncoder = commandEncoder.beginComputePass();
3425
+ computeFn(passEncoder);
3426
+ passEncoder.end();
3427
+ const stagingBuffer = device.createBuffer({
3428
+ size: outputSize,
3429
+ usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ
3430
+ });
3431
+ commandEncoder.copyBufferToBuffer(
3432
+ outputBuffer,
3433
+ 0,
3434
+ stagingBuffer,
3435
+ 0,
3436
+ outputSize
3437
+ );
3438
+ queue.submit([commandEncoder.finish()]);
3439
+ await stagingBuffer.mapAsync(GPUMapMode.READ);
3440
+ const mappedRange = stagingBuffer.getMappedRange();
3441
+ const result = mappedRange.slice(0);
3442
+ stagingBuffer.unmap();
3443
+ stagingBuffer.destroy();
3444
+ return result;
3445
+ }
3446
+
3447
+ // src/engine/helpers/pipeline-test-template.ts
3448
+ import { expect } from "vitest";
3449
+ async function testPipelineRendering(name, createPipeline, setupGeometry, expectedOutput) {
3450
+ const setup = await createRenderTestSetup(256, 256);
3451
+ try {
3452
+ const pipeline = createPipeline(setup.context.device);
3453
+ const geometry = setupGeometry(setup.context.device);
3454
+ const pixels = await renderAndCapture(setup, (pass) => {
3455
+ pass.setPipeline(pipeline);
3456
+ pass.setVertexBuffer(0, geometry.vertexBuffer);
3457
+ if (geometry.indexBuffer) {
3458
+ pass.setIndexBuffer(geometry.indexBuffer, "uint16");
3459
+ pass.drawIndexed(geometry.indexCount || 0);
3460
+ } else {
3461
+ pass.draw(geometry.vertexCount);
3462
+ }
3463
+ });
3464
+ if (expectedOutput) {
3465
+ expect(pixels).toEqual(expectedOutput);
3466
+ } else {
3467
+ expect(pixels.length).toBe(256 * 256 * 4);
3468
+ }
3469
+ } finally {
3470
+ await setup.cleanup();
3471
+ }
3472
+ }
3473
+ async function testComputeShader(name, createComputePipeline, inputData, expectedOutput) {
3474
+ const setup = await createComputeTestSetup(inputData.byteLength);
3475
+ const { device } = setup.context;
3476
+ try {
3477
+ const pipeline = createComputePipeline(device);
3478
+ const stagingBuffer = device.createBuffer({
3479
+ size: inputData.byteLength,
3480
+ usage: GPUBufferUsage.COPY_SRC | GPUBufferUsage.MAP_WRITE,
3481
+ mappedAtCreation: true
3482
+ });
3483
+ new Float32Array(stagingBuffer.getMappedRange()).set(inputData);
3484
+ stagingBuffer.unmap();
3485
+ const encoder = device.createCommandEncoder();
3486
+ encoder.copyBufferToBuffer(stagingBuffer, 0, setup.outputBuffer, 0, inputData.byteLength);
3487
+ device.queue.submit([encoder.finish()]);
3488
+ const bindGroup = device.createBindGroup({
3489
+ layout: pipeline.getBindGroupLayout(0),
3490
+ entries: [
3491
+ {
3492
+ binding: 0,
3493
+ resource: {
3494
+ buffer: setup.outputBuffer
3495
+ }
3496
+ }
3497
+ ]
3498
+ });
3499
+ const resultBuffer = await runComputeAndReadback(setup, (pass) => {
3500
+ pass.setPipeline(pipeline);
3501
+ pass.setBindGroup(0, bindGroup);
3502
+ pass.dispatchWorkgroups(Math.ceil(inputData.length / 64));
3503
+ });
3504
+ if (expectedOutput) {
3505
+ const floatResult = new Float32Array(resultBuffer);
3506
+ expect(floatResult).toEqual(expectedOutput);
3507
+ }
3508
+ stagingBuffer.destroy();
3509
+ } finally {
3510
+ await setup.cleanup();
3511
+ }
3512
+ }
3513
+
3012
3514
  // ../../node_modules/.pnpm/gl-matrix@3.4.4/node_modules/gl-matrix/esm/common.js
3013
3515
  var EPSILON = 1e-6;
3014
3516
  var ARRAY_TYPE = typeof Float32Array !== "undefined" ? Float32Array : Array;
@@ -3029,7 +3531,7 @@ __export(vec3_exports, {
3029
3531
  ceil: () => ceil,
3030
3532
  clone: () => clone,
3031
3533
  copy: () => copy,
3032
- create: () => create,
3534
+ create: () => create2,
3033
3535
  cross: () => cross,
3034
3536
  dist: () => dist,
3035
3537
  distance: () => distance,
@@ -3073,7 +3575,7 @@ __export(vec3_exports, {
3073
3575
  transformQuat: () => transformQuat,
3074
3576
  zero: () => zero
3075
3577
  });
3076
- function create() {
3578
+ function create2() {
3077
3579
  var out = new ARRAY_TYPE(3);
3078
3580
  if (ARRAY_TYPE != Float32Array) {
3079
3581
  out[0] = 0;
@@ -3385,7 +3887,7 @@ var sqrDist = squaredDistance;
3385
3887
  var len = length;
3386
3888
  var sqrLen = squaredLength;
3387
3889
  var forEach = (function() {
3388
- var vec = create();
3890
+ var vec = create2();
3389
3891
  return function(a, stride, offset, count, fn, arg) {
3390
3892
  var i, l;
3391
3893
  if (!stride) {
@@ -3508,7 +4010,7 @@ function simulateCameraMovement(camera, input, deltaTime) {
3508
4010
  }
3509
4011
 
3510
4012
  // src/client/helpers/hud.ts
3511
- import { vi as vi15 } from "vitest";
4013
+ import { vi as vi16 } from "vitest";
3512
4014
  function createMockHudState(overrides) {
3513
4015
  const defaultPs = {
3514
4016
  damageAlpha: 0,
@@ -3543,11 +4045,11 @@ function createMockHudState(overrides) {
3543
4045
  batches: 10
3544
4046
  };
3545
4047
  const defaultMessages = {
3546
- drawCenterPrint: vi15.fn(),
3547
- drawNotifications: vi15.fn(),
3548
- addCenterPrint: vi15.fn(),
3549
- addNotification: vi15.fn(),
3550
- clear: vi15.fn()
4048
+ drawCenterPrint: vi16.fn(),
4049
+ drawNotifications: vi16.fn(),
4050
+ addCenterPrint: vi16.fn(),
4051
+ addNotification: vi16.fn(),
4052
+ clear: vi16.fn()
3551
4053
  };
3552
4054
  return {
3553
4055
  ps: overrides?.ps ?? defaultPs,
@@ -3563,7 +4065,7 @@ function createMockHudState(overrides) {
3563
4065
  function createMockScoreboard(players = []) {
3564
4066
  return {
3565
4067
  players,
3566
- draw: vi15.fn()
4068
+ draw: vi16.fn()
3567
4069
  };
3568
4070
  }
3569
4071
  function createMockChatMessage(text, sender, timestamp = Date.now()) {
@@ -3664,6 +4166,254 @@ function createMockFogData(overrides = {}) {
3664
4166
  };
3665
4167
  }
3666
4168
 
4169
+ // src/client/mocks/download.ts
4170
+ import { vi as vi17 } from "vitest";
4171
+ function createMockDownloadManager(overrides) {
4172
+ return {
4173
+ download: vi17.fn().mockResolvedValue(new ArrayBuffer(0)),
4174
+ cancel: vi17.fn(),
4175
+ getProgress: vi17.fn().mockReturnValue(0),
4176
+ ...overrides
4177
+ };
4178
+ }
4179
+ function createMockPrecacheList(models = [], sounds = [], images = []) {
4180
+ return {
4181
+ models,
4182
+ sounds,
4183
+ images
4184
+ };
4185
+ }
4186
+ async function simulateDownload(url, progressCallback) {
4187
+ const steps = 10;
4188
+ for (let i = 0; i <= steps; i++) {
4189
+ if (progressCallback) {
4190
+ progressCallback(i / steps);
4191
+ }
4192
+ await new Promise((resolve) => setTimeout(resolve, 10));
4193
+ }
4194
+ return new ArrayBuffer(1024);
4195
+ }
4196
+
4197
+ // src/client/mocks/state.ts
4198
+ var MAX_MODELS = 256;
4199
+ var MAX_SOUNDS = 256;
4200
+ var MAX_IMAGES = 256;
4201
+ var MockClientConfigStrings = class {
4202
+ constructor() {
4203
+ this.strings = /* @__PURE__ */ new Map();
4204
+ this.models = [];
4205
+ this.sounds = [];
4206
+ this.images = [];
4207
+ }
4208
+ set(index, value) {
4209
+ this.strings.set(index, value);
4210
+ if (index >= 32 /* Models */ && index < 32 /* Models */ + MAX_MODELS) {
4211
+ this.models[index - 32 /* Models */] = value;
4212
+ } else if (index >= 288 /* Sounds */ && index < 288 /* Sounds */ + MAX_SOUNDS) {
4213
+ this.sounds[index - 288 /* Sounds */] = value;
4214
+ } else if (index >= 544 /* Images */ && index < 544 /* Images */ + MAX_IMAGES) {
4215
+ this.images[index - 544 /* Images */] = value;
4216
+ }
4217
+ }
4218
+ get(index) {
4219
+ return this.strings.get(index);
4220
+ }
4221
+ getModelName(index) {
4222
+ return this.models[index];
4223
+ }
4224
+ getSoundName(index) {
4225
+ return this.sounds[index];
4226
+ }
4227
+ getImageName(index) {
4228
+ return this.images[index];
4229
+ }
4230
+ getPlayerName(playernum) {
4231
+ const info = this.strings.get(800 /* Players */ + playernum);
4232
+ if (!info) return void 0;
4233
+ const parts = info.split("\\");
4234
+ for (let i = 1; i < parts.length; i += 2) {
4235
+ if (parts[i] === "name") {
4236
+ return parts[i + 1];
4237
+ }
4238
+ }
4239
+ return void 0;
4240
+ }
4241
+ clear() {
4242
+ this.strings.clear();
4243
+ this.models.length = 0;
4244
+ this.sounds.length = 0;
4245
+ this.images.length = 0;
4246
+ }
4247
+ };
4248
+ var createMockClientState = (overrides) => {
4249
+ const configStrings = new MockClientConfigStrings();
4250
+ return {
4251
+ tickRate: 10,
4252
+ frameTimeMs: 100,
4253
+ serverFrame: 0,
4254
+ serverProtocol: 34,
4255
+ configStrings,
4256
+ playerNum: 0,
4257
+ serverTime: 0,
4258
+ parseEntities: 0,
4259
+ inAutoDemo: false,
4260
+ getClientName: (num) => `Player${num}`,
4261
+ getKeyBinding: (key) => "",
4262
+ ...overrides
4263
+ };
4264
+ };
4265
+ var createMockFrame = (overrides) => ({
4266
+ serverFrame: 0,
4267
+ deltaFrame: -1,
4268
+ valid: true,
4269
+ entities: [],
4270
+ ...overrides
4271
+ });
4272
+ var createMockClientInfo = (overrides) => ({
4273
+ name: "Player",
4274
+ skin: "male/grunt",
4275
+ model: "male",
4276
+ icon: "pics/icon.pcx",
4277
+ ...overrides
4278
+ });
4279
+ var createMockConnectionState = (state = "connected") => ({
4280
+ state
4281
+ });
4282
+
4283
+ // src/client/mocks/console.ts
4284
+ import { vi as vi18 } from "vitest";
4285
+ function createMockConsole(overrides) {
4286
+ const history = [];
4287
+ const errors = [];
4288
+ const commands = {};
4289
+ const cvars = {};
4290
+ return {
4291
+ print: vi18.fn((text) => {
4292
+ history.push(text);
4293
+ }),
4294
+ error: vi18.fn((text) => {
4295
+ errors.push(text);
4296
+ }),
4297
+ execute: vi18.fn((text) => {
4298
+ const parts = text.trim().split(/\s+/);
4299
+ const cmd = parts[0];
4300
+ const args = parts.slice(1);
4301
+ if (commands[cmd]) {
4302
+ commands[cmd](args);
4303
+ } else {
4304
+ history.push(`Unknown command "${cmd}"`);
4305
+ }
4306
+ }),
4307
+ addCommand: vi18.fn((name, handler) => {
4308
+ commands[name] = handler;
4309
+ }),
4310
+ getCvar: vi18.fn((name) => cvars[name]),
4311
+ setCvar: vi18.fn((name, value) => {
4312
+ cvars[name] = value;
4313
+ }),
4314
+ getHistory: () => history,
4315
+ clearHistory: () => {
4316
+ history.length = 0;
4317
+ errors.length = 0;
4318
+ },
4319
+ getErrors: () => errors,
4320
+ ...overrides
4321
+ };
4322
+ }
4323
+ function createMockCommand(name, handler) {
4324
+ return { name, handler };
4325
+ }
4326
+ function createMockCvarRegistry(initialCvars) {
4327
+ return { ...initialCvars };
4328
+ }
4329
+
4330
+ // src/client/helpers/prediction.ts
4331
+ var createPredictionTestScenario = (lagMs = 100) => {
4332
+ const clientState = createMockClientState({
4333
+ playerNum: 0,
4334
+ serverTime: 1e3,
4335
+ getClientName: (num) => "TestPlayer"
4336
+ });
4337
+ const snapshots = [];
4338
+ for (let i = 0; i < 5; i++) {
4339
+ const frameEntities = [
4340
+ {
4341
+ number: 1,
4342
+ origin: { x: i * 10, y: 0, z: 0 },
4343
+ angles: { x: 0, y: 0, z: 0 },
4344
+ oldOrigin: { x: (i - 1) * 10, y: 0, z: 0 },
4345
+ modelIndex: 0,
4346
+ modelIndex2: 0,
4347
+ modelIndex3: 0,
4348
+ modelIndex4: 0,
4349
+ frame: 0,
4350
+ skinNum: 0,
4351
+ effects: 0,
4352
+ renderfx: 0,
4353
+ solid: 0,
4354
+ sound: 0,
4355
+ event: 0
4356
+ }
4357
+ ];
4358
+ snapshots.push(frameEntities);
4359
+ }
4360
+ return {
4361
+ clientState,
4362
+ snapshots,
4363
+ lagMs
4364
+ };
4365
+ };
4366
+ var simulateClientPrediction = (state, input, deltaTime) => {
4367
+ return {
4368
+ ...state,
4369
+ serverTime: state.serverTime + deltaTime * 1e3
4370
+ };
4371
+ };
4372
+ var createInterpolationTestData = (startState, endState, steps = 10) => {
4373
+ const result = [];
4374
+ for (let i = 0; i <= steps; i++) {
4375
+ const t = i / steps;
4376
+ const lerp2 = (a, b) => a + (b - a) * t;
4377
+ result.push({
4378
+ ...startState,
4379
+ origin: {
4380
+ x: lerp2(startState.origin.x, endState.origin.x),
4381
+ y: lerp2(startState.origin.y, endState.origin.y),
4382
+ z: lerp2(startState.origin.z, endState.origin.z)
4383
+ },
4384
+ angles: {
4385
+ x: lerp2(startState.angles.x, endState.angles.x),
4386
+ y: lerp2(startState.angles.y, endState.angles.y),
4387
+ z: lerp2(startState.angles.z, endState.angles.z)
4388
+ }
4389
+ });
4390
+ }
4391
+ return result;
4392
+ };
4393
+ var verifySmoothing = (states) => {
4394
+ let maxError = 0;
4395
+ let totalError = 0;
4396
+ const jumps = [];
4397
+ for (let i = 1; i < states.length; i++) {
4398
+ const prev = states[i - 1].origin;
4399
+ const curr = states[i].origin;
4400
+ const dx = curr.x - prev.x;
4401
+ const dy = curr.y - prev.y;
4402
+ const dz = curr.z - prev.z;
4403
+ const dist2 = Math.sqrt(dx * dx + dy * dy + dz * dz);
4404
+ if (dist2 > 50) {
4405
+ jumps.push(i);
4406
+ }
4407
+ totalError += dist2;
4408
+ }
4409
+ return {
4410
+ smooth: jumps.length === 0,
4411
+ maxError,
4412
+ averageError: totalError / (states.length - 1 || 1),
4413
+ jumps
4414
+ };
4415
+ };
4416
+
3667
4417
  // src/e2e/playwright.ts
3668
4418
  async function createPlaywrightTestClient(options = {}) {
3669
4419
  let playwright;
@@ -3856,6 +4606,7 @@ export {
3856
4606
  HandshakeStage,
3857
4607
  InputInjector,
3858
4608
  FakeBufferSource as MockAudioBufferSourceNode,
4609
+ MockClientConfigStrings,
3859
4610
  MockNetDriver,
3860
4611
  MockNetworkTransport,
3861
4612
  MockPointerLock,
@@ -3872,6 +4623,7 @@ export {
3872
4623
  createBinaryWriterMock,
3873
4624
  createBounds,
3874
4625
  createCombatTestContext,
4626
+ createComputeTestSetup,
3875
4627
  createConfigStringArrayMock,
3876
4628
  createConfigStringMock,
3877
4629
  createControlledTimer,
@@ -3882,33 +4634,49 @@ export {
3882
4634
  createEntityFactory,
3883
4635
  createEntityStateFactory,
3884
4636
  createGameStateSnapshotFactory,
4637
+ createHeadlessTestContext,
3885
4638
  createInputInjector,
4639
+ createInterpolationTestData,
3886
4640
  createItemEntityFactory,
3887
4641
  createMessageReaderMock,
3888
4642
  createMessageWriterMock,
3889
4643
  createMockAI,
3890
4644
  createMockAmmoItem,
3891
4645
  createMockArmorItem,
4646
+ createMockAssetManager,
3892
4647
  createMockAudioBuffer,
3893
4648
  createMockAudioContext,
4649
+ createMockBspMap,
3894
4650
  createMockBspPipeline,
3895
4651
  createMockBufferSource,
3896
4652
  createMockCamera,
3897
4653
  createMockCanvas,
3898
4654
  createMockCanvasContext2D,
3899
4655
  createMockChatMessage,
4656
+ createMockClientInfo,
4657
+ createMockClientState,
3900
4658
  createMockCollisionEntityIndex,
4659
+ createMockCommand,
4660
+ createMockCommandEncoder,
4661
+ createMockComputePassEncoder,
4662
+ createMockComputePipeline,
3901
4663
  createMockConnection,
4664
+ createMockConnectionState,
4665
+ createMockConsole,
4666
+ createMockCvarRegistry,
3902
4667
  createMockDamageIndicator,
3903
4668
  createMockDamageInfo,
3904
4669
  createMockDeltaFrame,
4670
+ createMockDownloadManager,
3905
4671
  createMockEngine,
3906
4672
  createMockEntityState,
3907
4673
  createMockFogData,
4674
+ createMockFrame,
3908
4675
  createMockFrameRenderer,
3909
4676
  createMockGPUAdapter,
3910
- createMockGPUCanvasContext,
4677
+ createMockGPUBuffer,
3911
4678
  createMockGPUDevice,
4679
+ createMockGPUTexture,
3912
4680
  createMockGame,
3913
4681
  createMockGameExports,
3914
4682
  createMockGameState,
@@ -3923,7 +4691,9 @@ export {
3923
4691
  createMockKeyboardEvent,
3924
4692
  createMockLocalStorage,
3925
4693
  createMockMasterServer,
4694
+ createMockMd2Model,
3926
4695
  createMockMd2Pipeline,
4696
+ createMockMd3Model,
3927
4697
  createMockMd3Pipeline,
3928
4698
  createMockMonsterAI,
3929
4699
  createMockMonsterMove,
@@ -3935,12 +4705,17 @@ export {
3935
4705
  createMockPerformance,
3936
4706
  createMockPointerLock,
3937
4707
  createMockPowerupItem,
4708
+ createMockPrecacheList,
4709
+ createMockQueue,
3938
4710
  createMockRAF,
3939
4711
  createMockRConClient,
3940
4712
  createMockRateLimiter,
3941
4713
  createMockRefDef,
4714
+ createMockRenderPassEncoder,
4715
+ createMockRenderPipeline,
3942
4716
  createMockRenderer,
3943
4717
  createMockRenderingContext,
4718
+ createMockSampler,
3944
4719
  createMockScoreboard,
3945
4720
  createMockServer,
3946
4721
  createMockServerClient,
@@ -3950,9 +4725,12 @@ export {
3950
4725
  createMockServerState,
3951
4726
  createMockServerStatic,
3952
4727
  createMockSessionStorage,
4728
+ createMockShaderModule,
3953
4729
  createMockSkyboxPipeline,
3954
4730
  createMockSnapshot,
3955
4731
  createMockSpritePipeline,
4732
+ createMockTexture,
4733
+ createMockTextureView,
3956
4734
  createMockTransport,
3957
4735
  createMockUDPSocket,
3958
4736
  createMockUserInfo,
@@ -3960,6 +4738,7 @@ export {
3960
4738
  createMockWeapon,
3961
4739
  createMockWeaponItem,
3962
4740
  createMockWebGL2Context,
4741
+ createMockWebGPUContext,
3963
4742
  createMockWheelEvent,
3964
4743
  createMonsterEntityFactory,
3965
4744
  createMultiplayerTestScenario,
@@ -3970,7 +4749,9 @@ export {
3970
4749
  createPlayerEntityFactory,
3971
4750
  createPlayerStateFactory,
3972
4751
  createPlaywrightTestClient,
4752
+ createPredictionTestScenario,
3973
4753
  createProjectileEntityFactory,
4754
+ createRenderTestSetup,
3974
4755
  createServerSnapshot,
3975
4756
  createSpawnTestContext,
3976
4757
  createStorageTestScenario,
@@ -3982,6 +4763,7 @@ export {
3982
4763
  createVector3,
3983
4764
  createViewTestScenario,
3984
4765
  createVisualTestScenario,
4766
+ initHeadlessWebGPU,
3985
4767
  intersects,
3986
4768
  ladderTrace,
3987
4769
  makeAxisBrush,
@@ -3994,6 +4776,8 @@ export {
3994
4776
  measureSnapshotSize,
3995
4777
  mockMonsterAttacks,
3996
4778
  randomVector3,
4779
+ renderAndCapture,
4780
+ runComputeAndReadback,
3997
4781
  serializeUserInfo,
3998
4782
  setupBrowserEnvironment,
3999
4783
  setupMockAudioContext,
@@ -4001,6 +4785,8 @@ export {
4001
4785
  setupWebGPUMocks,
4002
4786
  simulateBandwidthLimit,
4003
4787
  simulateCameraMovement,
4788
+ simulateClientPrediction,
4789
+ simulateDownload,
4004
4790
  simulateFrames,
4005
4791
  simulateGravity,
4006
4792
  simulateHandshake,
@@ -4021,7 +4807,10 @@ export {
4021
4807
  teardownBrowserEnvironment,
4022
4808
  teardownMockAudioContext,
4023
4809
  teardownNodeEnvironment,
4810
+ testComputeShader,
4811
+ testPipelineRendering,
4024
4812
  throttleBandwidth,
4813
+ verifySmoothing,
4025
4814
  verifySnapshotConsistency,
4026
4815
  waitForGameReady
4027
4816
  };