@quake2ts/test-utils 0.0.869 → 0.0.874

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.
package/dist/index.js CHANGED
@@ -1,11 +1,4 @@
1
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
- }) : x)(function(x) {
4
- if (typeof require !== "undefined") return require.apply(this, arguments);
5
- throw Error('Dynamic require of "' + x + '" is not supported');
6
- });
7
-
8
- // ../../node_modules/.pnpm/tsup@8.5.1_tsx@4.21.0_typescript@5.9.3/node_modules/tsup/assets/esm_shims.js
1
+ // ../../node_modules/.pnpm/tsup@8.5.1_postcss@8.5.6_tsx@4.21.0_typescript@5.9.3/node_modules/tsup/assets/esm_shims.js
9
2
  import path from "path";
10
3
  import { fileURLToPath } from "url";
11
4
  var getFilename = () => fileURLToPath(import.meta.url);
@@ -475,6 +468,127 @@ function createMockPlayerState(overrides) {
475
468
  };
476
469
  }
477
470
 
471
+ // src/shared/md2.ts
472
+ function createSimpleMd2Model() {
473
+ const scale = { x: 1, y: 1, z: 1 };
474
+ const translate = { x: 0, y: 0, z: 0 };
475
+ const basePositions = [
476
+ { x: -10, y: -10, z: -10 },
477
+ // 0
478
+ { x: 10, y: -10, z: -10 },
479
+ // 1
480
+ { x: 10, y: 10, z: -10 },
481
+ // 2
482
+ { x: -10, y: 10, z: -10 },
483
+ // 3
484
+ { x: -10, y: -10, z: 10 },
485
+ // 4
486
+ { x: 10, y: -10, z: 10 },
487
+ // 5
488
+ { x: 10, y: 10, z: 10 },
489
+ // 6
490
+ { x: -10, y: 10, z: 10 }
491
+ // 7
492
+ ];
493
+ const createFrame = (name, offset) => {
494
+ const vertices = basePositions.map((pos, index) => {
495
+ const modPos = {
496
+ x: pos.x + (index % 2 === 0 ? offset : -offset),
497
+ y: pos.y,
498
+ z: pos.z
499
+ };
500
+ return {
501
+ position: modPos,
502
+ normalIndex: 0,
503
+ // Dummy normal index
504
+ normal: { x: 0, y: 0, z: 1 }
505
+ // Dummy normal
506
+ };
507
+ });
508
+ return {
509
+ name,
510
+ vertices,
511
+ minBounds: { x: -20, y: -20, z: -20 },
512
+ maxBounds: { x: 20, y: 20, z: 20 }
513
+ };
514
+ };
515
+ const frames = [];
516
+ for (let i = 0; i < 20; i++) {
517
+ frames.push(createFrame(`frame${i}`, i * 0.5));
518
+ }
519
+ const triangles = [
520
+ // Front
521
+ { vertexIndices: [0, 1, 2], texCoordIndices: [0, 1, 2] },
522
+ { vertexIndices: [0, 2, 3], texCoordIndices: [0, 2, 3] },
523
+ // Back
524
+ { vertexIndices: [5, 4, 7], texCoordIndices: [1, 0, 3] },
525
+ { vertexIndices: [5, 7, 6], texCoordIndices: [1, 3, 2] },
526
+ // Top
527
+ { vertexIndices: [3, 2, 6], texCoordIndices: [0, 1, 2] },
528
+ { vertexIndices: [3, 6, 7], texCoordIndices: [0, 2, 3] },
529
+ // Bottom
530
+ { vertexIndices: [4, 5, 1], texCoordIndices: [0, 1, 2] },
531
+ { vertexIndices: [4, 1, 0], texCoordIndices: [0, 2, 3] },
532
+ // Right
533
+ { vertexIndices: [1, 5, 6], texCoordIndices: [0, 1, 2] },
534
+ { vertexIndices: [1, 6, 2], texCoordIndices: [0, 2, 3] },
535
+ // Left
536
+ { vertexIndices: [4, 0, 3], texCoordIndices: [0, 1, 2] },
537
+ { vertexIndices: [4, 3, 7], texCoordIndices: [0, 2, 3] }
538
+ ];
539
+ const glCommands = triangles.map((t) => ({
540
+ mode: "strip",
541
+ // or 'fan', doesn't matter for 3 verts
542
+ vertices: [
543
+ { s: 0, t: 0, vertexIndex: t.vertexIndices[0] },
544
+ { s: 1, t: 0, vertexIndex: t.vertexIndices[1] },
545
+ { s: 1, t: 1, vertexIndex: t.vertexIndices[2] }
546
+ ]
547
+ }));
548
+ const header = {
549
+ ident: 844121161,
550
+ version: 8,
551
+ skinWidth: 32,
552
+ skinHeight: 32,
553
+ frameSize: 40 + 8 * 4,
554
+ // header + verts * 4
555
+ numSkins: 1,
556
+ numVertices: 8,
557
+ numTexCoords: 4,
558
+ // Simplified
559
+ numTriangles: 12,
560
+ numGlCommands: 12,
561
+ // One per triangle for simplicity
562
+ numFrames: 20,
563
+ offsetSkins: 0,
564
+ offsetTexCoords: 0,
565
+ offsetTriangles: 0,
566
+ offsetFrames: 0,
567
+ offsetGlCommands: 0,
568
+ offsetEnd: 0,
569
+ magic: 844121161
570
+ };
571
+ return {
572
+ header,
573
+ skins: [{ name: "skin.pcx" }],
574
+ texCoords: [
575
+ { s: 0, t: 0 },
576
+ { s: 32, t: 0 },
577
+ { s: 32, t: 32 },
578
+ { s: 0, t: 32 }
579
+ ],
580
+ triangles,
581
+ frames,
582
+ glCommands
583
+ };
584
+ }
585
+ async function loadMd2Model(filename) {
586
+ if (filename === "simple-cube.md2") {
587
+ return createSimpleMd2Model();
588
+ }
589
+ throw new Error(`Model ${filename} not found in test fixtures`);
590
+ }
591
+
478
592
  // src/game/factories.ts
