quake2ts 0.0.552 → 0.0.553
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/package.json +1 -1
- package/packages/engine/dist/tsconfig.tsbuildinfo +1 -1
- package/packages/engine/dist/types/assets/index.d.ts +2 -0
- package/packages/engine/dist/types/assets/index.d.ts.map +1 -1
- package/packages/engine/dist/types/assets/interactionGraph.d.ts +21 -0
- package/packages/engine/dist/types/assets/interactionGraph.d.ts.map +1 -0
- package/packages/engine/dist/types/assets/visibilityAnalyzer.d.ts +9 -3
- package/packages/engine/dist/types/assets/visibilityAnalyzer.d.ts.map +1 -1
- package/packages/test-utils/dist/index.cjs +353 -2
- package/packages/test-utils/dist/index.cjs.map +1 -1
- package/packages/test-utils/dist/index.d.cts +38 -1
- package/packages/test-utils/dist/index.d.ts +38 -1
- package/packages/test-utils/dist/index.js +346 -1
- package/packages/test-utils/dist/index.js.map +1 -1
|
@@ -390,7 +390,348 @@ function createSpawnContext() {
|
|
|
390
390
|
function createEntity() {
|
|
391
391
|
return new Entity(1);
|
|
392
392
|
}
|
|
393
|
+
|
|
394
|
+
// src/setup/browser.ts
|
|
395
|
+
import { JSDOM } from "jsdom";
|
|
396
|
+
import { Canvas, Image, ImageData } from "@napi-rs/canvas";
|
|
397
|
+
import "fake-indexeddb/auto";
|
|
398
|
+
function setupBrowserEnvironment(options = {}) {
|
|
399
|
+
const { url = "http://localhost", pretendToBeVisual = true } = options;
|
|
400
|
+
const dom = new JSDOM("<!DOCTYPE html><html><head></head><body></body></html>", {
|
|
401
|
+
url,
|
|
402
|
+
pretendToBeVisual
|
|
403
|
+
});
|
|
404
|
+
global.window = dom.window;
|
|
405
|
+
global.document = dom.window.document;
|
|
406
|
+
global.navigator = dom.window.navigator;
|
|
407
|
+
global.location = dom.window.location;
|
|
408
|
+
global.HTMLElement = dom.window.HTMLElement;
|
|
409
|
+
global.Event = dom.window.Event;
|
|
410
|
+
global.CustomEvent = dom.window.CustomEvent;
|
|
411
|
+
global.DragEvent = dom.window.DragEvent;
|
|
412
|
+
global.MouseEvent = dom.window.MouseEvent;
|
|
413
|
+
global.KeyboardEvent = dom.window.KeyboardEvent;
|
|
414
|
+
global.FocusEvent = dom.window.FocusEvent;
|
|
415
|
+
global.WheelEvent = dom.window.WheelEvent;
|
|
416
|
+
global.InputEvent = dom.window.InputEvent;
|
|
417
|
+
global.UIEvent = dom.window.UIEvent;
|
|
418
|
+
try {
|
|
419
|
+
global.localStorage = dom.window.localStorage;
|
|
420
|
+
} catch (e) {
|
|
421
|
+
}
|
|
422
|
+
if (!global.localStorage) {
|
|
423
|
+
const storage = /* @__PURE__ */ new Map();
|
|
424
|
+
global.localStorage = {
|
|
425
|
+
getItem: (key) => storage.get(key) || null,
|
|
426
|
+
setItem: (key, value) => storage.set(key, value),
|
|
427
|
+
removeItem: (key) => storage.delete(key),
|
|
428
|
+
clear: () => storage.clear(),
|
|
429
|
+
key: (index) => Array.from(storage.keys())[index] || null,
|
|
430
|
+
get length() {
|
|
431
|
+
return storage.size;
|
|
432
|
+
}
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
const originalCreateElement = document.createElement.bind(document);
|
|
436
|
+
document.createElement = function(tagName, options2) {
|
|
437
|
+
if (tagName.toLowerCase() === "canvas") {
|
|
438
|
+
const napiCanvas = new Canvas(300, 150);
|
|
439
|
+
const domCanvas = originalCreateElement("canvas", options2);
|
|
440
|
+
Object.defineProperty(domCanvas, "width", {
|
|
441
|
+
get: () => napiCanvas.width,
|
|
442
|
+
set: (value) => {
|
|
443
|
+
napiCanvas.width = value;
|
|
444
|
+
},
|
|
445
|
+
enumerable: true,
|
|
446
|
+
configurable: true
|
|
447
|
+
});
|
|
448
|
+
Object.defineProperty(domCanvas, "height", {
|
|
449
|
+
get: () => napiCanvas.height,
|
|
450
|
+
set: (value) => {
|
|
451
|
+
napiCanvas.height = value;
|
|
452
|
+
},
|
|
453
|
+
enumerable: true,
|
|
454
|
+
configurable: true
|
|
455
|
+
});
|
|
456
|
+
const originalGetContext = domCanvas.getContext.bind(domCanvas);
|
|
457
|
+
domCanvas.getContext = function(contextId, options3) {
|
|
458
|
+
if (contextId === "2d") {
|
|
459
|
+
return napiCanvas.getContext("2d", options3);
|
|
460
|
+
}
|
|
461
|
+
if (contextId === "webgl" || contextId === "webgl2") {
|
|
462
|
+
return originalGetContext(contextId, options3);
|
|
463
|
+
}
|
|
464
|
+
return napiCanvas.getContext(contextId, options3);
|
|
465
|
+
};
|
|
466
|
+
domCanvas.__napiCanvas = napiCanvas;
|
|
467
|
+
return domCanvas;
|
|
468
|
+
}
|
|
469
|
+
return originalCreateElement(tagName, options2);
|
|
470
|
+
};
|
|
471
|
+
global.Image = Image;
|
|
472
|
+
global.ImageData = ImageData;
|
|
473
|
+
if (typeof global.createImageBitmap === "undefined") {
|
|
474
|
+
global.createImageBitmap = async function(image, _options) {
|
|
475
|
+
if (image && typeof image.width === "number" && typeof image.height === "number") {
|
|
476
|
+
const canvas2 = new Canvas(image.width, image.height);
|
|
477
|
+
const ctx = canvas2.getContext("2d");
|
|
478
|
+
if (image.data) {
|
|
479
|
+
ctx.putImageData(image, 0, 0);
|
|
480
|
+
}
|
|
481
|
+
return canvas2;
|
|
482
|
+
}
|
|
483
|
+
const canvas = new Canvas(100, 100);
|
|
484
|
+
return canvas;
|
|
485
|
+
};
|
|
486
|
+
}
|
|
487
|
+
if (typeof global.btoa === "undefined") {
|
|
488
|
+
global.btoa = function(str) {
|
|
489
|
+
return Buffer.from(str, "binary").toString("base64");
|
|
490
|
+
};
|
|
491
|
+
}
|
|
492
|
+
if (typeof global.atob === "undefined") {
|
|
493
|
+
global.atob = function(str) {
|
|
494
|
+
return Buffer.from(str, "base64").toString("binary");
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
function teardownBrowserEnvironment() {
|
|
499
|
+
delete global.window;
|
|
500
|
+
delete global.document;
|
|
501
|
+
delete global.navigator;
|
|
502
|
+
delete global.localStorage;
|
|
503
|
+
delete global.location;
|
|
504
|
+
delete global.HTMLElement;
|
|
505
|
+
delete global.Image;
|
|
506
|
+
delete global.ImageData;
|
|
507
|
+
delete global.createImageBitmap;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
// src/setup/node.ts
|
|
511
|
+
function setupNodeEnvironment() {
|
|
512
|
+
if (typeof global.fetch === "undefined") {
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
// src/setup/webgl.ts
|
|
517
|
+
function createMockWebGL2Context(canvas) {
|
|
518
|
+
const gl = {
|
|
519
|
+
canvas,
|
|
520
|
+
drawingBufferWidth: canvas.width,
|
|
521
|
+
drawingBufferHeight: canvas.height,
|
|
522
|
+
// Constants
|
|
523
|
+
VERTEX_SHADER: 35633,
|
|
524
|
+
FRAGMENT_SHADER: 35632,
|
|
525
|
+
COMPILE_STATUS: 35713,
|
|
526
|
+
LINK_STATUS: 35714,
|
|
527
|
+
ARRAY_BUFFER: 34962,
|
|
528
|
+
ELEMENT_ARRAY_BUFFER: 34963,
|
|
529
|
+
STATIC_DRAW: 35044,
|
|
530
|
+
DYNAMIC_DRAW: 35048,
|
|
531
|
+
FLOAT: 5126,
|
|
532
|
+
DEPTH_TEST: 2929,
|
|
533
|
+
BLEND: 3042,
|
|
534
|
+
SRC_ALPHA: 770,
|
|
535
|
+
ONE_MINUS_SRC_ALPHA: 771,
|
|
536
|
+
TEXTURE_2D: 3553,
|
|
537
|
+
RGBA: 6408,
|
|
538
|
+
UNSIGNED_BYTE: 5121,
|
|
539
|
+
COLOR_BUFFER_BIT: 16384,
|
|
540
|
+
DEPTH_BUFFER_BIT: 256,
|
|
541
|
+
TRIANGLES: 4,
|
|
542
|
+
TRIANGLE_STRIP: 5,
|
|
543
|
+
TRIANGLE_FAN: 6,
|
|
544
|
+
// Methods
|
|
545
|
+
createShader: () => ({}),
|
|
546
|
+
shaderSource: () => {
|
|
547
|
+
},
|
|
548
|
+
compileShader: () => {
|
|
549
|
+
},
|
|
550
|
+
getShaderParameter: (_, param) => {
|
|
551
|
+
if (param === 35713) return true;
|
|
552
|
+
return true;
|
|
553
|
+
},
|
|
554
|
+
getShaderInfoLog: () => "",
|
|
555
|
+
createProgram: () => ({}),
|
|
556
|
+
attachShader: () => {
|
|
557
|
+
},
|
|
558
|
+
linkProgram: () => {
|
|
559
|
+
},
|
|
560
|
+
getProgramParameter: (_, param) => {
|
|
561
|
+
if (param === 35714) return true;
|
|
562
|
+
return true;
|
|
563
|
+
},
|
|
564
|
+
getProgramInfoLog: () => "",
|
|
565
|
+
useProgram: () => {
|
|
566
|
+
},
|
|
567
|
+
createBuffer: () => ({}),
|
|
568
|
+
bindBuffer: () => {
|
|
569
|
+
},
|
|
570
|
+
bufferData: () => {
|
|
571
|
+
},
|
|
572
|
+
enableVertexAttribArray: () => {
|
|
573
|
+
},
|
|
574
|
+
vertexAttribPointer: () => {
|
|
575
|
+
},
|
|
576
|
+
enable: () => {
|
|
577
|
+
},
|
|
578
|
+
disable: () => {
|
|
579
|
+
},
|
|
580
|
+
depthMask: () => {
|
|
581
|
+
},
|
|
582
|
+
blendFunc: () => {
|
|
583
|
+
},
|
|
584
|
+
viewport: () => {
|
|
585
|
+
},
|
|
586
|
+
clearColor: () => {
|
|
587
|
+
},
|
|
588
|
+
clear: () => {
|
|
589
|
+
},
|
|
590
|
+
createTexture: () => ({}),
|
|
591
|
+
bindTexture: () => {
|
|
592
|
+
},
|
|
593
|
+
texImage2D: () => {
|
|
594
|
+
},
|
|
595
|
+
texParameteri: () => {
|
|
596
|
+
},
|
|
597
|
+
activeTexture: () => {
|
|
598
|
+
},
|
|
599
|
+
uniform1i: () => {
|
|
600
|
+
},
|
|
601
|
+
uniform1f: () => {
|
|
602
|
+
},
|
|
603
|
+
uniform2f: () => {
|
|
604
|
+
},
|
|
605
|
+
uniform3f: () => {
|
|
606
|
+
},
|
|
607
|
+
uniform4f: () => {
|
|
608
|
+
},
|
|
609
|
+
uniformMatrix4fv: () => {
|
|
610
|
+
},
|
|
611
|
+
getUniformLocation: () => ({}),
|
|
612
|
+
getAttribLocation: () => 0,
|
|
613
|
+
drawArrays: () => {
|
|
614
|
+
},
|
|
615
|
+
drawElements: () => {
|
|
616
|
+
},
|
|
617
|
+
createVertexArray: () => ({}),
|
|
618
|
+
bindVertexArray: () => {
|
|
619
|
+
},
|
|
620
|
+
deleteShader: () => {
|
|
621
|
+
},
|
|
622
|
+
deleteProgram: () => {
|
|
623
|
+
},
|
|
624
|
+
deleteBuffer: () => {
|
|
625
|
+
},
|
|
626
|
+
deleteTexture: () => {
|
|
627
|
+
},
|
|
628
|
+
deleteVertexArray: () => {
|
|
629
|
+
},
|
|
630
|
+
// WebGL2 specific
|
|
631
|
+
texImage3D: () => {
|
|
632
|
+
},
|
|
633
|
+
uniformBlockBinding: () => {
|
|
634
|
+
},
|
|
635
|
+
getExtension: () => null
|
|
636
|
+
};
|
|
637
|
+
return gl;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
// src/e2e/input.ts
|
|
641
|
+
var MockPointerLock = class {
|
|
642
|
+
static setup(doc) {
|
|
643
|
+
let _pointerLockElement = null;
|
|
644
|
+
Object.defineProperty(doc, "pointerLockElement", {
|
|
645
|
+
get: () => _pointerLockElement,
|
|
646
|
+
configurable: true
|
|
647
|
+
});
|
|
648
|
+
doc.exitPointerLock = () => {
|
|
649
|
+
if (_pointerLockElement) {
|
|
650
|
+
_pointerLockElement = null;
|
|
651
|
+
doc.dispatchEvent(new Event("pointerlockchange"));
|
|
652
|
+
}
|
|
653
|
+
};
|
|
654
|
+
global.HTMLElement.prototype.requestPointerLock = function() {
|
|
655
|
+
_pointerLockElement = this;
|
|
656
|
+
doc.dispatchEvent(new Event("pointerlockchange"));
|
|
657
|
+
};
|
|
658
|
+
}
|
|
659
|
+
};
|
|
660
|
+
var InputInjector = class {
|
|
661
|
+
constructor(doc, win) {
|
|
662
|
+
this.doc = doc;
|
|
663
|
+
this.win = win;
|
|
664
|
+
}
|
|
665
|
+
keyDown(key, code) {
|
|
666
|
+
const event = new this.win.KeyboardEvent("keydown", {
|
|
667
|
+
key,
|
|
668
|
+
code: code || key,
|
|
669
|
+
bubbles: true,
|
|
670
|
+
cancelable: true,
|
|
671
|
+
view: this.win
|
|
672
|
+
});
|
|
673
|
+
this.doc.dispatchEvent(event);
|
|
674
|
+
}
|
|
675
|
+
keyUp(key, code) {
|
|
676
|
+
const event = new this.win.KeyboardEvent("keyup", {
|
|
677
|
+
key,
|
|
678
|
+
code: code || key,
|
|
679
|
+
bubbles: true,
|
|
680
|
+
cancelable: true,
|
|
681
|
+
view: this.win
|
|
682
|
+
});
|
|
683
|
+
this.doc.dispatchEvent(event);
|
|
684
|
+
}
|
|
685
|
+
mouseMove(movementX, movementY, clientX = 0, clientY = 0) {
|
|
686
|
+
const event = new this.win.MouseEvent("mousemove", {
|
|
687
|
+
bubbles: true,
|
|
688
|
+
cancelable: true,
|
|
689
|
+
view: this.win,
|
|
690
|
+
clientX,
|
|
691
|
+
clientY,
|
|
692
|
+
movementX,
|
|
693
|
+
// Note: JSDOM might not support this standard property fully on event init
|
|
694
|
+
movementY
|
|
695
|
+
});
|
|
696
|
+
Object.defineProperty(event, "movementX", { value: movementX });
|
|
697
|
+
Object.defineProperty(event, "movementY", { value: movementY });
|
|
698
|
+
const target = this.doc.pointerLockElement || this.doc;
|
|
699
|
+
target.dispatchEvent(event);
|
|
700
|
+
}
|
|
701
|
+
mouseDown(button = 0) {
|
|
702
|
+
const event = new this.win.MouseEvent("mousedown", {
|
|
703
|
+
button,
|
|
704
|
+
bubbles: true,
|
|
705
|
+
cancelable: true,
|
|
706
|
+
view: this.win
|
|
707
|
+
});
|
|
708
|
+
const target = this.doc.pointerLockElement || this.doc;
|
|
709
|
+
target.dispatchEvent(event);
|
|
710
|
+
}
|
|
711
|
+
mouseUp(button = 0) {
|
|
712
|
+
const event = new this.win.MouseEvent("mouseup", {
|
|
713
|
+
button,
|
|
714
|
+
bubbles: true,
|
|
715
|
+
cancelable: true,
|
|
716
|
+
view: this.win
|
|
717
|
+
});
|
|
718
|
+
const target = this.doc.pointerLockElement || this.doc;
|
|
719
|
+
target.dispatchEvent(event);
|
|
720
|
+
}
|
|
721
|
+
wheel(deltaY) {
|
|
722
|
+
const event = new this.win.WheelEvent("wheel", {
|
|
723
|
+
deltaY,
|
|
724
|
+
bubbles: true,
|
|
725
|
+
cancelable: true,
|
|
726
|
+
view: this.win
|
|
727
|
+
});
|
|
728
|
+
const target = this.doc.pointerLockElement || this.doc;
|
|
729
|
+
target.dispatchEvent(event);
|
|
730
|
+
}
|
|
731
|
+
};
|
|
393
732
|
export {
|
|
733
|
+
InputInjector,
|
|
734
|
+
MockPointerLock,
|
|
394
735
|
createBinaryStreamMock,
|
|
395
736
|
createBinaryWriterMock,
|
|
396
737
|
createEntity,
|
|
@@ -398,6 +739,7 @@ export {
|
|
|
398
739
|
createGameStateSnapshotFactory,
|
|
399
740
|
createMockEngine,
|
|
400
741
|
createMockGame,
|
|
742
|
+
createMockWebGL2Context,
|
|
401
743
|
createNetChanMock,
|
|
402
744
|
createPlayerStateFactory,
|
|
403
745
|
createSpawnContext,
|
|
@@ -411,6 +753,9 @@ export {
|
|
|
411
753
|
makeLeafModel,
|
|
412
754
|
makeNode,
|
|
413
755
|
makePlane,
|
|
414
|
-
|
|
756
|
+
setupBrowserEnvironment,
|
|
757
|
+
setupNodeEnvironment,
|
|
758
|
+
stairTrace,
|
|
759
|
+
teardownBrowserEnvironment
|
|
415
760
|
};
|
|
416
761
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/shared/mocks.ts","../src/shared/bsp.ts","../src/game/factories.ts","../src/game/helpers.ts"],"sourcesContent":["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":"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","names":["vi"]}
|
|
1
|
+
{"version":3,"sources":["../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":["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":["vi","options","canvas"]}
|