quake2ts 0.0.581 → 0.0.584

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.
@@ -56,7 +56,6 @@ __export(index_exports, {
56
56
  createMockAI: () => createMockAI,
57
57
  createMockAmmoItem: () => createMockAmmoItem,
58
58
  createMockArmorItem: () => createMockArmorItem,
59
- createMockAudioContext: () => createMockAudioContext,
60
59
  createMockCamera: () => createMockCamera,
61
60
  createMockCanvas: () => createMockCanvas,
62
61
  createMockCanvasContext2D: () => createMockCanvasContext2D,
@@ -92,6 +91,7 @@ __export(index_exports, {
92
91
  createMockRConClient: () => createMockRConClient,
93
92
  createMockRateLimiter: () => createMockRateLimiter,
94
93
  createMockRefDef: () => createMockRefDef,
94
+ createMockRenderingContext: () => createMockRenderingContext,
95
95
  createMockServer: () => createMockServer,
96
96
  createMockServerClient: () => createMockServerClient,
97
97
  createMockServerConsole: () => createMockServerConsole,
@@ -141,7 +141,6 @@ __export(index_exports, {
141
141
  simulateBandwidthLimit: () => simulateBandwidthLimit,
142
142
  simulateCameraMovement: () => simulateCameraMovement,
143
143
  simulateFrames: () => simulateFrames,
144
- simulateFramesWithMock: () => simulateFramesWithMock,
145
144
  simulateHandshake: () => simulateHandshake,
146
145
  simulateNetworkCondition: () => simulateNetworkCondition,
147
146
  simulatePlayerInput: () => simulatePlayerInput,
@@ -154,6 +153,7 @@ __export(index_exports, {
154
153
  stairTrace: () => import_shared3.stairTrace,
155
154
  teardownBrowserEnvironment: () => teardownBrowserEnvironment,
156
155
  teardownMockAudioContext: () => teardownMockAudioContext,
156
+ teardownNodeEnvironment: () => teardownNodeEnvironment,
157
157
  throttleBandwidth: () => throttleBandwidth,
158
158
  verifySnapshotConsistency: () => verifySnapshotConsistency,
159
159
  waitForGameReady: () => waitForGameReady
@@ -2056,75 +2056,92 @@ function createMockCanvas(width = 300, height = 150) {
2056
2056
  canvas2.height = height;
2057
2057
  return canvas2;
2058
2058
  }
2059
- const canvas = new import_canvas2.Canvas(width, height);
2060
- const originalGetContext = canvas.getContext.bind(canvas);
2061
- canvas.getContext = function(contextId, options) {
2062
- if (contextId === "webgl2") {
2063
- return createMockWebGL2Context(canvas);
2064
- }
2065
- if (contextId === "2d") {
2066
- return originalGetContext("2d", options);
2067
- }
2068
- return originalGetContext(contextId, options);
2059
+ const napiCanvas = new import_canvas2.Canvas(width, height);
2060
+ const canvas = {
2061
+ width,
2062
+ height,
2063
+ getContext: (contextId, options) => {
2064
+ if (contextId === "2d") {
2065
+ return napiCanvas.getContext("2d", options);
2066
+ }
2067
+ if (contextId === "webgl2") {
2068
+ return createMockWebGL2Context(canvas);
2069
+ }
2070
+ return null;
2071
+ },
2072
+ toDataURL: () => napiCanvas.toDataURL(),
2073
+ toBuffer: (mime) => napiCanvas.toBuffer(mime)
2074
+ // Add other properties as needed
2069
2075
  };
2070
2076
  return canvas;
2071
2077
  }
2072
2078
  function createMockCanvasContext2D(canvas) {
2073
- if (!canvas) {
2074
- canvas = createMockCanvas();
2079
+ const c = canvas || createMockCanvas();
2080
+ const ctx = c.getContext("2d");
2081
+ if (!ctx) {
2082
+ throw new Error("Failed to create 2D context");
2075
2083
  }
2076
- return canvas.getContext("2d");
2084
+ return ctx;
2077
2085
  }
2078
2086
  function captureCanvasDrawCalls(context) {
2079
- const drawCalls = [];
2080
- const methodsToSpy = [
2081
- "fillRect",
2082
- "strokeRect",
2083
- "clearRect",
2084
- "fillText",
2085
- "strokeText",
2086
- "drawImage",
2087
- "beginPath",
2088
- "closePath",
2089
- "moveTo",
2090
- "lineTo",
2091
- "arc",
2092
- "arcTo",
2093
- "bezierCurveTo",
2094
- "quadraticCurveTo",
2095
- "stroke",
2096
- "fill",
2097
- "putImageData"
2098
- ];
2099
- methodsToSpy.forEach((method) => {
2100
- const original = context[method];
2101
- if (typeof original === "function") {
2102
- context[method] = function(...args) {
2103
- drawCalls.push({ method, args });
2104
- return original.apply(this, args);
2087
+ const calls = [];
2088
+ const proto = Object.getPrototypeOf(context);
2089
+ for (const key of Object.getOwnPropertyNames(proto)) {
2090
+ const value = context[key];
2091
+ if (typeof value === "function") {
2092
+ context[key] = function(...args) {
2093
+ calls.push({ method: key, args });
2094
+ return value.apply(context, args);
2105
2095
  };
2106
2096
  }
2107
- });
2108
- return drawCalls;
2097
+ }
2098
+ return calls;
2109
2099
  }
2110
2100
  function createMockImageData(width, height, fillColor) {
2111
- const imageData = new import_canvas2.ImageData(width, height);
2101
+ if (typeof global.ImageData !== "undefined") {
2102
+ const data2 = new Uint8ClampedArray(width * height * 4);
2103
+ if (fillColor) {
2104
+ for (let i = 0; i < data2.length; i += 4) {
2105
+ data2[i] = fillColor[0];
2106
+ data2[i + 1] = fillColor[1];
2107
+ data2[i + 2] = fillColor[2];
2108
+ data2[i + 3] = fillColor[3];
2109
+ }
2110
+ }
2111
+ return new global.ImageData(data2, width, height);
2112
+ }
2113
+ const data = new Uint8ClampedArray(width * height * 4);
2112
2114
  if (fillColor) {
2113
- const [r, g, b, a] = fillColor;
2114
- for (let i = 0; i < imageData.data.length; i += 4) {
2115
- imageData.data[i] = r;
2116
- imageData.data[i + 1] = g;
2117
- imageData.data[i + 2] = b;
2118
- imageData.data[i + 3] = a;
2115
+ for (let i = 0; i < data.length; i += 4) {
2116
+ data[i] = fillColor[0];
2117
+ data[i + 1] = fillColor[1];
2118
+ data[i + 2] = fillColor[2];
2119
+ data[i + 3] = fillColor[3];
2119
2120
  }
2120
2121
  }
2121
- return imageData;
2122
+ return new import_canvas2.ImageData(data, width, height);
2122
2123
  }
2123
- function createMockImage(width, height, src) {
2124
- const img = new import_canvas2.Image();
2125
- if (width) img.width = width;
2126
- if (height) img.height = height;
2127
- if (src) img.src = src;
2124
+ function createMockImage(width = 100, height = 100, src = "") {
2125
+ if (typeof document !== "undefined" && document.createElement) {
2126
+ const img2 = document.createElement("img");
2127
+ img2.width = width;
2128
+ img2.height = height;
2129
+ if (src) img2.src = src;
2130
+ return img2;
2131
+ }
2132
+ const img = {
2133
+ width,
2134
+ height,
2135
+ src,
2136
+ complete: true,
2137
+ onload: null,
2138
+ onerror: null
2139
+ };
2140
+ if (src) {
2141
+ setTimeout(() => {
2142
+ if (img.onload) img.onload();
2143
+ }, 0);
2144
+ }
2128
2145
  return img;
2129
2146
  }
2130
2147
 
@@ -2192,376 +2209,285 @@ function setupWebGPUMocks() {
2192
2209
  }
2193
2210
 
2194
2211
  // src/setup/timing.ts
2195
- var activeMockRAF;
2196
2212
  function createMockRAF() {
2197
2213
  let callbacks = [];
2198
- let nextId = 1;
2214
+ let lastId = 0;
2199
2215
  let currentTime = 0;
2200
2216
  const originalRAF = global.requestAnimationFrame;
2201
2217
  const originalCancelRAF = global.cancelAnimationFrame;
2202
- const raf = (callback) => {
2203
- const id = nextId++;
2204
- callbacks.push({ id, callback });
2205
- return id;
2218
+ global.requestAnimationFrame = (callback) => {
2219
+ lastId++;
2220
+ callbacks.push({ id: lastId, callback });
2221
+ return lastId;
2206
2222
  };
2207
- const cancel = (id) => {
2223
+ global.cancelAnimationFrame = (id) => {
2208
2224
  callbacks = callbacks.filter((cb) => cb.id !== id);
2209
2225
  };
2210
- const mock = {
2211
- tick(timestamp) {
2212
- if (typeof timestamp !== "number") {
2213
- currentTime += 16.6;
2214
- } else {
2215
- currentTime = timestamp;
2216
- }
2226
+ return {
2227
+ tick(time) {
2228
+ if (time) currentTime = time;
2229
+ else currentTime += 16.66;
2217
2230
  const currentCallbacks = [...callbacks];
2218
2231
  callbacks = [];
2219
- currentCallbacks.forEach(({ callback }) => {
2220
- callback(currentTime);
2221
- });
2232
+ currentCallbacks.forEach((cb) => cb.callback(currentTime));
2222
2233
  },
2223
- advance(deltaMs = 16.6) {
2224
- this.tick(currentTime + deltaMs);
2234
+ advance(ms) {
2235
+ currentTime += ms;
2236
+ this.tick(currentTime);
2225
2237
  },
2226
2238
  getCallbacks() {
2227
- return callbacks.map((c) => c.callback);
2228
- },
2229
- reset() {
2230
- callbacks = [];
2231
- nextId = 1;
2232
- currentTime = 0;
2233
- },
2234
- enable() {
2235
- activeMockRAF = this;
2236
- global.requestAnimationFrame = raf;
2237
- global.cancelAnimationFrame = cancel;
2238
- },
2239
- disable() {
2240
- if (activeMockRAF === this) {
2241
- activeMockRAF = void 0;
2242
- }
2243
- if (originalRAF) {
2244
- global.requestAnimationFrame = originalRAF;
2245
- } else {
2246
- delete global.requestAnimationFrame;
2247
- }
2248
- if (originalCancelRAF) {
2249
- global.cancelAnimationFrame = originalCancelRAF;
2250
- } else {
2251
- delete global.cancelAnimationFrame;
2252
- }
2239
+ return callbacks;
2253
2240
  }
2254
2241
  };
2255
- return mock;
2256
2242
  }
2257
2243
  function createMockPerformance(startTime = 0) {
2258
- let currentTime = startTime;
2259
- const mockPerf = {
2260
- now: () => currentTime,
2244
+ let now = startTime;
2245
+ const mockPerformance = {
2246
+ now: () => now,
2261
2247
  timeOrigin: startTime,
2262
2248
  timing: {
2263
2249
  navigationStart: startTime
2264
2250
  },
2265
- clearMarks: () => {
2266
- },
2267
- clearMeasures: () => {
2251
+ mark: (_name) => {
2268
2252
  },
2269
- clearResourceTimings: () => {
2253
+ measure: (_name, _start, _end) => {
2270
2254
  },
2271
2255
  getEntries: () => [],
2272
- getEntriesByName: () => [],
2273
- getEntriesByType: () => [],
2274
- mark: () => {
2275
- },
2276
- measure: () => {
2256
+ getEntriesByName: (_name) => [],
2257
+ getEntriesByType: (_type) => [],
2258
+ clearMarks: (_name) => {
2277
2259
  },
2278
- setResourceTimingBufferSize: () => {
2260
+ clearMeasures: (_name) => {
2279
2261
  },
2280
- toJSON: () => ({}),
2281
- addEventListener: () => {
2262
+ clearResourceTimings: () => {
2282
2263
  },
2283
- removeEventListener: () => {
2264
+ setResourceTimingBufferSize: (_maxSize) => {
2284
2265
  },
2285
- dispatchEvent: () => true
2286
- };
2287
- mockPerf.advance = (deltaMs) => {
2288
- currentTime += deltaMs;
2289
- };
2290
- mockPerf.setTime = (time) => {
2291
- currentTime = time;
2266
+ onresourcetimingbufferfull: null,
2267
+ toJSON: () => ({})
2292
2268
  };
2293
- return mockPerf;
2269
+ if (typeof global.performance === "undefined") {
2270
+ global.performance = mockPerformance;
2271
+ }
2272
+ return mockPerformance;
2294
2273
  }
2295
2274
  function createControlledTimer() {
2296
- let currentTime = 0;
2297
- let timers = [];
2298
- let nextId = 1;
2299
- const originalSetTimeout = global.setTimeout;
2300
- const originalClearTimeout = global.clearTimeout;
2301
- const originalSetInterval = global.setInterval;
2302
- const originalClearInterval = global.clearInterval;
2303
- const mockSetTimeout = (callback, delay = 0, ...args) => {
2304
- const id = nextId++;
2305
- timers.push({ id, callback, dueTime: currentTime + delay, args });
2306
- return id;
2307
- };
2308
- const mockClearTimeout = (id) => {
2309
- timers = timers.filter((t) => t.id !== id);
2310
- };
2311
- const mockSetInterval = (callback, delay = 0, ...args) => {
2312
- const id = nextId++;
2313
- timers.push({ id, callback, dueTime: currentTime + delay, interval: delay, args });
2314
- return id;
2315
- };
2316
- const mockClearInterval = (id) => {
2317
- timers = timers.filter((t) => t.id !== id);
2318
- };
2319
- global.setTimeout = mockSetTimeout;
2320
- global.clearTimeout = mockClearTimeout;
2321
- global.setInterval = mockSetInterval;
2322
- global.clearInterval = mockClearInterval;
2275
+ console.warn("createControlledTimer: Recommend using vi.useFakeTimers() instead.");
2323
2276
  return {
2324
- tick() {
2325
- this.advanceBy(0);
2326
- },
2327
- advanceBy(ms) {
2328
- const targetTime = currentTime + ms;
2329
- while (true) {
2330
- let earliest = null;
2331
- for (const t of timers) {
2332
- if (!earliest || t.dueTime < earliest.dueTime) {
2333
- earliest = t;
2334
- }
2335
- }
2336
- if (!earliest || earliest.dueTime > targetTime) {
2337
- break;
2338
- }
2339
- currentTime = earliest.dueTime;
2340
- const { callback, args, interval, id } = earliest;
2341
- if (interval !== void 0) {
2342
- earliest.dueTime += interval;
2343
- if (interval === 0) earliest.dueTime += 1;
2344
- } else {
2345
- timers = timers.filter((t) => t.id !== id);
2346
- }
2347
- callback(...args);
2348
- }
2349
- currentTime = targetTime;
2277
+ advanceBy: (ms) => {
2350
2278
  },
2351
- clear() {
2352
- timers = [];
2279
+ runAll: () => {
2353
2280
  },
2354
- restore() {
2355
- global.setTimeout = originalSetTimeout;
2356
- global.clearTimeout = originalClearTimeout;
2357
- global.setInterval = originalSetInterval;
2358
- global.clearInterval = originalClearInterval;
2281
+ clear: () => {
2359
2282
  }
2360
2283
  };
2361
2284
  }
2362
- function simulateFrames(count, frameTimeMs = 16.6, callback) {
2363
- if (!activeMockRAF) {
2364
- throw new Error("simulateFrames requires an active MockRAF. Ensure createMockRAF().enable() is called.");
2365
- }
2366
- for (let i = 0; i < count; i++) {
2367
- if (callback) callback(i);
2368
- activeMockRAF.advance(frameTimeMs);
2369
- }
2370
- }
2371
- function simulateFramesWithMock(mock, count, frameTimeMs = 16.6, callback) {
2285
+ function simulateFrames(count, frameTime = 16, callback) {
2372
2286
  for (let i = 0; i < count; i++) {
2373
2287
  if (callback) callback(i);
2374
- mock.advance(frameTimeMs);
2375
2288
  }
2376
2289
  }
2377
2290
 
2378
2291
  // src/setup/node.ts
2379
2292
  function setupNodeEnvironment(options = {}) {
2380
- if (options.polyfillFetch && typeof global.fetch === "undefined") {
2381
- }
2293
+ }
2294
+ function teardownNodeEnvironment() {
2295
+ }
2296
+
2297
+ // src/engine/rendering.ts
2298
+ var import_vitest12 = require("vitest");
2299
+ function createMockRenderingContext() {
2300
+ const gl = createMockWebGL2Context();
2301
+ const camera = {
2302
+ update: import_vitest12.vi.fn(),
2303
+ getViewMatrix: import_vitest12.vi.fn().mockReturnValue(new Float32Array(16)),
2304
+ getProjectionMatrix: import_vitest12.vi.fn().mockReturnValue(new Float32Array(16)),
2305
+ getViewProjectionMatrix: import_vitest12.vi.fn().mockReturnValue(new Float32Array(16)),
2306
+ getPosition: import_vitest12.vi.fn().mockReturnValue([0, 0, 0]),
2307
+ getForward: import_vitest12.vi.fn().mockReturnValue([0, 0, -1]),
2308
+ getRight: import_vitest12.vi.fn().mockReturnValue([1, 0, 0]),
2309
+ getUp: import_vitest12.vi.fn().mockReturnValue([0, 1, 0]),
2310
+ extractFrustumPlanes: import_vitest12.vi.fn(),
2311
+ transform: {
2312
+ origin: [0, 0, 0],
2313
+ angles: [0, 0, 0],
2314
+ fov: 90
2315
+ }
2316
+ };
2317
+ const md2 = {
2318
+ render: import_vitest12.vi.fn(),
2319
+ init: import_vitest12.vi.fn(),
2320
+ resize: import_vitest12.vi.fn()
2321
+ };
2322
+ const bsp = {
2323
+ render: import_vitest12.vi.fn(),
2324
+ init: import_vitest12.vi.fn(),
2325
+ resize: import_vitest12.vi.fn()
2326
+ };
2327
+ const sprite = {
2328
+ render: import_vitest12.vi.fn(),
2329
+ init: import_vitest12.vi.fn(),
2330
+ resize: import_vitest12.vi.fn()
2331
+ };
2332
+ const poly = {
2333
+ render: import_vitest12.vi.fn(),
2334
+ init: import_vitest12.vi.fn(),
2335
+ resize: import_vitest12.vi.fn()
2336
+ };
2337
+ const particle = {
2338
+ render: import_vitest12.vi.fn(),
2339
+ init: import_vitest12.vi.fn(),
2340
+ resize: import_vitest12.vi.fn()
2341
+ };
2342
+ return {
2343
+ gl,
2344
+ camera,
2345
+ pipelines: {
2346
+ md2,
2347
+ bsp,
2348
+ sprite,
2349
+ poly,
2350
+ particle
2351
+ }
2352
+ };
2382
2353
  }
2383
2354
 
2384
2355
  // src/setup/storage.ts
2385
- var import_auto2 = require("fake-indexeddb/auto");
2386
- function createMockLocalStorage(initialData = {}) {
2387
- const storage = new Map(Object.entries(initialData));
2356
+ function createStorageMock(initialData = {}) {
2357
+ const store = new Map(Object.entries(initialData));
2388
2358
  return {
2389
- getItem: (key) => storage.get(key) || null,
2390
- setItem: (key, value) => storage.set(key, value),
2391
- removeItem: (key) => storage.delete(key),
2392
- clear: () => storage.clear(),
2393
- key: (index) => Array.from(storage.keys())[index] || null,
2359
+ getItem: (key) => store.get(key) || null,
2360
+ setItem: (key, value) => store.set(key, value.toString()),
2361
+ removeItem: (key) => store.delete(key),
2362
+ clear: () => store.clear(),
2363
+ key: (index) => Array.from(store.keys())[index] || null,
2394
2364
  get length() {
2395
- return storage.size;
2365
+ return store.size;
2396
2366
  }
2397
2367
  };
2398
2368
  }
2369
+ function createMockLocalStorage(initialData = {}) {
2370
+ return createStorageMock(initialData);
2371
+ }
2399
2372
  function createMockSessionStorage(initialData = {}) {
2400
- return createMockLocalStorage(initialData);
2373
+ return createStorageMock(initialData);
2401
2374
  }
2402
- function createMockIndexedDB() {
2403
- if (typeof indexedDB === "undefined") {
2404
- throw new Error("IndexedDB mock not found. Ensure fake-indexeddb is loaded.");
2405
- }
2406
- return indexedDB;
2375
+ function createMockIndexedDB(databases) {
2376
+ return global.indexedDB;
2407
2377
  }
2408
2378
  function createStorageTestScenario(storageType = "local") {
2409
- if (storageType === "indexed") {
2410
- const dbName = `test-db-${Math.random().toString(36).substring(7)}`;
2411
- const storeName = "test-store";
2412
- const storage2 = createMockIndexedDB();
2413
- return {
2414
- storage: storage2,
2415
- populate: async (data) => {
2416
- return new Promise((resolve, reject) => {
2417
- const req = storage2.open(dbName, 1);
2418
- req.onupgradeneeded = (e) => {
2419
- const db = e.target.result;
2420
- db.createObjectStore(storeName);
2421
- };
2422
- req.onsuccess = (e) => {
2423
- const db = e.target.result;
2424
- const tx = db.transaction(storeName, "readwrite");
2425
- const store = tx.objectStore(storeName);
2426
- Object.entries(data).forEach(([k, v]) => store.put(v, k));
2427
- tx.oncomplete = () => {
2428
- db.close();
2429
- resolve();
2430
- };
2431
- tx.onerror = () => reject(tx.error);
2432
- };
2433
- req.onerror = () => reject(req.error);
2434
- });
2435
- },
2436
- verify: async (key, value) => {
2437
- return new Promise((resolve, reject) => {
2438
- const req = storage2.open(dbName, 1);
2439
- req.onsuccess = (e) => {
2440
- const db = e.target.result;
2441
- if (!db.objectStoreNames.contains(storeName)) {
2442
- db.close();
2443
- resolve(false);
2444
- return;
2445
- }
2446
- const tx = db.transaction(storeName, "readonly");
2447
- const store = tx.objectStore(storeName);
2448
- const getReq = store.get(key);
2449
- getReq.onsuccess = () => {
2450
- const result = getReq.result === value;
2451
- db.close();
2452
- resolve(result);
2453
- };
2454
- getReq.onerror = () => {
2455
- db.close();
2456
- resolve(false);
2457
- };
2458
- };
2459
- req.onerror = () => reject(req.error);
2460
- });
2461
- }
2462
- };
2463
- }
2464
- const storage = storageType === "local" ? createMockLocalStorage() : createMockSessionStorage();
2465
2379
  return {
2466
- storage,
2467
- populate(data) {
2468
- Object.entries(data).forEach(([k, v]) => storage.setItem(k, v));
2469
- },
2470
- verify(key, value) {
2471
- return storage.getItem(key) === value;
2472
- }
2380
+ localStorage: createMockLocalStorage(),
2381
+ sessionStorage: createMockSessionStorage(),
2382
+ indexedDB: createMockIndexedDB()
2473
2383
  };
2474
2384
  }
2475
2385
 
2476
2386
  // src/setup/audio.ts
2477
- function createMockAudioContext() {
2478
- const context = {
2479
- createGain: () => ({
2480
- connect: () => {
2481
- },
2482
- gain: { value: 1, setValueAtTime: () => {
2483
- } }
2484
- }),
2485
- createOscillator: () => ({
2486
- connect: () => {
2487
- },
2488
- start: () => {
2489
- },
2490
- stop: () => {
2491
- },
2492
- frequency: { value: 440 }
2493
- }),
2494
- createBufferSource: () => ({
2495
- connect: () => {
2496
- },
2497
- start: () => {
2498
- },
2499
- stop: () => {
2500
- },
2501
- buffer: null,
2502
- playbackRate: { value: 1 },
2503
- loop: false
2504
- }),
2505
- destination: {},
2506
- currentTime: 0,
2507
- state: "running",
2508
- resume: async () => {
2509
- },
2510
- suspend: async () => {
2511
- },
2512
- close: async () => {
2513
- },
2514
- decodeAudioData: async (buffer) => ({
2515
- duration: 1,
2516
- length: 44100,
2517
- sampleRate: 44100,
2518
- numberOfChannels: 2,
2519
- getChannelData: () => new Float32Array(44100)
2520
- }),
2521
- createBuffer: (channels, length2, sampleRate) => ({
2522
- duration: length2 / sampleRate,
2523
- length: length2,
2524
- sampleRate,
2525
- numberOfChannels: channels,
2526
- getChannelData: () => new Float32Array(length2)
2527
- }),
2528
- // Helper to track events if needed
2529
- _events: []
2530
- };
2531
- return new Proxy(context, {
2532
- get(target, prop, receiver) {
2533
- if (prop === "_events") return target._events;
2534
- const value = Reflect.get(target, prop, receiver);
2535
- if (typeof value === "function") {
2536
- return (...args) => {
2537
- target._events.push({ type: String(prop), args });
2538
- return Reflect.apply(value, target, args);
2539
- };
2540
- }
2541
- return value;
2542
- }
2543
- });
2544
- }
2545
2387
  function setupMockAudioContext() {
2546
- if (typeof global.AudioContext === "undefined" && typeof global.window !== "undefined") {
2547
- global.AudioContext = class {
2548
- constructor() {
2549
- return createMockAudioContext();
2550
- }
2551
- };
2552
- global.window.AudioContext = global.AudioContext;
2553
- global.window.webkitAudioContext = global.AudioContext;
2388
+ class MockAudioContext {
2389
+ constructor() {
2390
+ this.state = "suspended";
2391
+ this.destination = {};
2392
+ this.currentTime = 0;
2393
+ this.listener = {
2394
+ positionX: { value: 0 },
2395
+ positionY: { value: 0 },
2396
+ positionZ: { value: 0 },
2397
+ forwardX: { value: 0 },
2398
+ forwardY: { value: 0 },
2399
+ forwardZ: { value: 0 },
2400
+ upX: { value: 0 },
2401
+ upY: { value: 0 },
2402
+ upZ: { value: 0 },
2403
+ setOrientation: () => {
2404
+ },
2405
+ setPosition: () => {
2406
+ }
2407
+ };
2408
+ }
2409
+ createGain() {
2410
+ return {
2411
+ gain: { value: 1, linearRampToValueAtTime: () => {
2412
+ } },
2413
+ connect: () => {
2414
+ },
2415
+ disconnect: () => {
2416
+ }
2417
+ };
2418
+ }
2419
+ createBufferSource() {
2420
+ return {
2421
+ buffer: null,
2422
+ loop: false,
2423
+ playbackRate: { value: 1 },
2424
+ connect: () => {
2425
+ },
2426
+ start: () => {
2427
+ },
2428
+ stop: () => {
2429
+ },
2430
+ disconnect: () => {
2431
+ },
2432
+ onended: null
2433
+ };
2434
+ }
2435
+ createPanner() {
2436
+ return {
2437
+ panningModel: "equalpower",
2438
+ distanceModel: "inverse",
2439
+ positionX: { value: 0 },
2440
+ positionY: { value: 0 },
2441
+ positionZ: { value: 0 },
2442
+ orientationX: { value: 0 },
2443
+ orientationY: { value: 0 },
2444
+ orientationZ: { value: 0 },
2445
+ coneInnerAngle: 360,
2446
+ coneOuterAngle: 360,
2447
+ coneOuterGain: 0,
2448
+ connect: () => {
2449
+ },
2450
+ disconnect: () => {
2451
+ },
2452
+ setPosition: () => {
2453
+ },
2454
+ setOrientation: () => {
2455
+ }
2456
+ };
2457
+ }
2458
+ createBuffer(numOfChannels, length2, sampleRate) {
2459
+ return {
2460
+ duration: length2 / sampleRate,
2461
+ length: length2,
2462
+ sampleRate,
2463
+ numberOfChannels: numOfChannels,
2464
+ getChannelData: () => new Float32Array(length2)
2465
+ };
2466
+ }
2467
+ decodeAudioData(data, success) {
2468
+ const buffer = this.createBuffer(2, 100, 44100);
2469
+ if (success) success(buffer);
2470
+ return Promise.resolve(buffer);
2471
+ }
2472
+ resume() {
2473
+ return Promise.resolve();
2474
+ }
2475
+ suspend() {
2476
+ return Promise.resolve();
2477
+ }
2478
+ close() {
2479
+ return Promise.resolve();
2480
+ }
2554
2481
  }
2482
+ global.AudioContext = MockAudioContext;
2483
+ global.webkitAudioContext = MockAudioContext;
2555
2484
  }
2556
2485
  function teardownMockAudioContext() {
2557
- if (global.AudioContext && global.AudioContext.toString().includes("class")) {
2558
- delete global.AudioContext;
2559
- delete global.window.AudioContext;
2560
- delete global.window.webkitAudioContext;
2561
- }
2486
+ delete global.AudioContext;
2487
+ delete global.webkitAudioContext;
2562
2488
  }
2563
2489
  function captureAudioEvents(context) {
2564
- return context._events || [];
2490
+ return [];
2565
2491
  }
2566
2492
 
2567
2493
  // ../../node_modules/.pnpm/gl-matrix@3.4.4/node_modules/gl-matrix/esm/common.js
@@ -3051,217 +2977,110 @@ function simulateCameraMovement(camera, input, deltaTime) {
3051
2977
  }
3052
2978
 
3053
2979
  // src/e2e/playwright.ts
3054
- var import_playwright = require("playwright");
3055
- var import_http = require("http");
3056
- var import_serve_handler = __toESM(require("serve-handler"), 1);
3057
2980
  async function createPlaywrightTestClient(options = {}) {
3058
- let staticServer;
3059
- let clientUrl = options.clientUrl;
3060
- const rootPath = options.rootPath || process.cwd();
3061
- if (!clientUrl) {
3062
- staticServer = (0, import_http.createServer)((request, response) => {
3063
- return (0, import_serve_handler.default)(request, response, {
3064
- public: rootPath,
3065
- cleanUrls: false,
3066
- headers: [
3067
- {
3068
- source: "**/*",
3069
- headers: [
3070
- { key: "Cache-Control", value: "no-cache" },
3071
- { key: "Access-Control-Allow-Origin", value: "*" },
3072
- { key: "Cross-Origin-Opener-Policy", value: "same-origin" },
3073
- { key: "Cross-Origin-Embedder-Policy", value: "require-corp" }
3074
- ]
3075
- }
3076
- ]
3077
- });
3078
- });
3079
- await new Promise((resolve) => {
3080
- if (!staticServer) return;
3081
- staticServer.listen(0, () => {
3082
- const addr = staticServer?.address();
3083
- const port = typeof addr === "object" ? addr?.port : 0;
3084
- clientUrl = `http://localhost:${port}`;
3085
- console.log(`Test client serving from ${rootPath} at ${clientUrl}`);
3086
- resolve();
3087
- });
3088
- });
2981
+ let playwright;
2982
+ try {
2983
+ playwright = await import("playwright");
2984
+ } catch (e) {
2985
+ throw new Error("Playwright is not installed. Please install it to use this utility.");
3089
2986
  }
3090
- const browser = await import_playwright.chromium.launch({
3091
- headless: options.headless ?? true,
3092
- args: [
3093
- "--use-gl=egl",
3094
- "--ignore-gpu-blocklist",
3095
- ...options.launchOptions?.args || []
3096
- ],
3097
- ...options.launchOptions
2987
+ const browser = await playwright.chromium.launch({
2988
+ headless: options.headless ?? true
3098
2989
  });
3099
- const width = options.width || 1280;
3100
- const height = options.height || 720;
3101
2990
  const context = await browser.newContext({
3102
- viewport: { width, height },
3103
- deviceScaleFactor: 1,
3104
- ...options.contextOptions
2991
+ viewport: options.viewport || { width: 1280, height: 720 }
3105
2992
  });
3106
2993
  const page = await context.newPage();
3107
- const close = async () => {
3108
- await browser.close();
3109
- if (staticServer) {
3110
- staticServer.close();
3111
- }
3112
- };
3113
- const navigate = async (url) => {
3114
- const targetUrl = url || clientUrl;
3115
- if (!targetUrl) throw new Error("No URL to navigate to");
3116
- let finalUrl = targetUrl;
3117
- if (options.serverUrl && !targetUrl.includes("connect=")) {
3118
- const separator = targetUrl.includes("?") ? "&" : "?";
3119
- finalUrl = `${targetUrl}${separator}connect=${encodeURIComponent(options.serverUrl)}`;
3120
- }
3121
- console.log(`Navigating to: ${finalUrl}`);
3122
- await page.goto(finalUrl, { waitUntil: "domcontentloaded" });
3123
- };
3124
2994
  return {
3125
- browser,
3126
- context,
3127
2995
  page,
3128
- server: staticServer,
3129
- close,
3130
- navigate,
3131
- waitForGame: async (timeout = 1e4) => {
3132
- await waitForGameReady(page, timeout);
2996
+ browser,
2997
+ async navigate(url) {
2998
+ await page.goto(url);
2999
+ },
3000
+ async waitForGame() {
3001
+ await waitForGameReady(page);
3133
3002
  },
3134
- injectInput: async (type, data) => {
3003
+ async injectInput(type, data) {
3135
3004
  await page.evaluate(({ type: type2, data: data2 }) => {
3136
- if (window.injectGameInput) window.injectGameInput(type2, data2);
3005
+ console.log("Injecting input", type2, data2);
3137
3006
  }, { type, data });
3007
+ },
3008
+ async screenshot(name) {
3009
+ return await page.screenshot({ path: `${name}.png` });
3010
+ },
3011
+ async close() {
3012
+ await browser.close();
3138
3013
  }
3139
3014
  };
3140
3015
  }
3141
3016
  async function waitForGameReady(page, timeout = 1e4) {
3142
- try {
3143
- await page.waitForFunction(() => {
3144
- return window.gameInstance && window.gameInstance.isReady;
3145
- }, null, { timeout });
3146
- } catch (e) {
3147
- await page.waitForSelector("canvas", { timeout });
3148
- }
3017
+ await page.waitForFunction(() => {
3018
+ return window.game && window.game.isRunning;
3019
+ }, { timeout });
3149
3020
  }
3150
3021
  async function captureGameState(page) {
3151
3022
  return await page.evaluate(() => {
3152
- if (window.gameInstance && window.gameInstance.getState) {
3153
- return window.gameInstance.getState();
3154
- }
3155
- return {};
3023
+ const game = window.game;
3024
+ return {
3025
+ time: game ? game.time : 0,
3026
+ entities: game && game.entities ? game.entities.length : 0
3027
+ };
3156
3028
  });
3157
3029
  }
3158
3030
 
3159
3031
  // src/e2e/network.ts
3160
- var CONDITIONS = {
3161
- "good": {
3162
- offline: false,
3163
- downloadThroughput: 10 * 1024 * 1024,
3164
- // 10 Mbps
3165
- uploadThroughput: 5 * 1024 * 1024,
3166
- // 5 Mbps
3167
- latency: 20
3168
- },
3169
- "slow": {
3170
- offline: false,
3171
- downloadThroughput: 500 * 1024,
3172
- // 500 Kbps
3173
- uploadThroughput: 500 * 1024,
3174
- latency: 400
3175
- },
3176
- "unstable": {
3177
- offline: false,
3178
- downloadThroughput: 1 * 1024 * 1024,
3179
- uploadThroughput: 1 * 1024 * 1024,
3180
- latency: 100
3181
- },
3182
- "offline": {
3183
- offline: true,
3184
- downloadThroughput: 0,
3185
- uploadThroughput: 0,
3186
- latency: 0
3187
- }
3188
- };
3189
3032
  function simulateNetworkCondition(condition) {
3190
- const config = CONDITIONS[condition];
3191
- return createCustomNetworkCondition(config.latency, 0, 0, config);
3192
- }
3193
- function createCustomNetworkCondition(latency, jitter = 0, packetLoss = 0, baseConfig) {
3033
+ switch (condition) {
3034
+ case "good":
3035
+ return { latency: 20, jitter: 5, packetLoss: 0, bandwidth: 10 * 1024 * 1024 };
3036
+ case "slow":
3037
+ return { latency: 150, jitter: 20, packetLoss: 0.01, bandwidth: 1 * 1024 * 1024 };
3038
+ case "unstable":
3039
+ return { latency: 100, jitter: 100, packetLoss: 0.05, bandwidth: 512 * 1024 };
3040
+ case "offline":
3041
+ return { latency: 0, jitter: 0, packetLoss: 1, bandwidth: 0 };
3042
+ case "custom":
3043
+ default:
3044
+ return { latency: 0, jitter: 0, packetLoss: 0, bandwidth: Infinity };
3045
+ }
3046
+ }
3047
+ function createCustomNetworkCondition(latency, jitter, packetLoss) {
3194
3048
  return {
3195
- async apply(page) {
3196
- const client = await page.context().newCDPSession(page);
3197
- await client.send("Network.enable");
3198
- await client.send("Network.emulateNetworkConditions", {
3199
- offline: baseConfig?.offline || false,
3200
- latency: latency + Math.random() * jitter,
3201
- downloadThroughput: baseConfig?.downloadThroughput || -1,
3202
- uploadThroughput: baseConfig?.uploadThroughput || -1
3203
- });
3204
- },
3205
- async clear(page) {
3206
- const client = await page.context().newCDPSession(page);
3207
- await client.send("Network.emulateNetworkConditions", {
3208
- offline: false,
3209
- latency: 0,
3210
- downloadThroughput: -1,
3211
- uploadThroughput: -1
3212
- });
3213
- }
3049
+ latency,
3050
+ jitter,
3051
+ packetLoss,
3052
+ bandwidth: Infinity
3053
+ // Default to unlimited unless specified
3214
3054
  };
3215
3055
  }
3216
- async function throttleBandwidth(page, bytesPerSecond) {
3217
- const simulator = createCustomNetworkCondition(0, 0, 0, {
3218
- offline: false,
3219
- latency: 0,
3220
- downloadThroughput: bytesPerSecond,
3221
- uploadThroughput: bytesPerSecond
3222
- });
3223
- await simulator.apply(page);
3056
+ function throttleBandwidth(bytesPerSecond) {
3224
3057
  }
3225
3058
 
3226
3059
  // src/e2e/visual.ts
3227
- var import_path = __toESM(require("path"), 1);
3228
- var import_promises = __toESM(require("fs/promises"), 1);
3229
- async function captureGameScreenshot(page, name, options = {}) {
3230
- const dir = options.dir || "__screenshots__";
3231
- const screenshotPath = import_path.default.join(dir, `${name}.png`);
3232
- await import_promises.default.mkdir(dir, { recursive: true });
3233
- return await page.screenshot({
3234
- path: screenshotPath,
3235
- fullPage: options.fullPage ?? false,
3236
- animations: "disabled",
3237
- caret: "hide"
3238
- });
3239
- }
3240
- async function compareScreenshots(baseline, current, threshold = 0.1) {
3241
- if (baseline.equals(current)) {
3242
- return { pixelDiff: 0, matched: true };
3060
+ async function captureGameScreenshot(page, name) {
3061
+ return await page.screenshot({ path: `${name}.png` });
3062
+ }
3063
+ function compareScreenshots(baseline, current, threshold = 0.01) {
3064
+ if (baseline.length !== current.length) {
3065
+ return { diffPercentage: 1 };
3066
+ }
3067
+ let diffPixels = 0;
3068
+ const totalPixels = baseline.length;
3069
+ for (let i = 0; i < baseline.length; i++) {
3070
+ if (baseline[i] !== current[i]) {
3071
+ diffPixels++;
3072
+ }
3243
3073
  }
3074
+ const diffPercentage = diffPixels / totalPixels;
3244
3075
  return {
3245
- pixelDiff: -1,
3246
- // Unknown magnitude
3247
- matched: false
3076
+ diffPercentage
3077
+ // Generating a diff image buffer would require a library like pixelmatch
3248
3078
  };
3249
3079
  }
3250
- function createVisualTestScenario(page, sceneName) {
3080
+ function createVisualTestScenario(sceneName) {
3251
3081
  return {
3252
- async capture(snapshotName) {
3253
- return await captureGameScreenshot(page, `${sceneName}-${snapshotName}`);
3254
- },
3255
- async compare(snapshotName, baselineDir) {
3256
- const name = `${sceneName}-${snapshotName}`;
3257
- const current = await captureGameScreenshot(page, name, { dir: "__screenshots__/current" });
3258
- try {
3259
- const baselinePath = import_path.default.join(baselineDir, `${name}.png`);
3260
- const baseline = await import_promises.default.readFile(baselinePath);
3261
- return await compareScreenshots(baseline, current);
3262
- } catch (e) {
3263
- return { pixelDiff: -1, matched: false };
3264
- }
3082
+ sceneName,
3083
+ setup: async () => {
3265
3084
  }
3266
3085
  };
3267
3086
  }
@@ -3293,7 +3112,6 @@ function createVisualTestScenario(page, sceneName) {
3293
3112
  createMockAI,
3294
3113
  createMockAmmoItem,
3295
3114
  createMockArmorItem,
3296
- createMockAudioContext,
3297
3115
  createMockCamera,
3298
3116
  createMockCanvas,
3299
3117
  createMockCanvasContext2D,
@@ -3329,6 +3147,7 @@ function createVisualTestScenario(page, sceneName) {
3329
3147
  createMockRConClient,
3330
3148
  createMockRateLimiter,
3331
3149
  createMockRefDef,
3150
+ createMockRenderingContext,
3332
3151
  createMockServer,
3333
3152
  createMockServerClient,
3334
3153
  createMockServerConsole,
@@ -3378,7 +3197,6 @@ function createVisualTestScenario(page, sceneName) {
3378
3197
  simulateBandwidthLimit,
3379
3198
  simulateCameraMovement,
3380
3199
  simulateFrames,
3381
- simulateFramesWithMock,
3382
3200
  simulateHandshake,
3383
3201
  simulateNetworkCondition,
3384
3202
  simulatePlayerInput,
@@ -3391,6 +3209,7 @@ function createVisualTestScenario(page, sceneName) {
3391
3209
  stairTrace,
3392
3210
  teardownBrowserEnvironment,
3393
3211
  teardownMockAudioContext,
3212
+ teardownNodeEnvironment,
3394
3213
  throttleBandwidth,
3395
3214
  verifySnapshotConsistency,
3396
3215
  waitForGameReady