479
593
  import {
480
594
  Entity,
@@ -1413,20 +1527,20 @@ function createMockPowerupItem(id, duration, overrides = {}) {
1413
1527
  // src/server/mocks/transport.ts
1414
1528
  import { vi as vi6 } from "vitest";
1415
1529
  var MockTransport = class {
1416
- constructor() {
1417
- this.address = "127.0.0.1";
1418
- this.port = 27910;
1419
- this.sentMessages = [];
1420
- this.receivedMessages = [];
1530
+ onConnectionCallback;
1531
+ onErrorCallback;
1532
+ address = "127.0.0.1";
1533
+ port = 27910;
1534
+ sentMessages = [];
1535
+ receivedMessages = [];
1536
+ listening = false;
1537
+ listenSpy = legacyFn(async (port) => {
1538
+ this.port = port;
1539
+ this.listening = true;
1540
+ });
1541
+ closeSpy = legacyFn(() => {
1421
1542
  this.listening = false;
1422
- this.listenSpy = legacyFn(async (port) => {
1423
- this.port = port;
1424
- this.listening = true;
1425
- });
1426
- this.closeSpy = legacyFn(() => {
1427
- this.listening = false;
1428
- });
1429
- }
1543
+ });
1430
1544
  /**
1431
1545
  * Start listening on the specified port.
1432
1546
  */
@@ -1514,9 +1628,10 @@ function createMockNetDriver(overrides) {
1514
1628
  // src/server/mockTransport.ts
1515
1629
  import { NetChan } from "@quake2ts/shared";
1516
1630
  var MockNetworkTransport = class {
1631
+ netchan;
1632
+ recordedPackets = [];
1633
+ sentPackets = [];
1517
1634
  constructor() {
1518
- this.recordedPackets = [];
1519
- this.sentPackets = [];
1520
1635
  this.netchan = new NetChan();
1521
1636
  this.netchan.setup(1234, { type: "loopback", port: 0 });
1522
1637
  }
@@ -1552,25 +1667,23 @@ var MockNetworkTransport = class {
1552
1667
 
1553
1668
  // src/server/mockNetDriver.ts
1554
1669
  var MockNetDriver = class {
1555
- constructor() {
1556
- this.state = {
1557
- connected: false,
1558
- messagesSent: [],
1559
- messageHandlers: [],
1560
- closeHandlers: [],
1561
- errorHandlers: []
1562
- };
1563
- this.connectSpy = legacyFn(async (url) => {
1564
- this.state.connected = true;
1565
- });
1566
- this.disconnectSpy = legacyFn(() => {
1567
- this.state.connected = false;
1568
- this.state.closeHandlers.forEach((h) => h());
1569
- });
1570
- this.sendSpy = legacyFn((data) => {
1571
- this.state.messagesSent.push(new Uint8Array(data));
1572
- });
1573
- }
1670
+ state = {
1671
+ connected: false,
1672
+ messagesSent: [],
1673
+ messageHandlers: [],
1674
+ closeHandlers: [],
1675
+ errorHandlers: []
1676
+ };
1677
+ connectSpy = legacyFn(async (url) => {
1678
+ this.state.connected = true;
1679
+ });
1680
+ disconnectSpy = legacyFn(() => {
1681
+ this.state.connected = false;
1682
+ this.state.closeHandlers.forEach((h) => h());
1683
+ });
1684
+ sendSpy = legacyFn((data) => {
1685
+ this.state.messagesSent.push(new Uint8Array(data));
1686
+ });
1574
1687
  connect(url) {
1575
1688
  return this.connectSpy(url);
1576
1689
  }
@@ -2274,6 +2387,7 @@ function createMockWheelEvent(deltaX = 0, deltaY = 0) {
2274
2387
  });
2275
2388
  }
2276
2389
  var MockPointerLock = class {
2390
+ _doc;
2277
2391
  constructor(doc = document) {
2278
2392
  this._doc = doc;
2279
2393
  this.setup();
@@ -2410,196 +2524,66 @@ function createInputInjector(target) {
2410
2524
  // src/engine/mocks/webgl.ts
2411
2525
  import { vi as vi10 } from "vitest";
2412
2526
  var MockWebGL2RenderingContext = class {
2527
+ ARRAY_BUFFER = 34962;
2528
+ ELEMENT_ARRAY_BUFFER = 34963;
2529
+ STATIC_DRAW = 35044;
2530
+ DYNAMIC_DRAW = 35048;
2531
+ FLOAT = 5126;
2532
+ UNSIGNED_SHORT = 5123;
2533
+ TEXTURE_2D = 3553;
2534
+ TEXTURE_CUBE_MAP = 34067;
2535
+ TEXTURE_CUBE_MAP_POSITIVE_X = 34069;
2536
+ TEXTURE0 = 33984;
2537
+ TEXTURE_WRAP_S = 10242;
2538
+ TEXTURE_WRAP_T = 10243;
2539
+ TEXTURE_MIN_FILTER = 10241;
2540
+ TEXTURE_MAG_FILTER = 10240;
2541
+ LINEAR = 9729;
2542
+ NEAREST = 9728;
2543
+ CLAMP_TO_EDGE = 33071;
2544
+ RGBA = 6408;
2545
+ UNSIGNED_BYTE = 5121;
2546
+ FRAMEBUFFER = 36160;
2547
+ COLOR_ATTACHMENT0 = 36064;
2548
+ DEPTH_ATTACHMENT = 36096;
2549
+ RENDERBUFFER = 36161;
2550
+ DEPTH_COMPONENT24 = 33190;
2551
+ FRAMEBUFFER_COMPLETE = 36053;
2552
+ TRIANGLES = 4;
2553
+ DEPTH_TEST = 2929;
2554
+ CULL_FACE = 2884;
2555
+ BLEND = 3042;
2556
+ SRC_ALPHA = 770;
2557
+ ONE_MINUS_SRC_ALPHA = 771;
2558
+ ONE = 1;
2559
+ BACK = 1029;
2560
+ LEQUAL = 515;
2561
+ VERTEX_SHADER = 35633;
2562
+ FRAGMENT_SHADER = 35632;
2563
+ COMPILE_STATUS = 35713;
2564
+ LINK_STATUS = 35714;
2565
+ ONE_MINUS_SRC_COLOR = 769;
2566
+ TRIANGLE_STRIP = 5;
2567
+ QUERY_RESULT_AVAILABLE = 34919;
2568
+ QUERY_RESULT = 34918;
2569
+ // Constants commonly used in setup/webgl.ts
2570
+ TRIANGLE_FAN = 6;
2571
+ COLOR_BUFFER_BIT = 16384;
2572
+ DEPTH_BUFFER_BIT = 256;
2573
+ canvas;
2574
+ drawingBufferWidth;
2575
+ drawingBufferHeight;
2576
+ shaderCounter = 0;
2577
+ programCounter = 0;
2578
+ compileSucceeds = true;
2579
+ linkSucceeds = true;
2580
+ shaderInfoLog = "shader failed";
2581
+ programInfoLog = "program failed";
2582
+ extensions = /* @__PURE__ */ new Map();
2583
+ calls = [];
2584
+ uniformLocations = /* @__PURE__ */ new Map();
2585
+ attributeLocations = /* @__PURE__ */ new Map();
2413
2586
  constructor(canvas) {
2414
- this.ARRAY_BUFFER = 34962;
2415
- this.ELEMENT_ARRAY_BUFFER = 34963;
2416
- this.STATIC_DRAW = 35044;
2417
- this.DYNAMIC_DRAW = 35048;
2418
- this.FLOAT = 5126;
2419
- this.UNSIGNED_SHORT = 5123;
2420
- this.TEXTURE_2D = 3553;
2421
- this.TEXTURE_CUBE_MAP = 34067;
2422
- this.TEXTURE_CUBE_MAP_POSITIVE_X = 34069;
2423
- this.TEXTURE0 = 33984;
2424
- this.TEXTURE_WRAP_S = 10242;
2425
- this.TEXTURE_WRAP_T = 10243;
2426
- this.TEXTURE_MIN_FILTER = 10241;
2427
- this.TEXTURE_MAG_FILTER = 10240;
2428
- this.LINEAR = 9729;
2429
- this.NEAREST = 9728;
2430
- this.CLAMP_TO_EDGE = 33071;
2431
- this.RGBA = 6408;
2432
- this.UNSIGNED_BYTE = 5121;
2433
- this.FRAMEBUFFER = 36160;
2434
- this.COLOR_ATTACHMENT0 = 36064;
2435
- this.DEPTH_ATTACHMENT = 36096;
2436
- this.RENDERBUFFER = 36161;
2437
- this.DEPTH_COMPONENT24 = 33190;
2438
- this.FRAMEBUFFER_COMPLETE = 36053;
2439
- this.TRIANGLES = 4;
2440
- this.DEPTH_TEST = 2929;
2441
- this.CULL_FACE = 2884;
2442
- this.BLEND = 3042;
2443
- this.SRC_ALPHA = 770;
2444
- this.ONE_MINUS_SRC_ALPHA = 771;
2445
- this.ONE = 1;
2446
- this.BACK = 1029;
2447
- this.LEQUAL = 515;
2448
- this.VERTEX_SHADER = 35633;
2449
- this.FRAGMENT_SHADER = 35632;
2450
- this.COMPILE_STATUS = 35713;
2451
- this.LINK_STATUS = 35714;
2452
- this.ONE_MINUS_SRC_COLOR = 769;
2453
- this.TRIANGLE_STRIP = 5;
2454
- this.QUERY_RESULT_AVAILABLE = 34919;
2455
- this.QUERY_RESULT = 34918;
2456
- // Constants commonly used in setup/webgl.ts
2457
- this.TRIANGLE_FAN = 6;
2458
- this.COLOR_BUFFER_BIT = 16384;
2459
- this.DEPTH_BUFFER_BIT = 256;
2460
- this.shaderCounter = 0;
2461
- this.programCounter = 0;
2462
- this.compileSucceeds = true;
2463
- this.linkSucceeds = true;
2464
- this.shaderInfoLog = "shader failed";
2465
- this.programInfoLog = "program failed";
2466
- this.extensions = /* @__PURE__ */ new Map();
2467
- this.calls = [];
2468
- this.uniformLocations = /* @__PURE__ */ new Map();
2469
- this.attributeLocations = /* @__PURE__ */ new Map();
2470
- this.enable = vi10.fn((cap) => this.calls.push(`enable:${cap}`));
2471
- this.disable = vi10.fn((cap) => this.calls.push(`disable:${cap}`));
2472
- this.depthFunc = vi10.fn((func) => this.calls.push(`depthFunc:${func}`));
2473
- this.cullFace = vi10.fn((mode) => this.calls.push(`cullFace:${mode}`));
2474
- this.depthMask = vi10.fn((flag) => this.calls.push(`depthMask:${flag}`));
2475
- this.blendFuncSeparate = vi10.fn(
2476
- (srcRGB, dstRGB, srcAlpha, dstAlpha) => this.calls.push(`blendFuncSeparate:${srcRGB}:${dstRGB}:${srcAlpha}:${dstAlpha}`)
2477
- );
2478
- this.blendFunc = vi10.fn((sfactor, dfactor) => this.calls.push(`blendFunc:${sfactor}:${dfactor}`));
2479
- this.getExtension = vi10.fn((name) => this.extensions.get(name) ?? null);
2480
- this.viewport = vi10.fn((x, y, w, h) => this.calls.push(`viewport:${x}:${y}:${w}:${h}`));
2481
- this.clear = vi10.fn((mask) => this.calls.push(`clear:${mask}`));
2482
- this.clearColor = vi10.fn((r, g, b, a) => this.calls.push(`clearColor:${r}:${g}:${b}:${a}`));
2483
- this.createShader = vi10.fn((type) => ({ id: ++this.shaderCounter, type }));
2484
- this.shaderSource = vi10.fn((shader, source) => this.calls.push(`shaderSource:${shader.id}:${source}`));
2485
- this.compileShader = vi10.fn((shader) => this.calls.push(`compileShader:${shader.id}`));
2486
- this.getShaderParameter = vi10.fn(
2487
- (shader, pname) => pname === this.COMPILE_STATUS ? this.compileSucceeds : null
2488
- );
2489
- this.getShaderInfoLog = vi10.fn(() => this.compileSucceeds ? "" : this.shaderInfoLog);
2490
- this.deleteShader = vi10.fn((shader) => this.calls.push(`deleteShader:${shader.id}`));
2491
- this.createProgram = vi10.fn(() => ({ id: ++this.programCounter }));
2492
- this.attachShader = vi10.fn(
2493
- (program, shader) => this.calls.push(`attach:${program.id}:${shader.id}`)
2494
- );
2495
- this.bindAttribLocation = vi10.fn(
2496
- (program, index, name) => this.calls.push(`bindAttribLocation:${program.id}:${index}:${name}`)
2497
- );
2498
- this.linkProgram = vi10.fn((program) => this.calls.push(`link:${program.id}`));
2499
- this.getProgramParameter = vi10.fn(
2500
- (program, pname) => pname === this.LINK_STATUS ? this.linkSucceeds : null
2501
- );
2502
- this.getProgramInfoLog = vi10.fn(() => this.linkSucceeds ? "" : this.programInfoLog);
2503
- this.deleteProgram = vi10.fn((program) => this.calls.push(`deleteProgram:${program.id}`));
2504
- this.useProgram = vi10.fn((program) => this.calls.push(`useProgram:${program?.id ?? "null"}`));
2505
- this.getUniformLocation = vi10.fn((program, name) => {
2506
- this.calls.push(`getUniformLocation:${program.id}:${name}`);
2507
- return this.uniformLocations.get(name) ?? null;
2508
- });
2509
- this.getAttribLocation = vi10.fn((program, name) => {
2510
- this.calls.push(`getAttribLocation:${program.id}:${name}`);
2511
- return this.attributeLocations.get(name) ?? -1;
2512
- });
2513
- this.createBuffer = vi10.fn(() => ({ buffer: {} }));
2514
- this.bindBuffer = vi10.fn((target, buffer) => this.calls.push(`bindBuffer:${target}:${!!buffer}`));
2515
- this.bufferData = vi10.fn(
2516
- (target, data, usage) => this.calls.push(`bufferData:${target}:${usage}:${typeof data === "number" ? data : "data"}`)
2517
- );
2518
- this.bufferSubData = vi10.fn(
2519
- (target, offset, data) => this.calls.push(`bufferSubData:${target}:${offset}:${data.byteLength ?? "len"}`)
2520
- );
2521
- this.deleteBuffer = vi10.fn((buffer) => this.calls.push(`deleteBuffer:${!!buffer}`));
2522
- this.createVertexArray = vi10.fn(() => ({ vao: {} }));
2523
- this.bindVertexArray = vi10.fn((vao) => this.calls.push(`bindVertexArray:${!!vao}`));
2524
- this.enableVertexAttribArray = vi10.fn((index) => this.calls.push(`enableAttrib:${index}`));
2525
- this.vertexAttribPointer = vi10.fn(
2526
- (index, size, type, normalized, stride, offset) => this.calls.push(`vertexAttribPointer:${index}:${size}:${type}:${normalized}:${stride}:${offset}`)
2527
- );
2528
- this.vertexAttribDivisor = vi10.fn((index, divisor) => this.calls.push(`divisor:${index}:${divisor}`));
2529
- this.deleteVertexArray = vi10.fn((vao) => this.calls.push(`deleteVertexArray:${!!vao}`));
2530
- this.createTexture = vi10.fn(() => ({ texture: {} }));
2531
- this.activeTexture = vi10.fn((unit) => this.calls.push(`activeTexture:${unit}`));
2532
- this.bindTexture = vi10.fn((target, texture) => this.calls.push(`bindTexture:${target}:${!!texture}`));
2533
- this.texParameteri = vi10.fn(
2534
- (target, pname, param) => this.calls.push(`texParameteri:${target}:${pname}:${param}`)
2535
- );
2536
- this.texImage2D = vi10.fn(
2537
- (target, level, internalFormat, width, height, border, format, type, pixels) => this.calls.push(
2538
- `texImage2D:${target}:${level}:${internalFormat}:${width}:${height}:${border}:${format}:${type}:${pixels ? "data" : "null"}`
2539
- )
2540
- );
2541
- // Explicitly typing this one with legacyFn or manually typing it to avoid inference errors
2542
- this.texImage3D = legacyFn();
2543
- this.deleteTexture = vi10.fn((texture) => this.calls.push(`deleteTexture:${!!texture}`));
2544
- this.createFramebuffer = vi10.fn(() => ({ fb: {} }));
2545
- this.bindFramebuffer = vi10.fn(
2546
- (target, framebuffer) => this.calls.push(`bindFramebuffer:${target}:${!!framebuffer}`)
2547
- );
2548
- this.framebufferTexture2D = vi10.fn(
2549
- (target, attachment, textarget, texture, level) => this.calls.push(`framebufferTexture2D:${target}:${attachment}:${textarget}:${!!texture}:${level}`)
2550
- );
2551
- this.deleteFramebuffer = vi10.fn((fb) => this.calls.push(`deleteFramebuffer:${!!fb}`));
2552
- this.checkFramebufferStatus = vi10.fn((target) => this.FRAMEBUFFER_COMPLETE);
2553
- this.createRenderbuffer = vi10.fn(() => ({ rb: {} }));
2554
- this.bindRenderbuffer = vi10.fn(
2555
- (target, renderbuffer) => this.calls.push(`bindRenderbuffer:${target}:${!!renderbuffer}`)
2556
- );
2557
- this.renderbufferStorage = vi10.fn(
2558
- (target, internalformat, width, height) => this.calls.push(`renderbufferStorage:${target}:${internalformat}:${width}:${height}`)
2559
- );
2560
- this.framebufferRenderbuffer = vi10.fn(
2561
- (target, attachment, renderbuffertarget, renderbuffer) => this.calls.push(`framebufferRenderbuffer:${target}:${attachment}:${renderbuffertarget}:${!!renderbuffer}`)
2562
- );
2563
- this.deleteRenderbuffer = vi10.fn((rb) => this.calls.push(`deleteRenderbuffer:${!!rb}`));
2564
- this.drawArrays = vi10.fn(
2565
- (mode, first, count) => this.calls.push(`drawArrays:${mode}:${first}:${count}`)
2566
- );
2567
- this.drawElements = vi10.fn(
2568
- (mode, count, type, offset) => this.calls.push(`drawElements:${mode}:${count}:${type}:${offset}`)
2569
- );
2570
- // Queries
2571
- this.createQuery = vi10.fn(() => ({}));
2572
- this.beginQuery = legacyFn();
2573
- this.endQuery = legacyFn();
2574
- this.deleteQuery = legacyFn();
2575
- this.getQueryParameter = legacyFn();
2576
- this.getParameter = legacyFn();
2577
- this.uniform1f = vi10.fn(
2578
- (location, x) => this.calls.push(`uniform1f:${location ? "set" : "null"}:${x}`)
2579
- );
2580
- this.uniform1i = vi10.fn(
2581
- (location, x) => this.calls.push(`uniform1i:${location ? "set" : "null"}:${x}`)
2582
- );
2583
- this.uniform4f = vi10.fn(
2584
- (location, x, y, z, w) => this.calls.push(`uniform4f:${location ? "set" : "null"}:${x}:${y}:${z}:${w}`)
2585
- );
2586
- this.uniform3fv = vi10.fn(
2587
- (location, data) => this.calls.push(`uniform3fv:${location ? "set" : "null"}:${Array.from(data).join(",")}`)
2588
- );
2589
- this.uniform3f = vi10.fn(
2590
- (location, x, y, z) => this.calls.push(`uniform3f:${location ? "set" : "null"}:${x}:${y}:${z}`)
2591
- );
2592
- this.uniform2f = vi10.fn(
2593
- (location, x, y) => this.calls.push(`uniform2f:${location ? "set" : "null"}:${x}:${y}`)
2594
- );
2595
- this.uniform4fv = vi10.fn(
2596
- (location, data) => this.calls.push(`uniform4fv:${location ? "set" : "null"}:${Array.from(data).join(",")}`)
2597
- );
2598
- this.uniformMatrix4fv = vi10.fn(
2599
- (location, transpose, data) => this.calls.push(`uniformMatrix4fv:${location ? "set" : "null"}:${transpose}:${Array.from(data).join(",")}`)
2600
- );
2601
- this.uniformBlockBinding = legacyFn();
2602
- this.isContextLost = vi10.fn(() => false);
2603
2587
  if (canvas) {
2604
2588
  this.canvas = canvas;
2605
2589
  this.drawingBufferWidth = canvas.width;
@@ -2610,6 +2594,139 @@ var MockWebGL2RenderingContext = class {
2610
2594
  this.drawingBufferHeight = 600;
2611
2595
  }
2612
2596
  }
2597
+ enable = vi10.fn((cap) => this.calls.push(`enable:${cap}`));
2598
+ disable = vi10.fn((cap) => this.calls.push(`disable:${cap}`));
2599
+ depthFunc = vi10.fn((func) => this.calls.push(`depthFunc:${func}`));
2600
+ cullFace = vi10.fn((mode) => this.calls.push(`cullFace:${mode}`));
2601
+ depthMask = vi10.fn((flag) => this.calls.push(`depthMask:${flag}`));
2602
+ blendFuncSeparate = vi10.fn(
2603
+ (srcRGB, dstRGB, srcAlpha, dstAlpha) => this.calls.push(`blendFuncSeparate:${srcRGB}:${dstRGB}:${srcAlpha}:${dstAlpha}`)
2604
+ );
2605
+ blendFunc = vi10.fn((sfactor, dfactor) => this.calls.push(`blendFunc:${sfactor}:${dfactor}`));
2606
+ getExtension = vi10.fn((name) => this.extensions.get(name) ?? null);
2607
+ viewport = vi10.fn((x, y, w, h) => this.calls.push(`viewport:${x}:${y}:${w}:${h}`));
2608
+ clear = vi10.fn((mask) => this.calls.push(`clear:${mask}`));
2609
+ clearColor = vi10.fn((r, g, b, a) => this.calls.push(`clearColor:${r}:${g}:${b}:${a}`));
2610
+ createShader = vi10.fn((type) => ({ id: ++this.shaderCounter, type }));
2611
+ shaderSource = vi10.fn((shader, source) => this.calls.push(`shaderSource:${shader.id}:${source}`));
2612
+ compileShader = vi10.fn((shader) => this.calls.push(`compileShader:${shader.id}`));
2613
+ getShaderParameter = vi10.fn(
2614
+ (shader, pname) => pname === this.COMPILE_STATUS ? this.compileSucceeds : null
2615
+ );
2616
+ getShaderInfoLog = vi10.fn(() => this.compileSucceeds ? "" : this.shaderInfoLog);
2617
+ deleteShader = vi10.fn((shader) => this.calls.push(`deleteShader:${shader.id}`));
2618
+ createProgram = vi10.fn(() => ({ id: ++this.programCounter }));
2619
+ attachShader = vi10.fn(
2620
+ (program, shader) => this.calls.push(`attach:${program.id}:${shader.id}`)
2621
+ );
2622
+ bindAttribLocation = vi10.fn(
2623
+ (program, index, name) => this.calls.push(`bindAttribLocation:${program.id}:${index}:${name}`)
2624
+ );
2625
+ linkProgram = vi10.fn((program) => this.calls.push(`link:${program.id}`));
2626
+ getProgramParameter = vi10.fn(
2627
+ (program, pname) => pname === this.LINK_STATUS ? this.linkSucceeds : null
2628
+ );
2629
+ getProgramInfoLog = vi10.fn(() => this.linkSucceeds ? "" : this.programInfoLog);
2630
+ deleteProgram = vi10.fn((program) => this.calls.push(`deleteProgram:${program.id}`));
2631
+ useProgram = vi10.fn((program) => this.calls.push(`useProgram:${program?.id ?? "null"}`));
2632
+ getUniformLocation = vi10.fn((program, name) => {
2633
+ this.calls.push(`getUniformLocation:${program.id}:${name}`);
2634
+ return this.uniformLocations.get(name) ?? null;
2635
+ });
2636
+ getAttribLocation = vi10.fn((program, name) => {
2637
+ this.calls.push(`getAttribLocation:${program.id}:${name}`);
2638
+ return this.attributeLocations.get(name) ?? -1;
2639
+ });
2640
+ createBuffer = vi10.fn(() => ({ buffer: {} }));
2641
+ bindBuffer = vi10.fn((target, buffer) => this.calls.push(`bindBuffer:${target}:${!!buffer}`));
2642
+ bufferData = vi10.fn(
2643
+ (target, data, usage) => this.calls.push(`bufferData:${target}:${usage}:${typeof data === "number" ? data : "data"}`)
2644
+ );
2645
+ bufferSubData = vi10.fn(
2646
+ (target, offset, data) => this.calls.push(`bufferSubData:${target}:${offset}:${data.byteLength ?? "len"}`)
2647
+ );
2648
+ deleteBuffer = vi10.fn((buffer) => this.calls.push(`deleteBuffer:${!!buffer}`));
2649
+ createVertexArray = vi10.fn(() => ({ vao: {} }));
2650
+ bindVertexArray = vi10.fn((vao) => this.calls.push(`bindVertexArray:${!!vao}`));
2651
+ enableVertexAttribArray = vi10.fn((index) => this.calls.push(`enableAttrib:${index}`));
2652
+ vertexAttribPointer = vi10.fn(
2653
+ (index, size, type, normalized, stride, offset) => this.calls.push(`vertexAttribPointer:${index}:${size}:${type}:${normalized}:${stride}:${offset}`)
2654
+ );
2655
+ vertexAttribDivisor = vi10.fn((index, divisor) => this.calls.push(`divisor:${index}:${divisor}`));
2656
+ deleteVertexArray = vi10.fn((vao) => this.calls.push(`deleteVertexArray:${!!vao}`));
2657
+ createTexture = vi10.fn(() => ({ texture: {} }));
2658
+ activeTexture = vi10.fn((unit) => this.calls.push(`activeTexture:${unit}`));
2659
+ bindTexture = vi10.fn((target, texture) => this.calls.push(`bindTexture:${target}:${!!texture}`));
2660
+ texParameteri = vi10.fn(
2661
+ (target, pname, param) => this.calls.push(`texParameteri:${target}:${pname}:${param}`)
2662
+ );
2663
+ texImage2D = vi10.fn(
2664
+ (target, level, internalFormat, width, height, border, format, type, pixels) => this.calls.push(
2665
+ `texImage2D:${target}:${level}:${internalFormat}:${width}:${height}:${border}:${format}:${type}:${pixels ? "data" : "null"}`
2666
+ )
2667
+ );
2668
+ // Explicitly typing this one with legacyFn or manually typing it to avoid inference errors
2669
+ texImage3D = legacyFn();
2670
+ deleteTexture = vi10.fn((texture) => this.calls.push(`deleteTexture:${!!texture}`));
2671
+ createFramebuffer = vi10.fn(() => ({ fb: {} }));
2672
+ bindFramebuffer = vi10.fn(
2673
+ (target, framebuffer) => this.calls.push(`bindFramebuffer:${target}:${!!framebuffer}`)
2674
+ );
2675
+ framebufferTexture2D = vi10.fn(
2676
+ (target, attachment, textarget, texture, level) => this.calls.push(`framebufferTexture2D:${target}:${attachment}:${textarget}:${!!texture}:${level}`)
2677
+ );
2678
+ deleteFramebuffer = vi10.fn((fb) => this.calls.push(`deleteFramebuffer:${!!fb}`));
2679
+ checkFramebufferStatus = vi10.fn((target) => this.FRAMEBUFFER_COMPLETE);
2680
+ createRenderbuffer = vi10.fn(() => ({ rb: {} }));
2681
+ bindRenderbuffer = vi10.fn(
2682
+ (target, renderbuffer) => this.calls.push(`bindRenderbuffer:${target}:${!!renderbuffer}`)
2683
+ );
2684
+ renderbufferStorage = vi10.fn(
2685
+ (target, internalformat, width, height) => this.calls.push(`renderbufferStorage:${target}:${internalformat}:${width}:${height}`)
2686
+ );
2687
+ framebufferRenderbuffer = vi10.fn(
2688
+ (target, attachment, renderbuffertarget, renderbuffer) => this.calls.push(`framebufferRenderbuffer:${target}:${attachment}:${renderbuffertarget}:${!!renderbuffer}`)
2689
+ );
2690
+ deleteRenderbuffer = vi10.fn((rb) => this.calls.push(`deleteRenderbuffer:${!!rb}`));
2691
+ drawArrays = vi10.fn(
2692
+ (mode, first, count) => this.calls.push(`drawArrays:${mode}:${first}:${count}`)
2693
+ );
2694
+ drawElements = vi10.fn(
2695
+ (mode, count, type, offset) => this.calls.push(`drawElements:${mode}:${count}:${type}:${offset}`)
2696
+ );
2697
+ // Queries
2698
+ createQuery = vi10.fn(() => ({}));
2699
+ beginQuery = legacyFn();
2700
+ endQuery = legacyFn();
2701
+ deleteQuery = legacyFn();
2702
+ getQueryParameter = legacyFn();
2703
+ getParameter = legacyFn();
2704
+ uniform1f = vi10.fn(
2705
+ (location, x) => this.calls.push(`uniform1f:${location ? "set" : "null"}:${x}`)
2706
+ );
2707
+ uniform1i = vi10.fn(
2708
+ (location, x) => this.calls.push(`uniform1i:${location ? "set" : "null"}:${x}`)
2709
+ );
2710
+ uniform4f = vi10.fn(
2711
+ (location, x, y, z, w) => this.calls.push(`uniform4f:${location ? "set" : "null"}:${x}:${y}:${z}:${w}`)
2712
+ );
2713
+ uniform3fv = vi10.fn(
2714
+ (location, data) => this.calls.push(`uniform3fv:${location ? "set" : "null"}:${Array.from(data).join(",")}`)
2715
+ );
2716
+ uniform3f = vi10.fn(
2717
+ (location, x, y, z) => this.calls.push(`uniform3f:${location ? "set" : "null"}:${x}:${y}:${z}`)
2718
+ );
2719
+ uniform2f = vi10.fn(
2720
+ (location, x, y) => this.calls.push(`uniform2f:${location ? "set" : "null"}:${x}:${y}`)
2721
+ );
2722
+ uniform4fv = vi10.fn(
2723
+ (location, data) => this.calls.push(`uniform4fv:${location ? "set" : "null"}:${Array.from(data).join(",")}`)
2724
+ );
2725
+ uniformMatrix4fv = vi10.fn(
2726
+ (location, transpose, data) => this.calls.push(`uniformMatrix4fv:${location ? "set" : "null"}:${transpose}:${Array.from(data).join(",")}`)
2727
+ );
2728
+ uniformBlockBinding = legacyFn();
2729
+ isContextLost = vi10.fn(() => false);
2613
2730
  };
2614
2731
  function createMockWebGL2Context(overridesOrCanvas) {
2615
2732
  let context;
@@ -3012,14 +3129,16 @@ function createWebGPULifecycle() {
3012
3129
  }
3013
3130
 
3014
3131
  // src/setup/headless-webgl.ts
3132
+ import { createRequire } from "module";
3015
3133
  function createHeadlessWebGL(options = {}) {
3016
3134
  const width = options.width ?? 256;
3017
3135
  const height = options.height ?? 256;
3018
3136
  let createGL;
3019
3137
  try {
3020
- createGL = __require("gl");
3138
+ const require2 = createRequire(import.meta.url);
3139
+ createGL = require2("gl");
3021
3140
  } catch (e) {
3022
- throw new Error("gl package not found or failed to load. Install it to run WebGL tests.");
3141
+ throw new Error("gl package not found or failed to load. Install it to run WebGL tests. Error: " + e);
3023
3142
  }
3024
3143
  const glContext = createGL(width, height, {
3025
3144
  antialias: options.antialias ?? false,
@@ -3376,43 +3495,35 @@ var FakeAudioParam = class {
3376
3495
  }
3377
3496
  };
3378
3497
  var FakeAudioNode = class {
3379
- constructor() {
3380
- this.connections = [];
3381
- }
3498
+ connections = [];
3382
3499
  connect(destination) {
3383
3500
  this.connections.push(destination);
3384
3501
  }
3385
3502
  };
3386
3503
  var FakeGainNode = class extends FakeAudioNode {
3387
- constructor() {
3388
- super(...arguments);
3389
- this.gain = new FakeAudioParam(1);
3390
- }
3504
+ gain = new FakeAudioParam(1);
3391
3505
  };
3392
3506
  var FakePannerNode = class extends FakeAudioNode {
3393
- constructor() {
3394
- super(...arguments);
3395
- this.positionX = new FakeAudioParam(0);
3396
- this.positionY = new FakeAudioParam(0);
3397
- this.positionZ = new FakeAudioParam(0);
3398
- }
3507
+ positionX = new FakeAudioParam(0);
3508
+ positionY = new FakeAudioParam(0);
3509
+ positionZ = new FakeAudioParam(0);
3510
+ refDistance;
3511
+ maxDistance;
3512
+ rolloffFactor;
3513
+ distanceModel;
3399
3514
  };
3400
3515
  var FakeBiquadFilterNode = class extends FakeAudioNode {
3401
- constructor() {
3402
- super(...arguments);
3403
- this.frequency = new FakeAudioParam(0);
3404
- this.Q = new FakeAudioParam(0);
3405
- this.type = "lowpass";
3406
- }
3516
+ frequency = new FakeAudioParam(0);
3517
+ Q = new FakeAudioParam(0);
3518
+ type = "lowpass";
3407
3519
  };
3408
3520
  var FakeBufferSource = class extends FakeAudioNode {
3409
- constructor() {
3410
- super(...arguments);
3411
- this.buffer = null;
3412
- this.loop = false;
3413
- this.playbackRate = new FakeAudioParam(1);
3414
- this.onended = null;
3415
- }
3521
+ buffer = null;
3522
+ loop = false;
3523
+ playbackRate = new FakeAudioParam(1);
3524
+ onended = null;
3525
+ startedAt;
3526
+ stoppedAt;
3416
3527
  start(when = 0, offset, duration) {
3417
3528
  this.startedAt = when;
3418
3529
  this.offset = offset;
@@ -3422,19 +3533,23 @@ var FakeBufferSource = class extends FakeAudioNode {
3422
3533
  this.stoppedAt = when;
3423
3534
  this.onended?.();
3424
3535
  }
3536
+ offset;
3537
+ duration;
3425
3538
  };
3426
3539
  var FakeDestination = class extends FakeAudioNode {
3427
3540
  };
3428
3541
  var FakeAudioContext = class {
3542
+ destination = new FakeDestination();
3543
+ state = "suspended";
3544
+ currentTime = 0;
3545
+ resumeCalls = 0;
3546
+ gains = [];
3547
+ sources = [];
3548
+ panners = [];
3549
+ filters = [];
3550
+ lastDecoded;
3551
+ createPanner;
3429
3552
  constructor(enablePanner = true) {
3430
- this.destination = new FakeDestination();
3431
- this.state = "suspended";
3432
- this.currentTime = 0;
3433
- this.resumeCalls = 0;
3434
- this.gains = [];
3435
- this.sources = [];
3436
- this.panners = [];
3437
- this.filters = [];
3438
3553
  if (enablePanner) {
3439
3554
  this.createPanner = () => {
3440
3555
  const node = new FakePannerNode();
@@ -4035,26 +4150,24 @@ function createStorageTestScenario(storageType = "local") {
4035
4150
  // src/setup/audio.ts
4036
4151
  function setupMockAudioContext() {
4037
4152
  class MockAudioContext {
4038
- constructor() {
4039
- this.state = "suspended";
4040
- this.destination = {};
4041
- this.currentTime = 0;
4042
- this.listener = {
4043
- positionX: { value: 0 },
4044
- positionY: { value: 0 },
4045
- positionZ: { value: 0 },
4046
- forwardX: { value: 0 },
4047
- forwardY: { value: 0 },
4048
- forwardZ: { value: 0 },
4049
- upX: { value: 0 },
4050
- upY: { value: 0 },
4051
- upZ: { value: 0 },
4052
- setOrientation: () => {
4053
- },
4054
- setPosition: () => {
4055
- }
4056
- };
4057
- }
4153
+ state = "suspended";
4154
+ destination = {};
4155
+ currentTime = 0;
4156
+ listener = {
4157
+ positionX: { value: 0 },
4158
+ positionY: { value: 0 },
4159
+ positionZ: { value: 0 },
4160
+ forwardX: { value: 0 },
4161
+ forwardY: { value: 0 },
4162
+ forwardZ: { value: 0 },
4163
+ upX: { value: 0 },
4164
+ upY: { value: 0 },
4165
+ upZ: { value: 0 },
4166
+ setOrientation: () => {
4167
+ },
4168
+ setPosition: () => {
4169
+ }
4170
+ };
4058
4171
  createGain() {
4059
4172
  return {
4060
4173
  gain: { value: 1, linearRampToValueAtTime: () => {
@@ -4677,6 +4790,7 @@ async function expectAnimationSnapshot(renderAndCaptureFrame, options) {
4677
4790
  import { createServer } from "http";
4678
4791
  import path5 from "path";
4679
4792
  import fs4 from "fs";
4793
+ var sharedSetup;
4680
4794
  function findWorkspaceRoot(startDir) {
4681
4795
  let currentDir = startDir;
4682
4796
  while (currentDir !== path5.parse(currentDir).root) {
@@ -4691,6 +4805,25 @@ async function createWebGLPlaywrightSetup(options = {}) {
4691
4805
  const width = options.width ?? 256;
4692
4806
  const height = options.height ?? 256;
4693
4807
  const headless = options.headless ?? true;
4808
+ if (sharedSetup) {
4809
+ const { page: page2, browser: browser2, context: context2, server } = sharedSetup;
4810
+ if (!page2.isClosed()) {
4811
+ await page2.setViewportSize({ width, height });
4812
+ return {
4813
+ browser: browser2,
4814
+ context: context2,
4815
+ page: page2,
4816
+ width,
4817
+ height,
4818
+ server,
4819
+ // No-op cleanup for shared instance to keep it alive for next test
4820
+ cleanup: async () => {
4821
+ }
4822
+ };
4823
+ } else {
4824
+ sharedSetup = void 0;
4825
+ }
4826
+ }
4694
4827
  let chromium;
4695
4828
  let handler;
4696
4829
  try {
@@ -4747,7 +4880,6 @@ async function createWebGLPlaywrightSetup(options = {}) {
4747
4880
  const page = await context.newPage();
4748
4881
  page.on("console", (msg) => {
4749
4882
  if (msg.type() === "error") console.error(`[Browser Error] ${msg.text()}`);
4750
- else console.log(`[Browser] ${msg.text()}`);
4751
4883
  });
4752
4884
  page.on("pageerror", (err) => {
4753
4885
  console.error(`[Browser Page Error] ${err.message}`);
@@ -4755,9 +4887,14 @@ async function createWebGLPlaywrightSetup(options = {}) {
4755
4887
  await page.goto(serverUrl, { waitUntil: "domcontentloaded" });
4756
4888
  await page.evaluate(`window.createRendererTest()`);
4757
4889
  await page.waitForFunction(() => window.testRenderer !== void 0, { timeout: 5e3 });
4890
+ sharedSetup = {
4891
+ browser,
4892
+ context,
4893
+ page,
4894
+ server: staticServer,
4895
+ serverUrl
4896
+ };
4758
4897
  const cleanup = async () => {
4759
- await browser.close();
4760
- staticServer.close();
4761
4898
  };
4762
4899
  return {
4763
4900
  browser,
@@ -4779,9 +4916,11 @@ async function renderAndCaptureWebGLPlaywright(page, renderFn, width, height, fr
4779
4916
  throw new Error("Renderer not initialized");
4780
4917
  }
4781
4918
  if (width2 !== void 0 && height2 !== void 0) {
4782
- canvas.width = width2;
4783
- canvas.height = height2;
4784
- gl.viewport(0, 0, width2, height2);
4919
+ if (canvas.width !== width2 || canvas.height !== height2) {
4920
+ canvas.width = width2;
4921
+ canvas.height = height2;
4922
+ gl.viewport(0, 0, width2, height2);
4923
+ }
4785
4924
  }
4786
4925
  try {
4787
4926
  const fn = new Function("renderer", "gl", "frameIndex", code);
@@ -5855,11 +5994,11 @@ var MAX_MODELS = 256;
5855
5994
  var MAX_SOUNDS = 256;
5856
5995
  var MAX_IMAGES = 256;
5857
5996
  var MockClientConfigStrings = class {
5997
+ strings = /* @__PURE__ */ new Map();
5998
+ models = [];
5999
+ sounds = [];
6000
+ images = [];
5858
6001
  constructor() {
5859
- this.strings = /* @__PURE__ */ new Map();
5860
- this.models = [];
5861
- this.sounds = [];
5862
- this.images = [];
5863
6002
  }
5864
6003
  set(index, value) {
5865
6004
  this.strings.set(index, value);
@@ -6509,6 +6648,7 @@ export {
6509
6648
  createRenderTestSetup,
6510
6649
  createSaveGameSnapshot,
6511
6650
  createServerSnapshot,
6651
+ createSimpleMd2Model,
6512
6652
  createSolidTexture,
6513
6653
  createSpawnRegistry,
6514
6654
  createSpawnTestContext,
@@ -6538,6 +6678,7 @@ export {
6538
6678
  intersects,
6539
6679
  ladderTrace,
6540
6680
  loadMapFromPak,
6681
+ loadMd2Model,
6541
6682
  loadPNG,
6542
6683
  makeAxisBrush,
6543
6684
  makeBrushFromMinsMaxs,