quake2ts 0.0.552 → 0.0.556

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.
@@ -1 +1 @@
1
- {"version":3,"file":"speaker.d.ts","sourceRoot":"","sources":["../../../../src/entities/target/speaker.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAiCjD,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,aAAa,QA4B5D"}
1
+ {"version":3,"file":"speaker.d.ts","sourceRoot":"","sources":["../../../../src/entities/target/speaker.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAiCjD,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,aAAa,QAiC5D"}
@@ -20,6 +20,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
+ InputInjector: () => InputInjector,
24
+ MockPointerLock: () => MockPointerLock,
23
25
  createBinaryStreamMock: () => createBinaryStreamMock,
24
26
  createBinaryWriterMock: () => createBinaryWriterMock,
25
27
  createEntity: () => createEntity,
@@ -27,6 +29,7 @@ __export(index_exports, {
27
29
  createGameStateSnapshotFactory: () => createGameStateSnapshotFactory,
28
30
  createMockEngine: () => createMockEngine,
29
31
  createMockGame: () => createMockGame,
32
+ createMockWebGL2Context: () => createMockWebGL2Context,
30
33
  createNetChanMock: () => createNetChanMock,
31
34
  createPlayerStateFactory: () => createPlayerStateFactory,
32
35
  createSpawnContext: () => createSpawnContext,
@@ -40,7 +43,10 @@ __export(index_exports, {
40
43
  makeLeafModel: () => makeLeafModel,
41
44
  makeNode: () => makeNode,
42
45
  makePlane: () => makePlane,
43
- stairTrace: () => import_shared3.stairTrace
46
+ setupBrowserEnvironment: () => setupBrowserEnvironment,
47
+ setupNodeEnvironment: () => setupNodeEnvironment,
48
+ stairTrace: () => import_shared3.stairTrace,
49
+ teardownBrowserEnvironment: () => teardownBrowserEnvironment
44
50
  });
45
51
  module.exports = __toCommonJS(index_exports);
46
52
 
@@ -433,8 +439,349 @@ function createSpawnContext() {
433
439
  function createEntity() {
434
440
  return new import_game.Entity(1);
435
441
  }
442
+
443
+ // src/setup/browser.ts
444
+ var import_jsdom = require("jsdom");
445
+ var import_canvas = require("@napi-rs/canvas");
446
+ var import_auto = require("fake-indexeddb/auto");
447
+ function setupBrowserEnvironment(options = {}) {
448
+ const { url = "http://localhost", pretendToBeVisual = true } = options;
449
+ const dom = new import_jsdom.JSDOM("<!DOCTYPE html><html><head></head><body></body></html>", {
450
+ url,
451
+ pretendToBeVisual
452
+ });
453
+ global.window = dom.window;
454
+ global.document = dom.window.document;
455
+ global.navigator = dom.window.navigator;
456
+ global.location = dom.window.location;
457
+ global.HTMLElement = dom.window.HTMLElement;
458
+ global.Event = dom.window.Event;
459
+ global.CustomEvent = dom.window.CustomEvent;
460
+ global.DragEvent = dom.window.DragEvent;
461
+ global.MouseEvent = dom.window.MouseEvent;
462
+ global.KeyboardEvent = dom.window.KeyboardEvent;
463
+ global.FocusEvent = dom.window.FocusEvent;
464
+ global.WheelEvent = dom.window.WheelEvent;
465
+ global.InputEvent = dom.window.InputEvent;
466
+ global.UIEvent = dom.window.UIEvent;
467
+ try {
468
+ global.localStorage = dom.window.localStorage;
469
+ } catch (e) {
470
+ }
471
+ if (!global.localStorage) {
472
+ const storage = /* @__PURE__ */ new Map();
473
+ global.localStorage = {
474
+ getItem: (key) => storage.get(key) || null,
475
+ setItem: (key, value) => storage.set(key, value),
476
+ removeItem: (key) => storage.delete(key),
477
+ clear: () => storage.clear(),
478
+ key: (index) => Array.from(storage.keys())[index] || null,
479
+ get length() {
480
+ return storage.size;
481
+ }
482
+ };
483
+ }
484
+ const originalCreateElement = document.createElement.bind(document);
485
+ document.createElement = function(tagName, options2) {
486
+ if (tagName.toLowerCase() === "canvas") {
487
+ const napiCanvas = new import_canvas.Canvas(300, 150);
488
+ const domCanvas = originalCreateElement("canvas", options2);
489
+ Object.defineProperty(domCanvas, "width", {
490
+ get: () => napiCanvas.width,
491
+ set: (value) => {
492
+ napiCanvas.width = value;
493
+ },
494
+ enumerable: true,
495
+ configurable: true
496
+ });
497
+ Object.defineProperty(domCanvas, "height", {
498
+ get: () => napiCanvas.height,
499
+ set: (value) => {
500
+ napiCanvas.height = value;
501
+ },
502
+ enumerable: true,
503
+ configurable: true
504
+ });
505
+ const originalGetContext = domCanvas.getContext.bind(domCanvas);
506
+ domCanvas.getContext = function(contextId, options3) {
507
+ if (contextId === "2d") {
508
+ return napiCanvas.getContext("2d", options3);
509
+ }
510
+ if (contextId === "webgl" || contextId === "webgl2") {
511
+ return originalGetContext(contextId, options3);
512
+ }
513
+ return napiCanvas.getContext(contextId, options3);
514
+ };
515
+ domCanvas.__napiCanvas = napiCanvas;
516
+ return domCanvas;
517
+ }
518
+ return originalCreateElement(tagName, options2);
519
+ };
520
+ global.Image = import_canvas.Image;
521
+ global.ImageData = import_canvas.ImageData;
522
+ if (typeof global.createImageBitmap === "undefined") {
523
+ global.createImageBitmap = async function(image, _options) {
524
+ if (image && typeof image.width === "number" && typeof image.height === "number") {
525
+ const canvas2 = new import_canvas.Canvas(image.width, image.height);
526
+ const ctx = canvas2.getContext("2d");
527
+ if (image.data) {
528
+ ctx.putImageData(image, 0, 0);
529
+ }
530
+ return canvas2;
531
+ }
532
+ const canvas = new import_canvas.Canvas(100, 100);
533
+ return canvas;
534
+ };
535
+ }
536
+ if (typeof global.btoa === "undefined") {
537
+ global.btoa = function(str) {
538
+ return Buffer.from(str, "binary").toString("base64");
539
+ };
540
+ }
541
+ if (typeof global.atob === "undefined") {
542
+ global.atob = function(str) {
543
+ return Buffer.from(str, "base64").toString("binary");
544
+ };
545
+ }
546
+ }
547
+ function teardownBrowserEnvironment() {
548
+ delete global.window;
549
+ delete global.document;
550
+ delete global.navigator;
551
+ delete global.localStorage;
552
+ delete global.location;
553
+ delete global.HTMLElement;
554
+ delete global.Image;
555
+ delete global.ImageData;
556
+ delete global.createImageBitmap;
557
+ }
558
+
559
+ // src/setup/node.ts
560
+ function setupNodeEnvironment() {
561
+ if (typeof global.fetch === "undefined") {
562
+ }
563
+ }
564
+
565
+ // src/setup/webgl.ts
566
+ function createMockWebGL2Context(canvas) {
567
+ const gl = {
568
+ canvas,
569
+ drawingBufferWidth: canvas.width,
570
+ drawingBufferHeight: canvas.height,
571
+ // Constants
572
+ VERTEX_SHADER: 35633,
573
+ FRAGMENT_SHADER: 35632,
574
+ COMPILE_STATUS: 35713,
575
+ LINK_STATUS: 35714,
576
+ ARRAY_BUFFER: 34962,
577
+ ELEMENT_ARRAY_BUFFER: 34963,
578
+ STATIC_DRAW: 35044,
579
+ DYNAMIC_DRAW: 35048,
580
+ FLOAT: 5126,
581
+ DEPTH_TEST: 2929,
582
+ BLEND: 3042,
583
+ SRC_ALPHA: 770,
584
+ ONE_MINUS_SRC_ALPHA: 771,
585
+ TEXTURE_2D: 3553,
586
+ RGBA: 6408,
587
+ UNSIGNED_BYTE: 5121,
588
+ COLOR_BUFFER_BIT: 16384,
589
+ DEPTH_BUFFER_BIT: 256,
590
+ TRIANGLES: 4,
591
+ TRIANGLE_STRIP: 5,
592
+ TRIANGLE_FAN: 6,
593
+ // Methods
594
+ createShader: () => ({}),
595
+ shaderSource: () => {
596
+ },
597
+ compileShader: () => {
598
+ },
599
+ getShaderParameter: (_, param) => {
600
+ if (param === 35713) return true;
601
+ return true;
602
+ },
603
+ getShaderInfoLog: () => "",
604
+ createProgram: () => ({}),
605
+ attachShader: () => {
606
+ },
607
+ linkProgram: () => {
608
+ },
609
+ getProgramParameter: (_, param) => {
610
+ if (param === 35714) return true;
611
+ return true;
612
+ },
613
+ getProgramInfoLog: () => "",
614
+ useProgram: () => {
615
+ },
616
+ createBuffer: () => ({}),
617
+ bindBuffer: () => {
618
+ },
619
+ bufferData: () => {
620
+ },
621
+ enableVertexAttribArray: () => {
622
+ },
623
+ vertexAttribPointer: () => {
624
+ },
625
+ enable: () => {
626
+ },
627
+ disable: () => {
628
+ },
629
+ depthMask: () => {
630
+ },
631
+ blendFunc: () => {
632
+ },
633
+ viewport: () => {
634
+ },
635
+ clearColor: () => {
636
+ },
637
+ clear: () => {
638
+ },
639
+ createTexture: () => ({}),
640
+ bindTexture: () => {
641
+ },
642
+ texImage2D: () => {
643
+ },
644
+ texParameteri: () => {
645
+ },
646
+ activeTexture: () => {
647
+ },
648
+ uniform1i: () => {
649
+ },
650
+ uniform1f: () => {
651
+ },
652
+ uniform2f: () => {
653
+ },
654
+ uniform3f: () => {
655
+ },
656
+ uniform4f: () => {
657
+ },
658
+ uniformMatrix4fv: () => {
659
+ },
660
+ getUniformLocation: () => ({}),
661
+ getAttribLocation: () => 0,
662
+ drawArrays: () => {
663
+ },
664
+ drawElements: () => {
665
+ },
666
+ createVertexArray: () => ({}),
667
+ bindVertexArray: () => {
668
+ },
669
+ deleteShader: () => {
670
+ },
671
+ deleteProgram: () => {
672
+ },
673
+ deleteBuffer: () => {
674
+ },
675
+ deleteTexture: () => {
676
+ },
677
+ deleteVertexArray: () => {
678
+ },
679
+ // WebGL2 specific
680
+ texImage3D: () => {
681
+ },
682
+ uniformBlockBinding: () => {
683
+ },
684
+ getExtension: () => null
685
+ };
686
+ return gl;
687
+ }
688
+
689
+ // src/e2e/input.ts
690
+ var MockPointerLock = class {
691
+ static setup(doc) {
692
+ let _pointerLockElement = null;
693
+ Object.defineProperty(doc, "pointerLockElement", {
694
+ get: () => _pointerLockElement,
695
+ configurable: true
696
+ });
697
+ doc.exitPointerLock = () => {
698
+ if (_pointerLockElement) {
699
+ _pointerLockElement = null;
700
+ doc.dispatchEvent(new Event("pointerlockchange"));
701
+ }
702
+ };
703
+ global.HTMLElement.prototype.requestPointerLock = function() {
704
+ _pointerLockElement = this;
705
+ doc.dispatchEvent(new Event("pointerlockchange"));
706
+ };
707
+ }
708
+ };
709
+ var InputInjector = class {
710
+ constructor(doc, win) {
711
+ this.doc = doc;
712
+ this.win = win;
713
+ }
714
+ keyDown(key, code) {
715
+ const event = new this.win.KeyboardEvent("keydown", {
716
+ key,
717
+ code: code || key,
718
+ bubbles: true,
719
+ cancelable: true,
720
+ view: this.win
721
+ });
722
+ this.doc.dispatchEvent(event);
723
+ }
724
+ keyUp(key, code) {
725
+ const event = new this.win.KeyboardEvent("keyup", {
726
+ key,
727
+ code: code || key,
728
+ bubbles: true,
729
+ cancelable: true,
730
+ view: this.win
731
+ });
732
+ this.doc.dispatchEvent(event);
733
+ }
734
+ mouseMove(movementX, movementY, clientX = 0, clientY = 0) {
735
+ const event = new this.win.MouseEvent("mousemove", {
736
+ bubbles: true,
737
+ cancelable: true,
738
+ view: this.win,
739
+ clientX,
740
+ clientY,
741
+ movementX,
742
+ // Note: JSDOM might not support this standard property fully on event init
743
+ movementY
744
+ });
745
+ Object.defineProperty(event, "movementX", { value: movementX });
746
+ Object.defineProperty(event, "movementY", { value: movementY });
747
+ const target = this.doc.pointerLockElement || this.doc;
748
+ target.dispatchEvent(event);
749
+ }
750
+ mouseDown(button = 0) {
751
+ const event = new this.win.MouseEvent("mousedown", {
752
+ button,
753
+ bubbles: true,
754
+ cancelable: true,
755
+ view: this.win
756
+ });
757
+ const target = this.doc.pointerLockElement || this.doc;
758
+ target.dispatchEvent(event);
759
+ }
760
+ mouseUp(button = 0) {
761
+ const event = new this.win.MouseEvent("mouseup", {
762
+ button,
763
+ bubbles: true,
764
+ cancelable: true,
765
+ view: this.win
766
+ });
767
+ const target = this.doc.pointerLockElement || this.doc;
768
+ target.dispatchEvent(event);
769
+ }
770
+ wheel(deltaY) {
771
+ const event = new this.win.WheelEvent("wheel", {
772
+ deltaY,
773
+ bubbles: true,
774
+ cancelable: true,
775
+ view: this.win
776
+ });
777
+ const target = this.doc.pointerLockElement || this.doc;
778
+ target.dispatchEvent(event);
779
+ }
780
+ };
436
781
  // Annotate the CommonJS export names for ESM import in node:
437
782
  0 && (module.exports = {
783
+ InputInjector,
784
+ MockPointerLock,
438
785
  createBinaryStreamMock,
439
786
  createBinaryWriterMock,
440
787
  createEntity,
@@ -442,6 +789,7 @@ function createEntity() {
442
789
  createGameStateSnapshotFactory,
443
790
  createMockEngine,
444
791
  createMockGame,
792
+ createMockWebGL2Context,
445
793
  createNetChanMock,
446
794
  createPlayerStateFactory,
447
795
  createSpawnContext,
@@ -455,6 +803,9 @@ function createEntity() {
455
803
  makeLeafModel,
456
804
  makeNode,
457
805
  makePlane,
458
- stairTrace
806
+ setupBrowserEnvironment,
807
+ setupNodeEnvironment,
808
+ stairTrace,
809
+ teardownBrowserEnvironment
459
810
  });
460
811
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/shared/mocks.ts","../src/shared/bsp.ts","../src/game/factories.ts","../src/game/helpers.ts"],"sourcesContent":["// Export all test utilities\nexport * from './shared/mocks.js';\nexport * from './shared/bsp.js';\nexport * from './game/factories.js';\nexport * from './game/helpers.js';\n","import { vi, type Mock } from 'vitest';\n\nexport interface BinaryWriterMock {\n writeByte: Mock<[number], void>;\n writeShort: Mock<[number], void>;\n writeLong: Mock<[number], void>;\n writeString: Mock<[string], void>;\n writeBytes: Mock<[Uint8Array], void>;\n getBuffer: Mock<[], Uint8Array>;\n reset: Mock<[], void>;\n writeInt8: Mock<[number], void>;\n writeUint8: Mock<[number], void>;\n writeInt16: Mock<[number], void>;\n writeUint16: Mock<[number], void>;\n writeInt32: Mock<[number], void>;\n writeUint32: Mock<[number], void>;\n writeFloat: Mock<[number], void>;\n getData: Mock<[], Uint8Array>;\n}\n\nexport const createBinaryWriterMock = (): BinaryWriterMock => ({\n writeByte: vi.fn(),\n writeShort: vi.fn(),\n writeLong: vi.fn(),\n writeString: vi.fn(),\n writeBytes: vi.fn(),\n getBuffer: vi.fn<[], Uint8Array>(() => new Uint8Array(0)),\n reset: vi.fn(),\n // Legacy methods (if any)\n writeInt8: vi.fn(),\n writeUint8: vi.fn(),\n writeInt16: vi.fn(),\n writeUint16: vi.fn(),\n writeInt32: vi.fn(),\n writeUint32: vi.fn(),\n writeFloat: vi.fn(),\n getData: vi.fn<[], Uint8Array>(() => new Uint8Array(0)),\n});\n\nexport const createNetChanMock = () => ({\n qport: 1234,\n\n // Sequencing\n incomingSequence: 0,\n outgoingSequence: 0,\n incomingAcknowledged: 0,\n\n // Reliable messaging\n incomingReliableAcknowledged: false,\n incomingReliableSequence: 0,\n outgoingReliableSequence: 0,\n reliableMessage: createBinaryWriterMock(),\n reliableLength: 0,\n\n // Fragmentation\n fragmentSendOffset: 0,\n fragmentBuffer: null,\n fragmentLength: 0,\n fragmentReceived: 0,\n\n // Timing\n lastReceived: 0,\n lastSent: 0,\n\n remoteAddress: { type: 'IP', port: 1234 },\n\n // Methods\n setup: vi.fn(),\n reset: vi.fn(),\n transmit: vi.fn(),\n process: vi.fn(),\n canSendReliable: vi.fn(() => true),\n writeReliableByte: vi.fn(),\n writeReliableShort: vi.fn(),\n writeReliableLong: vi.fn(),\n writeReliableString: vi.fn(),\n getReliableData: vi.fn<[], Uint8Array>(() => new Uint8Array(0)),\n needsKeepalive: vi.fn(() => false),\n isTimedOut: vi.fn(() => false),\n});\n\nexport interface BinaryStreamMock {\n getPosition: Mock<[], number>;\n getReadPosition: Mock<[], number>;\n getLength: Mock<[], number>;\n getRemaining: Mock<[], number>;\n seek: Mock<[number], void>;\n setReadPosition: Mock<[number], void>;\n hasMore: Mock<[], boolean>;\n hasBytes: Mock<[number], boolean>;\n\n readChar: Mock<[], number>;\n readByte: Mock<[], number>;\n readShort: Mock<[], number>;\n readUShort: Mock<[], number>;\n readLong: Mock<[], number>;\n readULong: Mock<[], number>;\n readFloat: Mock<[], number>;\n\n readString: Mock<[], string>;\n readStringLine: Mock<[], string>;\n\n readCoord: Mock<[], number>;\n readAngle: Mock<[], number>;\n readAngle16: Mock<[], number>;\n\n readData: Mock<[number], Uint8Array>;\n\n readPos: Mock<[], any>; // Use proper type if available, e.g., Vec3\n readDir: Mock<[], any>;\n}\n\nexport const createBinaryStreamMock = (): BinaryStreamMock => ({\n getPosition: vi.fn(() => 0),\n getReadPosition: vi.fn(() => 0),\n getLength: vi.fn(() => 0),\n getRemaining: vi.fn(() => 0),\n seek: vi.fn(),\n setReadPosition: vi.fn(),\n hasMore: vi.fn(() => true),\n hasBytes: vi.fn((amount: number) => true),\n\n readChar: vi.fn(() => 0),\n readByte: vi.fn(() => 0),\n readShort: vi.fn(() => 0),\n readUShort: vi.fn(() => 0),\n readLong: vi.fn(() => 0),\n readULong: vi.fn(() => 0),\n readFloat: vi.fn(() => 0),\n\n readString: vi.fn(() => ''),\n readStringLine: vi.fn(() => ''),\n\n readCoord: vi.fn(() => 0),\n readAngle: vi.fn(() => 0),\n readAngle16: vi.fn(() => 0),\n\n readData: vi.fn<[number], Uint8Array>((length: number) => new Uint8Array(length)),\n\n readPos: vi.fn(),\n readDir: vi.fn(),\n});\n","import {\n computePlaneSignBits,\n type CollisionBrush,\n type CollisionModel,\n type CollisionPlane,\n type CollisionNode,\n type CollisionLeaf,\n CONTENTS_SOLID,\n type Vec3\n} from '@quake2ts/shared';\n\nexport function makePlane(normal: Vec3, dist: number): CollisionPlane {\n return {\n normal,\n dist,\n type: Math.abs(normal.x) === 1 ? 0 : Math.abs(normal.y) === 1 ? 1 : Math.abs(normal.z) === 1 ? 2 : 3,\n signbits: computePlaneSignBits(normal),\n };\n}\n\nexport function makeAxisBrush(size: number, contents = CONTENTS_SOLID): CollisionBrush {\n const half = size / 2;\n const planes = [\n makePlane({ x: 1, y: 0, z: 0 }, half),\n makePlane({ x: -1, y: 0, z: 0 }, half),\n makePlane({ x: 0, y: 1, z: 0 }, half),\n makePlane({ x: 0, y: -1, z: 0 }, half),\n makePlane({ x: 0, y: 0, z: 1 }, half),\n makePlane({ x: 0, y: 0, z: -1 }, half),\n ];\n\n return {\n contents,\n sides: planes.map((plane) => ({ plane, surfaceFlags: 0 })),\n };\n}\n\nexport function makeNode(plane: CollisionPlane, children: [number, number]): CollisionNode {\n return { plane, children };\n}\n\nexport function makeBspModel(\n planes: CollisionPlane[],\n nodes: CollisionNode[],\n leaves: CollisionLeaf[],\n brushes: CollisionBrush[],\n leafBrushes: number[]\n): CollisionModel {\n return {\n planes,\n nodes,\n leaves,\n brushes,\n leafBrushes,\n bmodels: [],\n };\n}\n\nexport function makeLeaf(contents: number, firstLeafBrush: number, numLeafBrushes: number): CollisionLeaf {\n return { contents, cluster: 0, area: 0, firstLeafBrush, numLeafBrushes };\n}\n\nexport function makeLeafModel(brushes: CollisionBrush[]): CollisionModel {\n const planes = brushes.flatMap((brush) => brush.sides.map((side) => side.plane));\n\n return {\n planes,\n nodes: [],\n leaves: [makeLeaf(0, 0, brushes.length)],\n brushes,\n leafBrushes: brushes.map((_, i) => i),\n bmodels: [],\n };\n}\n\nexport function makeBrushFromMinsMaxs(mins: Vec3, maxs: Vec3, contents = CONTENTS_SOLID): CollisionBrush {\n const planes = [\n makePlane({ x: 1, y: 0, z: 0 }, maxs.x),\n makePlane({ x: -1, y: 0, z: 0 }, -mins.x),\n makePlane({ x: 0, y: 1, z: 0 }, maxs.y),\n makePlane({ x: 0, y: -1, z: 0 }, -mins.y),\n makePlane({ x: 0, y: 0, z: 1 }, maxs.z),\n makePlane({ x: 0, y: 0, z: -1 }, -mins.z),\n ];\n\n return {\n contents,\n sides: planes.map((plane) => ({ plane, surfaceFlags: 0 })),\n };\n}\n","import type { PlayerState, EntityState } from '@quake2ts/shared';\nimport type { GameStateSnapshot } from '@quake2ts/game';\n\nexport const createPlayerStateFactory = (overrides?: Partial<PlayerState>): PlayerState => ({\n pm_type: 0,\n pm_time: 0,\n pm_flags: 0,\n origin: { x: 0, y: 0, z: 0 },\n velocity: { x: 0, y: 0, z: 0 },\n viewAngles: { x: 0, y: 0, z: 0 },\n onGround: false,\n waterLevel: 0,\n watertype: 0,\n mins: { x: 0, y: 0, z: 0 },\n maxs: { x: 0, y: 0, z: 0 },\n damageAlpha: 0,\n damageIndicators: [],\n blend: [0, 0, 0, 0],\n stats: [],\n kick_angles: { x: 0, y: 0, z: 0 },\n kick_origin: { x: 0, y: 0, z: 0 },\n gunoffset: { x: 0, y: 0, z: 0 },\n gunangles: { x: 0, y: 0, z: 0 },\n gunindex: 0,\n gun_frame: 0,\n rdflags: 0,\n fov: 90,\n renderfx: 0,\n ...overrides,\n});\n\nexport const createEntityStateFactory = (overrides?: Partial<EntityState>): EntityState => ({\n number: 0,\n origin: { x: 0, y: 0, z: 0 },\n angles: { x: 0, y: 0, z: 0 },\n oldOrigin: { x: 0, y: 0, z: 0 },\n modelIndex: 0,\n modelIndex2: 0,\n modelIndex3: 0,\n modelIndex4: 0,\n frame: 0,\n skinNum: 0,\n effects: 0,\n renderfx: 0,\n solid: 0,\n sound: 0,\n event: 0,\n ...overrides,\n});\n\nexport const createGameStateSnapshotFactory = (overrides?: Partial<GameStateSnapshot>): GameStateSnapshot => ({\n gravity: { x: 0, y: 0, z: -800 },\n origin: { x: 0, y: 0, z: 0 },\n velocity: { x: 0, y: 0, z: 0 },\n viewangles: { x: 0, y: 0, z: 0 },\n level: { timeSeconds: 0, frameNumber: 0, previousTimeSeconds: 0, deltaSeconds: 0.1 },\n entities: {\n activeCount: 0,\n worldClassname: 'worldspawn',\n },\n packetEntities: [],\n pmFlags: 0,\n pmType: 0,\n waterlevel: 0,\n watertype: 0,\n deltaAngles: { x: 0, y: 0, z: 0 },\n health: 100,\n armor: 0,\n ammo: 0,\n blend: [0, 0, 0, 0],\n damageAlpha: 0,\n damageIndicators: [],\n stats: [],\n kick_angles: { x: 0, y: 0, z: 0 },\n kick_origin: { x: 0, y: 0, z: 0 },\n gunoffset: { x: 0, y: 0, z: 0 },\n gunangles: { x: 0, y: 0, z: 0 },\n gunindex: 0,\n pm_time: 0,\n gun_frame: 0,\n rdflags: 0,\n fov: 90,\n renderfx: 0,\n pm_flags: 0,\n pm_type: 0,\n ...overrides,\n});\n","import { vi, type Mock } from 'vitest';\nimport { Entity, SpawnRegistry, ScriptHookRegistry, type SpawnContext, type EntitySystem } from '@quake2ts/game';\nimport { createRandomGenerator, type Vec3 } from '@quake2ts/shared';\n\n// Re-export generic helpers from shared\nexport { intersects, stairTrace, ladderTrace } from '@quake2ts/shared';\n\n// -- Types --\n\nexport interface MockEngine {\n sound: Mock<[Entity, number, string, number, number, number], void>;\n soundIndex: Mock<[string], number>;\n modelIndex: Mock<[string], number>;\n centerprintf: Mock<[Entity, string], void>;\n}\n\nexport interface MockGame {\n random: ReturnType<typeof createRandomGenerator>;\n registerEntitySpawn: Mock<[string, (entity: Entity) => void], void>;\n unregisterEntitySpawn: Mock<[string], void>;\n getCustomEntities: Mock<[], string[]>;\n hooks: ScriptHookRegistry;\n registerHooks: Mock<[any], any>;\n spawnWorld: Mock<[], void>;\n clientBegin: Mock<[any], void>;\n damage: Mock<[number], void>;\n}\n\nexport interface TestContext extends SpawnContext {\n entities: EntitySystem;\n game: MockGame;\n engine: MockEngine;\n}\n\n// -- Factories --\n\nexport const createMockEngine = (): MockEngine => ({\n sound: vi.fn(),\n soundIndex: vi.fn((sound: string) => 0),\n modelIndex: vi.fn((model: string) => 0),\n centerprintf: vi.fn(),\n});\n\nexport const createMockGame = (seed: number = 12345): { game: MockGame, spawnRegistry: SpawnRegistry } => {\n const spawnRegistry = new SpawnRegistry();\n const hooks = new ScriptHookRegistry();\n\n const game: MockGame = {\n random: createRandomGenerator({ seed }),\n registerEntitySpawn: vi.fn((classname: string, spawnFunc: (entity: Entity) => void) => {\n spawnRegistry.register(classname, (entity) => spawnFunc(entity));\n }),\n unregisterEntitySpawn: vi.fn((classname: string) => {\n spawnRegistry.unregister(classname);\n }),\n getCustomEntities: vi.fn(() => Array.from(spawnRegistry.keys())),\n hooks,\n registerHooks: vi.fn((newHooks) => hooks.register(newHooks)),\n spawnWorld: vi.fn(() => {\n hooks.onMapLoad('q2dm1');\n }),\n clientBegin: vi.fn((client) => {\n hooks.onPlayerSpawn({} as any);\n }),\n damage: vi.fn((amount: number) => {\n hooks.onDamage({} as any, null, null, amount, 0, 0);\n })\n };\n\n return { game, spawnRegistry };\n};\n\nexport function createTestContext(options?: { seed?: number, initialEntities?: Entity[] }): TestContext {\n const engine = createMockEngine();\n const seed = options?.seed ?? 12345;\n const { game, spawnRegistry } = createMockGame(seed);\n\n const traceFn = vi.fn((start: Vec3, end: Vec3, mins?: Vec3, maxs?: Vec3) => ({\n fraction: 1.0,\n ent: null,\n allsolid: false,\n startsolid: false,\n endpos: end,\n plane: { normal: { x: 0, y: 0, z: 1 }, dist: 0 },\n surfaceFlags: 0,\n contents: 0\n }));\n\n const entityList: Entity[] = options?.initialEntities ? [...options.initialEntities] : [];\n\n // Create hooks helper that interacts with the entity list\n const hooks = game.hooks;\n\n const entities = {\n spawn: vi.fn(() => {\n const ent = new Entity(entityList.length + 1);\n entityList.push(ent);\n hooks.onEntitySpawn(ent);\n return ent;\n }),\n free: vi.fn((ent: Entity) => {\n const idx = entityList.indexOf(ent);\n if (idx !== -1) {\n entityList.splice(idx, 1);\n }\n hooks.onEntityRemove(ent);\n }),\n finalizeSpawn: vi.fn(),\n freeImmediate: vi.fn((ent: Entity) => {\n const idx = entityList.indexOf(ent);\n if (idx !== -1) {\n entityList.splice(idx, 1);\n }\n }),\n setSpawnRegistry: vi.fn(),\n timeSeconds: 10,\n deltaSeconds: 0.1,\n modelIndex: vi.fn(() => 0),\n scheduleThink: vi.fn((entity: Entity, time: number) => {\n entity.nextthink = time;\n }),\n linkentity: vi.fn(),\n trace: traceFn,\n pointcontents: vi.fn(() => 0),\n multicast: vi.fn(),\n unicast: vi.fn(),\n engine,\n game,\n sound: vi.fn((ent: Entity, chan: number, sound: string, vol: number, attn: number, timeofs: number) => {\n engine.sound(ent, chan, sound, vol, attn, timeofs);\n }),\n soundIndex: vi.fn((sound: string) => engine.soundIndex(sound)),\n useTargets: vi.fn((entity: Entity, activator: Entity | null) => {\n }),\n findByTargetName: vi.fn(() => []),\n pickTarget: vi.fn(() => null),\n killBox: vi.fn(),\n rng: createRandomGenerator({ seed }),\n imports: {\n configstring: vi.fn(),\n trace: traceFn,\n pointcontents: vi.fn(() => 0),\n },\n level: {\n intermission_angle: { x: 0, y: 0, z: 0 },\n intermission_origin: { x: 0, y: 0, z: 0 },\n next_auto_save: 0,\n health_bar_entities: null\n },\n targetNameIndex: new Map(),\n forEachEntity: vi.fn((callback: (ent: Entity) => void) => {\n entityList.forEach(callback);\n }),\n find: vi.fn((predicate: (ent: Entity) => boolean) => {\n return entityList.find(predicate);\n }),\n findByClassname: vi.fn((classname: string) => {\n return entityList.find(e => e.classname === classname);\n }),\n beginFrame: vi.fn((timeSeconds: number) => {\n (entities as any).timeSeconds = timeSeconds;\n }),\n targetAwareness: {\n timeSeconds: 10,\n frameNumber: 1,\n sightEntity: null,\n soundEntity: null,\n },\n // Adding missing properties to satisfy EntitySystem interface partially or fully\n // We cast to unknown first anyway, but filling these in makes it safer for consumers\n skill: 1,\n deathmatch: false,\n coop: false,\n activeCount: entityList.length,\n world: entityList.find(e => e.classname === 'worldspawn') || new Entity(0),\n // ... other EntitySystem properties would go here\n } as unknown as EntitySystem;\n\n return {\n keyValues: {},\n entities,\n game,\n engine,\n health_multiplier: 1,\n warn: vi.fn(),\n free: vi.fn(),\n // Mock precache functions if they are part of SpawnContext in future or TestContext extensions\n precacheModel: vi.fn(),\n precacheSound: vi.fn(),\n precacheImage: vi.fn(),\n } as unknown as TestContext;\n}\n\nexport function createSpawnContext(): SpawnContext {\n return createTestContext();\n}\n\nexport function createEntity(): Entity {\n return new Entity(1);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,oBAA8B;AAoBvB,IAAM,yBAAyB,OAAyB;AAAA,EAC7D,WAAW,iBAAG,GAAG;AAAA,EACjB,YAAY,iBAAG,GAAG;AAAA,EAClB,WAAW,iBAAG,GAAG;AAAA,EACjB,aAAa,iBAAG,GAAG;AAAA,EACnB,YAAY,iBAAG,GAAG;AAAA,EAClB,WAAW,iBAAG,GAAmB,MAAM,IAAI,WAAW,CAAC,CAAC;AAAA,EACxD,OAAO,iBAAG,GAAG;AAAA;AAAA,EAEb,WAAW,iBAAG,GAAG;AAAA,EACjB,YAAY,iBAAG,GAAG;AAAA,EAClB,YAAY,iBAAG,GAAG;AAAA,EAClB,aAAa,iBAAG,GAAG;AAAA,EACnB,YAAY,iBAAG,GAAG;AAAA,EAClB,aAAa,iBAAG,GAAG;AAAA,EACnB,YAAY,iBAAG,GAAG;AAAA,EAClB,SAAS,iBAAG,GAAmB,MAAM,IAAI,WAAW,CAAC,CAAC;AACxD;AAEO,IAAM,oBAAoB,OAAO;AAAA,EACtC,OAAO;AAAA;AAAA,EAGP,kBAAkB;AAAA,EAClB,kBAAkB;AAAA,EAClB,sBAAsB;AAAA;AAAA,EAGtB,8BAA8B;AAAA,EAC9B,0BAA0B;AAAA,EAC1B,0BAA0B;AAAA,EAC1B,iBAAiB,uBAAuB;AAAA,EACxC,gBAAgB;AAAA;AAAA,EAGhB,oBAAoB;AAAA,EACpB,gBAAgB;AAAA,EAChB,gBAAgB;AAAA,EAChB,kBAAkB;AAAA;AAAA,EAGlB,cAAc;AAAA,EACd,UAAU;AAAA,EAEV,eAAe,EAAE,MAAM,MAAM,MAAM,KAAK;AAAA;AAAA,EAGxC,OAAO,iBAAG,GAAG;AAAA,EACb,OAAO,iBAAG,GAAG;AAAA,EACb,UAAU,iBAAG,GAAG;AAAA,EAChB,SAAS,iBAAG,GAAG;AAAA,EACf,iBAAiB,iBAAG,GAAG,MAAM,IAAI;AAAA,EACjC,mBAAmB,iBAAG,GAAG;AAAA,EACzB,oBAAoB,iBAAG,GAAG;AAAA,EAC1B,mBAAmB,iBAAG,GAAG;AAAA,EACzB,qBAAqB,iBAAG,GAAG;AAAA,EAC3B,iBAAiB,iBAAG,GAAmB,MAAM,IAAI,WAAW,CAAC,CAAC;AAAA,EAC9D,gBAAgB,iBAAG,GAAG,MAAM,KAAK;AAAA,EACjC,YAAY,iBAAG,GAAG,MAAM,KAAK;AAC/B;AAiCO,IAAM,yBAAyB,OAAyB;AAAA,EAC7D,aAAa,iBAAG,GAAG,MAAM,CAAC;AAAA,EAC1B,iBAAiB,iBAAG,GAAG,MAAM,CAAC;AAAA,EAC9B,WAAW,iBAAG,GAAG,MAAM,CAAC;AAAA,EACxB,cAAc,iBAAG,GAAG,MAAM,CAAC;AAAA,EAC3B,MAAM,iBAAG,GAAG;AAAA,EACZ,iBAAiB,iBAAG,GAAG;AAAA,EACvB,SAAS,iBAAG,GAAG,MAAM,IAAI;AAAA,EACzB,UAAU,iBAAG,GAAG,CAAC,WAAmB,IAAI;AAAA,EAExC,UAAU,iBAAG,GAAG,MAAM,CAAC;AAAA,EACvB,UAAU,iBAAG,GAAG,MAAM,CAAC;AAAA,EACvB,WAAW,iBAAG,GAAG,MAAM,CAAC;AAAA,EACxB,YAAY,iBAAG,GAAG,MAAM,CAAC;AAAA,EACzB,UAAU,iBAAG,GAAG,MAAM,CAAC;AAAA,EACvB,WAAW,iBAAG,GAAG,MAAM,CAAC;AAAA,EACxB,WAAW,iBAAG,GAAG,MAAM,CAAC;AAAA,EAExB,YAAY,iBAAG,GAAG,MAAM,EAAE;AAAA,EAC1B,gBAAgB,iBAAG,GAAG,MAAM,EAAE;AAAA,EAE9B,WAAW,iBAAG,GAAG,MAAM,CAAC;AAAA,EACxB,WAAW,iBAAG,GAAG,MAAM,CAAC;AAAA,EACxB,aAAa,iBAAG,GAAG,MAAM,CAAC;AAAA,EAE1B,UAAU,iBAAG,GAAyB,CAAC,WAAmB,IAAI,WAAW,MAAM,CAAC;AAAA,EAEhF,SAAS,iBAAG,GAAG;AAAA,EACf,SAAS,iBAAG,GAAG;AACjB;;;AC7IA,oBASO;AAEA,SAAS,UAAU,QAAc,MAA8B;AACpE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,MAAM,KAAK,IAAI,OAAO,CAAC,MAAM,IAAI,IAAI,KAAK,IAAI,OAAO,CAAC,MAAM,IAAI,IAAI,KAAK,IAAI,OAAO,CAAC,MAAM,IAAI,IAAI;AAAA,IACnG,cAAU,oCAAqB,MAAM;AAAA,EACvC;AACF;AAEO,SAAS,cAAc,MAAc,WAAW,8BAAgC;AACrF,QAAM,OAAO,OAAO;AACpB,QAAM,SAAS;AAAA,IACb,UAAU,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE,GAAG,IAAI;AAAA,IACpC,UAAU,EAAE,GAAG,IAAI,GAAG,GAAG,GAAG,EAAE,GAAG,IAAI;AAAA,IACrC,UAAU,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE,GAAG,IAAI;AAAA,IACpC,UAAU,EAAE,GAAG,GAAG,GAAG,IAAI,GAAG,EAAE,GAAG,IAAI;AAAA,IACrC,UAAU,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE,GAAG,IAAI;AAAA,IACpC,UAAU,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,IAAI;AAAA,EACvC;AAEA,SAAO;AAAA,IACL;AAAA,IACA,OAAO,OAAO,IAAI,CAAC,WAAW,EAAE,OAAO,cAAc,EAAE,EAAE;AAAA,EAC3D;AACF;AAEO,SAAS,SAAS,OAAuB,UAA2C;AACzF,SAAO,EAAE,OAAO,SAAS;AAC3B;AAEO,SAAS,aACd,QACA,OACA,QACA,SACA,aACgB;AAChB,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,SAAS,CAAC;AAAA,EACZ;AACF;AAEO,SAAS,SAAS,UAAkB,gBAAwB,gBAAuC;AACxG,SAAO,EAAE,UAAU,SAAS,GAAG,MAAM,GAAG,gBAAgB,eAAe;AACzE;AAEO,SAAS,cAAc,SAA2C;AACvE,QAAM,SAAS,QAAQ,QAAQ,CAAC,UAAU,MAAM,MAAM,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC;AAE/E,SAAO;AAAA,IACL;AAAA,IACA,OAAO,CAAC;AAAA,IACR,QAAQ,CAAC,SAAS,GAAG,GAAG,QAAQ,MAAM,CAAC;AAAA,IACvC;AAAA,IACA,aAAa,QAAQ,IAAI,CAAC,GAAG,MAAM,CAAC;AAAA,IACpC,SAAS,CAAC;AAAA,EACZ;AACF;AAEO,SAAS,sBAAsB,MAAY,MAAY,WAAW,8BAAgC;AACvG,QAAM,SAAS;AAAA,IACb,UAAU,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE,GAAG,KAAK,CAAC;AAAA,IACtC,UAAU,EAAE,GAAG,IAAI,GAAG,GAAG,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC;AAAA,IACxC,UAAU,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE,GAAG,KAAK,CAAC;AAAA,IACtC,UAAU,EAAE,GAAG,GAAG,GAAG,IAAI,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC;AAAA,IACxC,UAAU,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE,GAAG,KAAK,CAAC;AAAA,IACtC,UAAU,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC;AAAA,EAC1C;AAEA,SAAO;AAAA,IACL;AAAA,IACA,OAAO,OAAO,IAAI,CAAC,WAAW,EAAE,OAAO,cAAc,EAAE,EAAE;AAAA,EAC3D;AACF;;;ACtFO,IAAM,2BAA2B,CAAC,eAAmD;AAAA,EAC1F,SAAS;AAAA,EACT,SAAS;AAAA,EACT,UAAU;AAAA,EACV,QAAQ,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE;AAAA,EAC3B,UAAU,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE;AAAA,EAC7B,YAAY,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE;AAAA,EAC/B,UAAU;AAAA,EACV,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,MAAM,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE;AAAA,EACzB,MAAM,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE;AAAA,EACzB,aAAa;AAAA,EACb,kBAAkB,CAAC;AAAA,EACnB,OAAO,CAAC,GAAG,GAAG,GAAG,CAAC;AAAA,EAClB,OAAO,CAAC;AAAA,EACR,aAAa,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE;AAAA,EAChC,aAAa,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE;AAAA,EAChC,WAAW,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE;AAAA,EAC9B,WAAW,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE;AAAA,EAC9B,UAAU;AAAA,EACV,WAAW;AAAA,EACX,SAAS;AAAA,EACT,KAAK;AAAA,EACL,UAAU;AAAA,EACV,GAAG;AACL;AAEO,IAAM,2BAA2B,CAAC,eAAmD;AAAA,EAC1F,QAAQ;AAAA,EACR,QAAQ,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE;AAAA,EAC3B,QAAQ,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE;AAAA,EAC3B,WAAW,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE;AAAA,EAC9B,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,aAAa;AAAA,EACb,aAAa;AAAA,EACb,OAAO;AAAA,EACP,SAAS;AAAA,EACT,SAAS;AAAA,EACT,UAAU;AAAA,EACV,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AAAA,EACP,GAAG;AACL;AAEO,IAAM,iCAAiC,CAAC,eAA+D;AAAA,EAC5G,SAAS,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,KAAK;AAAA,EAC/B,QAAQ,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE;AAAA,EAC3B,UAAU,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE;AAAA,EAC7B,YAAY,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE;AAAA,EAC/B,OAAO,EAAE,aAAa,GAAG,aAAa,GAAG,qBAAqB,GAAG,cAAc,IAAI;AAAA,EACnF,UAAU;AAAA,IACR,aAAa;AAAA,IACb,gBAAgB;AAAA,EAClB;AAAA,EACA,gBAAgB,CAAC;AAAA,EACjB,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,aAAa,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE;AAAA,EAChC,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,MAAM;AAAA,EACN,OAAO,CAAC,GAAG,GAAG,GAAG,CAAC;AAAA,EAClB,aAAa;AAAA,EACb,kBAAkB,CAAC;AAAA,EACnB,OAAO,CAAC;AAAA,EACR,aAAa,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE;AAAA,EAChC,aAAa,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE;AAAA,EAChC,WAAW,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE;AAAA,EAC9B,WAAW,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE;AAAA,EAC9B,UAAU;AAAA,EACV,SAAS;AAAA,EACT,WAAW;AAAA,EACX,SAAS;AAAA,EACT,KAAK;AAAA,EACL,UAAU;AAAA,EACV,UAAU;AAAA,EACV,SAAS;AAAA,EACT,GAAG;AACL;;;ACtFA,IAAAA,iBAA8B;AAC9B,kBAAgG;AAChG,IAAAC,iBAAiD;AAGjD,IAAAA,iBAAoD;AA+B7C,IAAM,mBAAmB,OAAmB;AAAA,EACjD,OAAO,kBAAG,GAAG;AAAA,EACb,YAAY,kBAAG,GAAG,CAAC,UAAkB,CAAC;AAAA,EACtC,YAAY,kBAAG,GAAG,CAAC,UAAkB,CAAC;AAAA,EACtC,cAAc,kBAAG,GAAG;AACtB;AAEO,IAAM,iBAAiB,CAAC,OAAe,UAA4D;AACxG,QAAM,gBAAgB,IAAI,0BAAc;AACxC,QAAM,QAAQ,IAAI,+BAAmB;AAErC,QAAM,OAAiB;AAAA,IACrB,YAAQ,sCAAsB,EAAE,KAAK,CAAC;AAAA,IACtC,qBAAqB,kBAAG,GAAG,CAAC,WAAmB,cAAwC;AACrF,oBAAc,SAAS,WAAW,CAAC,WAAW,UAAU,MAAM,CAAC;AAAA,IACjE,CAAC;AAAA,IACD,uBAAuB,kBAAG,GAAG,CAAC,cAAsB;AAClD,oBAAc,WAAW,SAAS;AAAA,IACpC,CAAC;AAAA,IACD,mBAAmB,kBAAG,GAAG,MAAM,MAAM,KAAK,cAAc,KAAK,CAAC,CAAC;AAAA,IAC/D;AAAA,IACA,eAAe,kBAAG,GAAG,CAAC,aAAa,MAAM,SAAS,QAAQ,CAAC;AAAA,IAC3D,YAAY,kBAAG,GAAG,MAAM;AACtB,YAAM,UAAU,OAAO;AAAA,IACzB,CAAC;AAAA,IACD,aAAa,kBAAG,GAAG,CAAC,WAAW;AAC7B,YAAM,cAAc,CAAC,CAAQ;AAAA,IAC/B,CAAC;AAAA,IACD,QAAQ,kBAAG,GAAG,CAAC,WAAmB;AAChC,YAAM,SAAS,CAAC,GAAU,MAAM,MAAM,QAAQ,GAAG,CAAC;AAAA,IACpD,CAAC;AAAA,EACH;AAEA,SAAO,EAAE,MAAM,cAAc;AAC/B;AAEO,SAAS,kBAAkB,SAAsE;AACtG,QAAM,SAAS,iBAAiB;AAChC,QAAM,OAAO,SAAS,QAAQ;AAC9B,QAAM,EAAE,MAAM,cAAc,IAAI,eAAe,IAAI;AAEnD,QAAM,UAAU,kBAAG,GAAG,CAAC,OAAa,KAAW,MAAa,UAAiB;AAAA,IAC3E,UAAU;AAAA,IACV,KAAK;AAAA,IACL,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,OAAO,EAAE,QAAQ,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE,GAAG,MAAM,EAAE;AAAA,IAC/C,cAAc;AAAA,IACd,UAAU;AAAA,EACZ,EAAE;AAEF,QAAM,aAAuB,SAAS,kBAAkB,CAAC,GAAG,QAAQ,eAAe,IAAI,CAAC;AAGxF,QAAM,QAAQ,KAAK;AAEnB,QAAM,WAAW;AAAA,IACf,OAAO,kBAAG,GAAG,MAAM;AACjB,YAAM,MAAM,IAAI,mBAAO,WAAW,SAAS,CAAC;AAC5C,iBAAW,KAAK,GAAG;AACnB,YAAM,cAAc,GAAG;AACvB,aAAO;AAAA,IACT,CAAC;AAAA,IACD,MAAM,kBAAG,GAAG,CAAC,QAAgB;AAC3B,YAAM,MAAM,WAAW,QAAQ,GAAG;AAClC,UAAI,QAAQ,IAAI;AACd,mBAAW,OAAO,KAAK,CAAC;AAAA,MAC1B;AACA,YAAM,eAAe,GAAG;AAAA,IAC1B,CAAC;AAAA,IACD,eAAe,kBAAG,GAAG;AAAA,IACrB,eAAe,kBAAG,GAAG,CAAC,QAAgB;AACpC,YAAM,MAAM,WAAW,QAAQ,GAAG;AAClC,UAAI,QAAQ,IAAI;AACd,mBAAW,OAAO,KAAK,CAAC;AAAA,MAC1B;AAAA,IACF,CAAC;AAAA,IACD,kBAAkB,kBAAG,GAAG;AAAA,IACxB,aAAa;AAAA,IACb,cAAc;AAAA,IACd,YAAY,kBAAG,GAAG,MAAM,CAAC;AAAA,IACzB,eAAe,kBAAG,GAAG,CAAC,QAAgB,SAAiB;AACrD,aAAO,YAAY;AAAA,IACrB,CAAC;AAAA,IACD,YAAY,kBAAG,GAAG;AAAA,IAClB,OAAO;AAAA,IACP,eAAe,kBAAG,GAAG,MAAM,CAAC;AAAA,IAC5B,WAAW,kBAAG,GAAG;AAAA,IACjB,SAAS,kBAAG,GAAG;AAAA,IACf;AAAA,IACA;AAAA,IACA,OAAO,kBAAG,GAAG,CAAC,KAAa,MAAc,OAAe,KAAa,MAAc,YAAoB;AACrG,aAAO,MAAM,KAAK,MAAM,OAAO,KAAK,MAAM,OAAO;AAAA,IACnD,CAAC;AAAA,IACD,YAAY,kBAAG,GAAG,CAAC,UAAkB,OAAO,WAAW,KAAK,CAAC;AAAA,IAC7D,YAAY,kBAAG,GAAG,CAAC,QAAgB,cAA6B;AAAA,IAChE,CAAC;AAAA,IACD,kBAAkB,kBAAG,GAAG,MAAM,CAAC,CAAC;AAAA,IAChC,YAAY,kBAAG,GAAG,MAAM,IAAI;AAAA,IAC5B,SAAS,kBAAG,GAAG;AAAA,IACf,SAAK,sCAAsB,EAAE,KAAK,CAAC;AAAA,IACnC,SAAS;AAAA,MACP,cAAc,kBAAG,GAAG;AAAA,MACpB,OAAO;AAAA,MACP,eAAe,kBAAG,GAAG,MAAM,CAAC;AAAA,IAC9B;AAAA,IACA,OAAO;AAAA,MACL,oBAAoB,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE;AAAA,MACvC,qBAAqB,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE;AAAA,MACxC,gBAAgB;AAAA,MAChB,qBAAqB;AAAA,IACvB;AAAA,IACA,iBAAiB,oBAAI,IAAI;AAAA,IACzB,eAAe,kBAAG,GAAG,CAAC,aAAoC;AACxD,iBAAW,QAAQ,QAAQ;AAAA,IAC7B,CAAC;AAAA,IACD,MAAM,kBAAG,GAAG,CAAC,cAAwC;AACnD,aAAO,WAAW,KAAK,SAAS;AAAA,IAClC,CAAC;AAAA,IACD,iBAAiB,kBAAG,GAAG,CAAC,cAAsB;AAC5C,aAAO,WAAW,KAAK,OAAK,EAAE,cAAc,SAAS;AAAA,IACvD,CAAC;AAAA,IACD,YAAY,kBAAG,GAAG,CAAC,gBAAwB;AACzC,MAAC,SAAiB,cAAc;AAAA,IAClC,CAAC;AAAA,IACD,iBAAiB;AAAA,MACf,aAAa;AAAA,MACb,aAAa;AAAA,MACb,aAAa;AAAA,MACb,aAAa;AAAA,IACf;AAAA;AAAA;AAAA,IAGA,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,MAAM;AAAA,IACN,aAAa,WAAW;AAAA,IACxB,OAAO,WAAW,KAAK,OAAK,EAAE,cAAc,YAAY,KAAK,IAAI,mBAAO,CAAC;AAAA;AAAA,EAE3E;AAEA,SAAO;AAAA,IACL,WAAW,CAAC;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,IACA,mBAAmB;AAAA,IACnB,MAAM,kBAAG,GAAG;AAAA,IACZ,MAAM,kBAAG,GAAG;AAAA;AAAA,IAEZ,eAAe,kBAAG,GAAG;AAAA,IACrB,eAAe,kBAAG,GAAG;AAAA,IACrB,eAAe,kBAAG,GAAG;AAAA,EACvB;AACF;AAEO,SAAS,qBAAmC;AACjD,SAAO,kBAAkB;AAC3B;AAEO,SAAS,eAAuB;AACrC,SAAO,IAAI,mBAAO,CAAC;AACrB;","names":["import_vitest","import_shared"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/shared/mocks.ts","../src/shared/bsp.ts","../src/game/factories.ts","../src/game/helpers.ts","../src/setup/browser.ts","../src/setup/node.ts","../src/setup/webgl.ts","../src/e2e/input.ts"],"sourcesContent":["// Export all test utilities\nexport * from './shared/mocks.js';\nexport * from './shared/bsp.js';\nexport * from './game/factories.js';\nexport * from './game/helpers.js';\nexport * from './setup/browser.js';\nexport * from './setup/node.js';\nexport * from './setup/webgl.js';\nexport * from './e2e/input.js';\n","import { vi, type Mock } from 'vitest';\n\nexport interface BinaryWriterMock {\n writeByte: Mock<[number], void>;\n writeShort: Mock<[number], void>;\n writeLong: Mock<[number], void>;\n writeString: Mock<[string], void>;\n writeBytes: Mock<[Uint8Array], void>;\n getBuffer: Mock<[], Uint8Array>;\n reset: Mock<[], void>;\n writeInt8: Mock<[number], void>;\n writeUint8: Mock<[number], void>;\n writeInt16: Mock<[number], void>;\n writeUint16: Mock<[number], void>;\n writeInt32: Mock<[number], void>;\n writeUint32: Mock<[number], void>;\n writeFloat: Mock<[number], void>;\n getData: Mock<[], Uint8Array>;\n}\n\nexport const createBinaryWriterMock = (): BinaryWriterMock => ({\n writeByte: vi.fn(),\n writeShort: vi.fn(),\n writeLong: vi.fn(),\n writeString: vi.fn(),\n writeBytes: vi.fn(),\n getBuffer: vi.fn<[], Uint8Array>(() => new Uint8Array(0)),\n reset: vi.fn(),\n // Legacy methods (if any)\n writeInt8: vi.fn(),\n writeUint8: vi.fn(),\n writeInt16: vi.fn(),\n writeUint16: vi.fn(),\n writeInt32: vi.fn(),\n writeUint32: vi.fn(),\n writeFloat: vi.fn(),\n getData: vi.fn<[], Uint8Array>(() => new Uint8Array(0)),\n});\n\nexport const createNetChanMock = () => ({\n qport: 1234,\n\n // Sequencing\n incomingSequence: 0,\n outgoingSequence: 0,\n incomingAcknowledged: 0,\n\n // Reliable messaging\n incomingReliableAcknowledged: false,\n incomingReliableSequence: 0,\n outgoingReliableSequence: 0,\n reliableMessage: createBinaryWriterMock(),\n reliableLength: 0,\n\n // Fragmentation\n fragmentSendOffset: 0,\n fragmentBuffer: null,\n fragmentLength: 0,\n fragmentReceived: 0,\n\n // Timing\n lastReceived: 0,\n lastSent: 0,\n\n remoteAddress: { type: 'IP', port: 1234 },\n\n // Methods\n setup: vi.fn(),\n reset: vi.fn(),\n transmit: vi.fn(),\n process: vi.fn(),\n canSendReliable: vi.fn(() => true),\n writeReliableByte: vi.fn(),\n writeReliableShort: vi.fn(),\n writeReliableLong: vi.fn(),\n writeReliableString: vi.fn(),\n getReliableData: vi.fn<[], Uint8Array>(() => new Uint8Array(0)),\n needsKeepalive: vi.fn(() => false),\n isTimedOut: vi.fn(() => false),\n});\n\nexport interface BinaryStreamMock {\n getPosition: Mock<[], number>;\n getReadPosition: Mock<[], number>;\n getLength: Mock<[], number>;\n getRemaining: Mock<[], number>;\n seek: Mock<[number], void>;\n setReadPosition: Mock<[number], void>;\n hasMore: Mock<[], boolean>;\n hasBytes: Mock<[number], boolean>;\n\n readChar: Mock<[], number>;\n readByte: Mock<[], number>;\n readShort: Mock<[], number>;\n readUShort: Mock<[], number>;\n readLong: Mock<[], number>;\n readULong: Mock<[], number>;\n readFloat: Mock<[], number>;\n\n readString: Mock<[], string>;\n readStringLine: Mock<[], string>;\n\n readCoord: Mock<[], number>;\n readAngle: Mock<[], number>;\n readAngle16: Mock<[], number>;\n\n readData: Mock<[number], Uint8Array>;\n\n readPos: Mock<[], any>; // Use proper type if available, e.g., Vec3\n readDir: Mock<[], any>;\n}\n\nexport const createBinaryStreamMock = (): BinaryStreamMock => ({\n getPosition: vi.fn(() => 0),\n getReadPosition: vi.fn(() => 0),\n getLength: vi.fn(() => 0),\n getRemaining: vi.fn(() => 0),\n seek: vi.fn(),\n setReadPosition: vi.fn(),\n hasMore: vi.fn(() => true),\n hasBytes: vi.fn((amount: number) => true),\n\n readChar: vi.fn(() => 0),\n readByte: vi.fn(() => 0),\n readShort: vi.fn(() => 0),\n readUShort: vi.fn(() => 0),\n readLong: vi.fn(() => 0),\n readULong: vi.fn(() => 0),\n readFloat: vi.fn(() => 0),\n\n readString: vi.fn(() => ''),\n readStringLine: vi.fn(() => ''),\n\n readCoord: vi.fn(() => 0),\n readAngle: vi.fn(() => 0),\n readAngle16: vi.fn(() => 0),\n\n readData: vi.fn<[number], Uint8Array>((length: number) => new Uint8Array(length)),\n\n readPos: vi.fn(),\n readDir: vi.fn(),\n});\n","import {\n computePlaneSignBits,\n type CollisionBrush,\n type CollisionModel,\n type CollisionPlane,\n type CollisionNode,\n type CollisionLeaf,\n CONTENTS_SOLID,\n type Vec3\n} from '@quake2ts/shared';\n\nexport function makePlane(normal: Vec3, dist: number): CollisionPlane {\n return {\n normal,\n dist,\n type: Math.abs(normal.x) === 1 ? 0 : Math.abs(normal.y) === 1 ? 1 : Math.abs(normal.z) === 1 ? 2 : 3,\n signbits: computePlaneSignBits(normal),\n };\n}\n\nexport function makeAxisBrush(size: number, contents = CONTENTS_SOLID): CollisionBrush {\n const half = size / 2;\n const planes = [\n makePlane({ x: 1, y: 0, z: 0 }, half),\n makePlane({ x: -1, y: 0, z: 0 }, half),\n makePlane({ x: 0, y: 1, z: 0 }, half),\n makePlane({ x: 0, y: -1, z: 0 }, half),\n makePlane({ x: 0, y: 0, z: 1 }, half),\n makePlane({ x: 0, y: 0, z: -1 }, half),\n ];\n\n return {\n contents,\n sides: planes.map((plane) => ({ plane, surfaceFlags: 0 })),\n };\n}\n\nexport function makeNode(plane: CollisionPlane, children: [number, number]): CollisionNode {\n return { plane, children };\n}\n\nexport function makeBspModel(\n planes: CollisionPlane[],\n nodes: CollisionNode[],\n leaves: CollisionLeaf[],\n brushes: CollisionBrush[],\n leafBrushes: number[]\n): CollisionModel {\n return {\n planes,\n nodes,\n leaves,\n brushes,\n leafBrushes,\n bmodels: [],\n };\n}\n\nexport function makeLeaf(contents: number, firstLeafBrush: number, numLeafBrushes: number): CollisionLeaf {\n return { contents, cluster: 0, area: 0, firstLeafBrush, numLeafBrushes };\n}\n\nexport function makeLeafModel(brushes: CollisionBrush[]): CollisionModel {\n const planes = brushes.flatMap((brush) => brush.sides.map((side) => side.plane));\n\n return {\n planes,\n nodes: [],\n leaves: [makeLeaf(0, 0, brushes.length)],\n brushes,\n leafBrushes: brushes.map((_, i) => i),\n bmodels: [],\n };\n}\n\nexport function makeBrushFromMinsMaxs(mins: Vec3, maxs: Vec3, contents = CONTENTS_SOLID): CollisionBrush {\n const planes = [\n makePlane({ x: 1, y: 0, z: 0 }, maxs.x),\n makePlane({ x: -1, y: 0, z: 0 }, -mins.x),\n makePlane({ x: 0, y: 1, z: 0 }, maxs.y),\n makePlane({ x: 0, y: -1, z: 0 }, -mins.y),\n makePlane({ x: 0, y: 0, z: 1 }, maxs.z),\n makePlane({ x: 0, y: 0, z: -1 }, -mins.z),\n ];\n\n return {\n contents,\n sides: planes.map((plane) => ({ plane, surfaceFlags: 0 })),\n };\n}\n","import type { PlayerState, EntityState } from '@quake2ts/shared';\nimport type { GameStateSnapshot } from '@quake2ts/game';\n\nexport const createPlayerStateFactory = (overrides?: Partial<PlayerState>): PlayerState => ({\n pm_type: 0,\n pm_time: 0,\n pm_flags: 0,\n origin: { x: 0, y: 0, z: 0 },\n velocity: { x: 0, y: 0, z: 0 },\n viewAngles: { x: 0, y: 0, z: 0 },\n onGround: false,\n waterLevel: 0,\n watertype: 0,\n mins: { x: 0, y: 0, z: 0 },\n maxs: { x: 0, y: 0, z: 0 },\n damageAlpha: 0,\n damageIndicators: [],\n blend: [0, 0, 0, 0],\n stats: [],\n kick_angles: { x: 0, y: 0, z: 0 },\n kick_origin: { x: 0, y: 0, z: 0 },\n gunoffset: { x: 0, y: 0, z: 0 },\n gunangles: { x: 0, y: 0, z: 0 },\n gunindex: 0,\n gun_frame: 0,\n rdflags: 0,\n fov: 90,\n renderfx: 0,\n ...overrides,\n});\n\nexport const createEntityStateFactory = (overrides?: Partial<EntityState>): EntityState => ({\n number: 0,\n origin: { x: 0, y: 0, z: 0 },\n angles: { x: 0, y: 0, z: 0 },\n oldOrigin: { x: 0, y: 0, z: 0 },\n modelIndex: 0,\n modelIndex2: 0,\n modelIndex3: 0,\n modelIndex4: 0,\n frame: 0,\n skinNum: 0,\n effects: 0,\n renderfx: 0,\n solid: 0,\n sound: 0,\n event: 0,\n ...overrides,\n});\n\nexport const createGameStateSnapshotFactory = (overrides?: Partial<GameStateSnapshot>): GameStateSnapshot => ({\n gravity: { x: 0, y: 0, z: -800 },\n origin: { x: 0, y: 0, z: 0 },\n velocity: { x: 0, y: 0, z: 0 },\n viewangles: { x: 0, y: 0, z: 0 },\n level: { timeSeconds: 0, frameNumber: 0, previousTimeSeconds: 0, deltaSeconds: 0.1 },\n entities: {\n activeCount: 0,\n worldClassname: 'worldspawn',\n },\n packetEntities: [],\n pmFlags: 0,\n pmType: 0,\n waterlevel: 0,\n watertype: 0,\n deltaAngles: { x: 0, y: 0, z: 0 },\n health: 100,\n armor: 0,\n ammo: 0,\n blend: [0, 0, 0, 0],\n damageAlpha: 0,\n damageIndicators: [],\n stats: [],\n kick_angles: { x: 0, y: 0, z: 0 },\n kick_origin: { x: 0, y: 0, z: 0 },\n gunoffset: { x: 0, y: 0, z: 0 },\n gunangles: { x: 0, y: 0, z: 0 },\n gunindex: 0,\n pm_time: 0,\n gun_frame: 0,\n rdflags: 0,\n fov: 90,\n renderfx: 0,\n pm_flags: 0,\n pm_type: 0,\n ...overrides,\n});\n","import { vi, type Mock } from 'vitest';\nimport { Entity, SpawnRegistry, ScriptHookRegistry, type SpawnContext, type EntitySystem } from '@quake2ts/game';\nimport { createRandomGenerator, type Vec3 } from '@quake2ts/shared';\n\n// Re-export generic helpers from shared\nexport { intersects, stairTrace, ladderTrace } from '@quake2ts/shared';\n\n// -- Types --\n\nexport interface MockEngine {\n sound: Mock<[Entity, number, string, number, number, number], void>;\n soundIndex: Mock<[string], number>;\n modelIndex: Mock<[string], number>;\n centerprintf: Mock<[Entity, string], void>;\n}\n\nexport interface MockGame {\n random: ReturnType<typeof createRandomGenerator>;\n registerEntitySpawn: Mock<[string, (entity: Entity) => void], void>;\n unregisterEntitySpawn: Mock<[string], void>;\n getCustomEntities: Mock<[], string[]>;\n hooks: ScriptHookRegistry;\n registerHooks: Mock<[any], any>;\n spawnWorld: Mock<[], void>;\n clientBegin: Mock<[any], void>;\n damage: Mock<[number], void>;\n}\n\nexport interface TestContext extends SpawnContext {\n entities: EntitySystem;\n game: MockGame;\n engine: MockEngine;\n}\n\n// -- Factories --\n\nexport const createMockEngine = (): MockEngine => ({\n sound: vi.fn(),\n soundIndex: vi.fn((sound: string) => 0),\n modelIndex: vi.fn((model: string) => 0),\n centerprintf: vi.fn(),\n});\n\nexport const createMockGame = (seed: number = 12345): { game: MockGame, spawnRegistry: SpawnRegistry } => {\n const spawnRegistry = new SpawnRegistry();\n const hooks = new ScriptHookRegistry();\n\n const game: MockGame = {\n random: createRandomGenerator({ seed }),\n registerEntitySpawn: vi.fn((classname: string, spawnFunc: (entity: Entity) => void) => {\n spawnRegistry.register(classname, (entity) => spawnFunc(entity));\n }),\n unregisterEntitySpawn: vi.fn((classname: string) => {\n spawnRegistry.unregister(classname);\n }),\n getCustomEntities: vi.fn(() => Array.from(spawnRegistry.keys())),\n hooks,\n registerHooks: vi.fn((newHooks) => hooks.register(newHooks)),\n spawnWorld: vi.fn(() => {\n hooks.onMapLoad('q2dm1');\n }),\n clientBegin: vi.fn((client) => {\n hooks.onPlayerSpawn({} as any);\n }),\n damage: vi.fn((amount: number) => {\n hooks.onDamage({} as any, null, null, amount, 0, 0);\n })\n };\n\n return { game, spawnRegistry };\n};\n\nexport function createTestContext(options?: { seed?: number, initialEntities?: Entity[] }): TestContext {\n const engine = createMockEngine();\n const seed = options?.seed ?? 12345;\n const { game, spawnRegistry } = createMockGame(seed);\n\n const traceFn = vi.fn((start: Vec3, end: Vec3, mins?: Vec3, maxs?: Vec3) => ({\n fraction: 1.0,\n ent: null,\n allsolid: false,\n startsolid: false,\n endpos: end,\n plane: { normal: { x: 0, y: 0, z: 1 }, dist: 0 },\n surfaceFlags: 0,\n contents: 0\n }));\n\n const entityList: Entity[] = options?.initialEntities ? [...options.initialEntities] : [];\n\n // Create hooks helper that interacts with the entity list\n const hooks = game.hooks;\n\n const entities = {\n spawn: vi.fn(() => {\n const ent = new Entity(entityList.length + 1);\n entityList.push(ent);\n hooks.onEntitySpawn(ent);\n return ent;\n }),\n free: vi.fn((ent: Entity) => {\n const idx = entityList.indexOf(ent);\n if (idx !== -1) {\n entityList.splice(idx, 1);\n }\n hooks.onEntityRemove(ent);\n }),\n finalizeSpawn: vi.fn(),\n freeImmediate: vi.fn((ent: Entity) => {\n const idx = entityList.indexOf(ent);\n if (idx !== -1) {\n entityList.splice(idx, 1);\n }\n }),\n setSpawnRegistry: vi.fn(),\n timeSeconds: 10,\n deltaSeconds: 0.1,\n modelIndex: vi.fn(() => 0),\n scheduleThink: vi.fn((entity: Entity, time: number) => {\n entity.nextthink = time;\n }),\n linkentity: vi.fn(),\n trace: traceFn,\n pointcontents: vi.fn(() => 0),\n multicast: vi.fn(),\n unicast: vi.fn(),\n engine,\n game,\n sound: vi.fn((ent: Entity, chan: number, sound: string, vol: number, attn: number, timeofs: number) => {\n engine.sound(ent, chan, sound, vol, attn, timeofs);\n }),\n soundIndex: vi.fn((sound: string) => engine.soundIndex(sound)),\n useTargets: vi.fn((entity: Entity, activator: Entity | null) => {\n }),\n findByTargetName: vi.fn(() => []),\n pickTarget: vi.fn(() => null),\n killBox: vi.fn(),\n rng: createRandomGenerator({ seed }),\n imports: {\n configstring: vi.fn(),\n trace: traceFn,\n pointcontents: vi.fn(() => 0),\n },\n level: {\n intermission_angle: { x: 0, y: 0, z: 0 },\n intermission_origin: { x: 0, y: 0, z: 0 },\n next_auto_save: 0,\n health_bar_entities: null\n },\n targetNameIndex: new Map(),\n forEachEntity: vi.fn((callback: (ent: Entity) => void) => {\n entityList.forEach(callback);\n }),\n find: vi.fn((predicate: (ent: Entity) => boolean) => {\n return entityList.find(predicate);\n }),\n findByClassname: vi.fn((classname: string) => {\n return entityList.find(e => e.classname === classname);\n }),\n beginFrame: vi.fn((timeSeconds: number) => {\n (entities as any).timeSeconds = timeSeconds;\n }),\n targetAwareness: {\n timeSeconds: 10,\n frameNumber: 1,\n sightEntity: null,\n soundEntity: null,\n },\n // Adding missing properties to satisfy EntitySystem interface partially or fully\n // We cast to unknown first anyway, but filling these in makes it safer for consumers\n skill: 1,\n deathmatch: false,\n coop: false,\n activeCount: entityList.length,\n world: entityList.find(e => e.classname === 'worldspawn') || new Entity(0),\n // ... other EntitySystem properties would go here\n } as unknown as EntitySystem;\n\n return {\n keyValues: {},\n entities,\n game,\n engine,\n health_multiplier: 1,\n warn: vi.fn(),\n free: vi.fn(),\n // Mock precache functions if they are part of SpawnContext in future or TestContext extensions\n precacheModel: vi.fn(),\n precacheSound: vi.fn(),\n precacheImage: vi.fn(),\n } as unknown as TestContext;\n}\n\nexport function createSpawnContext(): SpawnContext {\n return createTestContext();\n}\n\nexport function createEntity(): Entity {\n return new Entity(1);\n}\n","import { JSDOM } from 'jsdom';\nimport { Canvas, Image, ImageData } from '@napi-rs/canvas';\nimport 'fake-indexeddb/auto';\n\nexport interface BrowserSetupOptions {\n url?: string;\n pretendToBeVisual?: boolean;\n}\n\n/**\n * Sets up a browser environment for testing using JSDOM and napi-rs/canvas.\n * This should be called in your vitest.setup.ts file.\n */\nexport function setupBrowserEnvironment(options: BrowserSetupOptions = {}) {\n const { url = 'http://localhost', pretendToBeVisual = true } = options;\n\n // Create a JSDOM instance\n const dom = new JSDOM('<!DOCTYPE html><html><head></head><body></body></html>', {\n url,\n pretendToBeVisual,\n });\n\n // Set up global variables\n global.window = dom.window as any;\n global.document = dom.window.document;\n global.navigator = dom.window.navigator;\n global.location = dom.window.location;\n global.HTMLElement = dom.window.HTMLElement;\n\n // Polyfill global Event constructors to match JSDOM's window\n global.Event = dom.window.Event;\n global.CustomEvent = dom.window.CustomEvent;\n global.DragEvent = dom.window.DragEvent as any;\n global.MouseEvent = dom.window.MouseEvent;\n global.KeyboardEvent = dom.window.KeyboardEvent;\n global.FocusEvent = dom.window.FocusEvent;\n global.WheelEvent = dom.window.WheelEvent;\n global.InputEvent = dom.window.InputEvent;\n global.UIEvent = dom.window.UIEvent;\n\n // Setup Storage mocks\n // First try to use JSDOM's localStorage\n try {\n global.localStorage = dom.window.localStorage;\n } catch (e) {\n // Ignore if it fails (e.g. strict mode)\n }\n\n // Fallback if not present\n if (!global.localStorage) {\n const storage = new Map<string, string>();\n global.localStorage = {\n getItem: (key: string) => storage.get(key) || null,\n setItem: (key: string, value: string) => storage.set(key, value),\n removeItem: (key: string) => storage.delete(key),\n clear: () => storage.clear(),\n key: (index: number) => Array.from(storage.keys())[index] || null,\n get length() { return storage.size; }\n } as Storage;\n }\n\n // Override document.createElement for canvas elements to use napi-rs/canvas\n const originalCreateElement = document.createElement.bind(document);\n document.createElement = function (tagName: string, options?: any) {\n if (tagName.toLowerCase() === 'canvas') {\n const napiCanvas = new Canvas(300, 150); // default canvas size\n\n // Create a wrapper that extends the DOM canvas element\n const domCanvas = originalCreateElement('canvas', options);\n\n // Copy properties and methods from napi-rs canvas to DOM canvas\n Object.defineProperty(domCanvas, 'width', {\n get: () => napiCanvas.width,\n set: (value) => { napiCanvas.width = value; },\n enumerable: true,\n configurable: true\n });\n\n Object.defineProperty(domCanvas, 'height', {\n get: () => napiCanvas.height,\n set: (value) => { napiCanvas.height = value; },\n enumerable: true,\n configurable: true\n });\n\n // Override getContext to return appropriate context\n const originalGetContext = domCanvas.getContext.bind(domCanvas);\n domCanvas.getContext = function(contextId: string, options?: any) {\n if (contextId === '2d') {\n return napiCanvas.getContext('2d', options);\n }\n // For webgl/webgl2, return jsdom's default context (null or mock)\n // or the original behavior if needed.\n if (contextId === 'webgl' || contextId === 'webgl2') {\n return originalGetContext(contextId, options);\n }\n return napiCanvas.getContext(contextId as any, options);\n } as any;\n\n // Store reference to napi canvas for direct access if needed\n (domCanvas as any).__napiCanvas = napiCanvas;\n\n return domCanvas;\n }\n return originalCreateElement(tagName, options);\n } as any;\n\n // Set up global Image constructor\n global.Image = Image as any;\n\n // Set up global ImageData constructor\n global.ImageData = ImageData as any;\n\n // Mock createImageBitmap if not available\n if (typeof global.createImageBitmap === 'undefined') {\n global.createImageBitmap = async function (\n image: any, // Relax type to allow passing different image sources\n _options?: ImageBitmapOptions\n ): Promise<any> {\n // Handle ImageData specially\n if (image && typeof image.width === 'number' && typeof image.height === 'number') {\n // For testing purposes, we can create a small canvas with the image data\n const canvas = new Canvas(image.width, image.height);\n const ctx = canvas.getContext('2d');\n // Only try to put data if it looks like ImageData\n if (image.data) {\n ctx.putImageData(image as any, 0, 0);\n }\n return canvas;\n }\n // Fallback for other sources (e.g. Image element) - return empty canvas of generic size\n const canvas = new Canvas(100, 100);\n return canvas;\n } as any;\n }\n\n // Mock btoa and atob if not available\n if (typeof global.btoa === 'undefined') {\n global.btoa = function (str: string): string {\n return Buffer.from(str, 'binary').toString('base64');\n };\n }\n\n if (typeof global.atob === 'undefined') {\n global.atob = function (str: string): string {\n return Buffer.from(str, 'base64').toString('binary');\n };\n }\n}\n\n/**\n * Cleans up the browser environment.\n */\nexport function teardownBrowserEnvironment() {\n // Optional cleanup if needed, though usually global scope cleanup is handled by test runner context\n // or by just overriding it again.\n // For strict cleanup, we could delete globals, but in Vitest environment, it might persist?\n // We'll leave it simple for now or just undefined them.\n\n // @ts-ignore\n delete global.window;\n // @ts-ignore\n delete global.document;\n // @ts-ignore\n delete global.navigator;\n // @ts-ignore\n delete global.localStorage;\n // @ts-ignore\n delete global.location;\n // @ts-ignore\n delete global.HTMLElement;\n // @ts-ignore\n delete global.Image;\n // @ts-ignore\n delete global.ImageData;\n // @ts-ignore\n delete global.createImageBitmap;\n\n // Note: btoa/atob might be native in newer Node versions, so be careful deleting them if they were original.\n // But here we only set them if undefined.\n}\n","/**\n * Sets up a Node.js environment for testing.\n * This is primarily for backend or shared logic that doesn't rely on browser APIs.\n */\nexport function setupNodeEnvironment() {\n // Add any Node-specific global setup here\n // For now, this is a placeholder or can be used for things like\n // polyfilling fetch if not present in older Node versions (though Quake2TS targets recent Node)\n\n if (typeof global.fetch === 'undefined') {\n // In a real scenario, we might import node-fetch here\n // global.fetch = ...\n }\n}\n","\nexport function createMockWebGL2Context(canvas: HTMLCanvasElement): WebGL2RenderingContext {\n const gl = {\n canvas,\n drawingBufferWidth: canvas.width,\n drawingBufferHeight: canvas.height,\n\n // Constants\n VERTEX_SHADER: 0x8B31,\n FRAGMENT_SHADER: 0x8B30,\n COMPILE_STATUS: 0x8B81,\n LINK_STATUS: 0x8B82,\n ARRAY_BUFFER: 0x8892,\n ELEMENT_ARRAY_BUFFER: 0x8893,\n STATIC_DRAW: 0x88E4,\n DYNAMIC_DRAW: 0x88E8,\n FLOAT: 0x1406,\n DEPTH_TEST: 0x0B71,\n BLEND: 0x0BE2,\n SRC_ALPHA: 0x0302,\n ONE_MINUS_SRC_ALPHA: 0x0303,\n TEXTURE_2D: 0x0DE1,\n RGBA: 0x1908,\n UNSIGNED_BYTE: 0x1401,\n COLOR_BUFFER_BIT: 0x4000,\n DEPTH_BUFFER_BIT: 0x0100,\n TRIANGLES: 0x0004,\n TRIANGLE_STRIP: 0x0005,\n TRIANGLE_FAN: 0x0006,\n\n // Methods\n createShader: () => ({}),\n shaderSource: () => {},\n compileShader: () => {},\n getShaderParameter: (_: any, param: number) => {\n if (param === 0x8B81) return true; // COMPILE_STATUS\n return true;\n },\n getShaderInfoLog: () => '',\n createProgram: () => ({}),\n attachShader: () => {},\n linkProgram: () => {},\n getProgramParameter: (_: any, param: number) => {\n if (param === 0x8B82) return true; // LINK_STATUS\n return true;\n },\n getProgramInfoLog: () => '',\n useProgram: () => {},\n createBuffer: () => ({}),\n bindBuffer: () => {},\n bufferData: () => {},\n enableVertexAttribArray: () => {},\n vertexAttribPointer: () => {},\n enable: () => {},\n disable: () => {},\n depthMask: () => {},\n blendFunc: () => {},\n viewport: () => {},\n clearColor: () => {},\n clear: () => {},\n createTexture: () => ({}),\n bindTexture: () => {},\n texImage2D: () => {},\n texParameteri: () => {},\n activeTexture: () => {},\n uniform1i: () => {},\n uniform1f: () => {},\n uniform2f: () => {},\n uniform3f: () => {},\n uniform4f: () => {},\n uniformMatrix4fv: () => {},\n getUniformLocation: () => ({}),\n getAttribLocation: () => 0,\n drawArrays: () => {},\n drawElements: () => {},\n createVertexArray: () => ({}),\n bindVertexArray: () => {},\n deleteShader: () => {},\n deleteProgram: () => {},\n deleteBuffer: () => {},\n deleteTexture: () => {},\n deleteVertexArray: () => {},\n\n // WebGL2 specific\n texImage3D: () => {},\n uniformBlockBinding: () => {},\n getExtension: () => null,\n } as unknown as WebGL2RenderingContext;\n\n return gl;\n}\n","\nexport class MockPointerLock {\n static setup(doc: Document) {\n // Mock pointerLockElement property\n let _pointerLockElement: Element | null = null;\n\n Object.defineProperty(doc, 'pointerLockElement', {\n get: () => _pointerLockElement,\n configurable: true\n });\n\n // Mock exitPointerLock\n doc.exitPointerLock = () => {\n if (_pointerLockElement) {\n _pointerLockElement = null;\n doc.dispatchEvent(new Event('pointerlockchange'));\n }\n };\n\n // Mock requestPointerLock on Element prototype\n // We need to extend the Element interface to make TS happy if we were strict,\n // but here we are modifying the prototype directly.\n // @ts-ignore\n (global.HTMLElement.prototype as any).requestPointerLock = function() {\n // In a real browser this is async and requires user gesture,\n // but for tests we make it immediate.\n _pointerLockElement = this;\n doc.dispatchEvent(new Event('pointerlockchange'));\n };\n }\n}\n\nexport class InputInjector {\n constructor(private doc: Document, private win: any) {}\n\n keyDown(key: string, code?: string) {\n const event = new this.win.KeyboardEvent('keydown', {\n key,\n code: code || key,\n bubbles: true,\n cancelable: true,\n view: this.win\n });\n this.doc.dispatchEvent(event);\n }\n\n keyUp(key: string, code?: string) {\n const event = new this.win.KeyboardEvent('keyup', {\n key,\n code: code || key,\n bubbles: true,\n cancelable: true,\n view: this.win\n });\n this.doc.dispatchEvent(event);\n }\n\n mouseMove(movementX: number, movementY: number, clientX = 0, clientY = 0) {\n const event = new this.win.MouseEvent('mousemove', {\n bubbles: true,\n cancelable: true,\n view: this.win,\n clientX,\n clientY,\n movementX, // Note: JSDOM might not support this standard property fully on event init\n movementY\n } as any);\n\n // Force movement properties if JSDOM doesn't handle them\n Object.defineProperty(event, 'movementX', { value: movementX });\n Object.defineProperty(event, 'movementY', { value: movementY });\n\n // Dispatch to pointer lock element if active, otherwise document\n // @ts-ignore\n const target = this.doc.pointerLockElement || this.doc;\n target.dispatchEvent(event);\n }\n\n mouseDown(button: number = 0) {\n const event = new this.win.MouseEvent('mousedown', {\n button,\n bubbles: true,\n cancelable: true,\n view: this.win\n });\n // @ts-ignore\n const target = this.doc.pointerLockElement || this.doc;\n target.dispatchEvent(event);\n }\n\n mouseUp(button: number = 0) {\n const event = new this.win.MouseEvent('mouseup', {\n button,\n bubbles: true,\n cancelable: true,\n view: this.win\n });\n // @ts-ignore\n const target = this.doc.pointerLockElement || this.doc;\n target.dispatchEvent(event);\n }\n\n wheel(deltaY: number) {\n const event = new this.win.WheelEvent('wheel', {\n deltaY,\n bubbles: true,\n cancelable: true,\n view: this.win\n });\n // @ts-ignore\n const target = this.doc.pointerLockElement || this.doc;\n target.dispatchEvent(event);\n }\n}\n"],"mappings":"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","names":["import_vitest","import_shared","options","canvas"]}
@@ -127,4 +127,41 @@ declare function createTestContext(options?: {
127
127
  declare function createSpawnContext(): SpawnContext;
128
128
  declare function createEntity(): Entity;
129
129
 
130
- export { type BinaryStreamMock, type BinaryWriterMock, type MockEngine, type MockGame, type TestContext, createBinaryStreamMock, createBinaryWriterMock, createEntity, createEntityStateFactory, createGameStateSnapshotFactory, createMockEngine, createMockGame, createNetChanMock, createPlayerStateFactory, createSpawnContext, createTestContext, makeAxisBrush, makeBrushFromMinsMaxs, makeBspModel, makeLeaf, makeLeafModel, makeNode, makePlane };
130
+ interface BrowserSetupOptions {
131
+ url?: string;
132
+ pretendToBeVisual?: boolean;
133
+ }
134
+ /**
135
+ * Sets up a browser environment for testing using JSDOM and napi-rs/canvas.
136
+ * This should be called in your vitest.setup.ts file.
137
+ */
138
+ declare function setupBrowserEnvironment(options?: BrowserSetupOptions): void;
139
+ /**
140
+ * Cleans up the browser environment.
141
+ */
142
+ declare function teardownBrowserEnvironment(): void;
143
+
144
+ /**
145
+ * Sets up a Node.js environment for testing.
146
+ * This is primarily for backend or shared logic that doesn't rely on browser APIs.
147
+ */
148
+ declare function setupNodeEnvironment(): void;
149
+
150
+ declare function createMockWebGL2Context(canvas: HTMLCanvasElement): WebGL2RenderingContext;
151
+
152
+ declare class MockPointerLock {
153
+ static setup(doc: Document): void;
154
+ }
155
+ declare class InputInjector {
156
+ private doc;
157
+ private win;
158
+ constructor(doc: Document, win: any);
159
+ keyDown(key: string, code?: string): void;
160
+ keyUp(key: string, code?: string): void;
161
+ mouseMove(movementX: number, movementY: number, clientX?: number, clientY?: number): void;
162
+ mouseDown(button?: number): void;
163
+ mouseUp(button?: number): void;
164
+ wheel(deltaY: number): void;
165
+ }
166
+
167
+ export { type BinaryStreamMock, type BinaryWriterMock, type BrowserSetupOptions, InputInjector, type MockEngine, type MockGame, MockPointerLock, type TestContext, createBinaryStreamMock, createBinaryWriterMock, createEntity, createEntityStateFactory, createGameStateSnapshotFactory, createMockEngine, createMockGame, createMockWebGL2Context, createNetChanMock, createPlayerStateFactory, createSpawnContext, createTestContext, makeAxisBrush, makeBrushFromMinsMaxs, makeBspModel, makeLeaf, makeLeafModel, makeNode, makePlane, setupBrowserEnvironment, setupNodeEnvironment, teardownBrowserEnvironment };
@@ -127,4 +127,41 @@ declare function createTestContext(options?: {
127
127
  declare function createSpawnContext(): SpawnContext;
128
128
  declare function createEntity(): Entity;
129
129
 
130
- export { type BinaryStreamMock, type BinaryWriterMock, type MockEngine, type MockGame, type TestContext, createBinaryStreamMock, createBinaryWriterMock, createEntity, createEntityStateFactory, createGameStateSnapshotFactory, createMockEngine, createMockGame, createNetChanMock, createPlayerStateFactory, createSpawnContext, createTestContext, makeAxisBrush, makeBrushFromMinsMaxs, makeBspModel, makeLeaf, makeLeafModel, makeNode, makePlane };
130
+ interface BrowserSetupOptions {
131
+ url?: string;
132
+ pretendToBeVisual?: boolean;
133
+ }
134
+ /**
135
+ * Sets up a browser environment for testing using JSDOM and napi-rs/canvas.
136
+ * This should be called in your vitest.setup.ts file.
137
+ */
138
+ declare function setupBrowserEnvironment(options?: BrowserSetupOptions): void;
139
+ /**
140
+ * Cleans up the browser environment.
141
+ */
142
+ declare function teardownBrowserEnvironment(): void;
143
+
144
+ /**
145
+ * Sets up a Node.js environment for testing.
146
+ * This is primarily for backend or shared logic that doesn't rely on browser APIs.
147
+ */
148
+ declare function setupNodeEnvironment(): void;
149
+
150
+ declare function createMockWebGL2Context(canvas: HTMLCanvasElement): WebGL2RenderingContext;
151
+
152
+ declare class MockPointerLock {
153
+ static setup(doc: Document): void;
154
+ }
155
+ declare class InputInjector {
156
+ private doc;
157
+ private win;
158
+ constructor(doc: Document, win: any);
159
+ keyDown(key: string, code?: string): void;
160
+ keyUp(key: string, code?: string): void;
161
+ mouseMove(movementX: number, movementY: number, clientX?: number, clientY?: number): void;
162
+ mouseDown(button?: number): void;
163
+ mouseUp(button?: number): void;
164
+ wheel(deltaY: number): void;
165
+ }
166
+
167
+ export { type BinaryStreamMock, type BinaryWriterMock, type BrowserSetupOptions, InputInjector, type MockEngine, type MockGame, MockPointerLock, type TestContext, createBinaryStreamMock, createBinaryWriterMock, createEntity, createEntityStateFactory, createGameStateSnapshotFactory, createMockEngine, createMockGame, createMockWebGL2Context, createNetChanMock, createPlayerStateFactory, createSpawnContext, createTestContext, makeAxisBrush, makeBrushFromMinsMaxs, makeBspModel, makeLeaf, makeLeafModel, makeNode, makePlane, setupBrowserEnvironment, setupNodeEnvironment, teardownBrowserEnvironment };