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.
@@ -1912,7 +1912,7 @@ function teardownBrowserEnvironment() {
1912
1912
  }
1913
1913
 
1914
1914
  // src/setup/canvas.ts
1915
- import { Canvas as Canvas2, Image as Image2, ImageData as ImageData2 } from "@napi-rs/canvas";
1915
+ import { Canvas as Canvas2, ImageData as ImageData2 } from "@napi-rs/canvas";
1916
1916
  function createMockCanvas(width = 300, height = 150) {
1917
1917
  if (typeof document !== "undefined" && document.createElement) {
1918
1918
  const canvas2 = document.createElement("canvas");
@@ -1920,75 +1920,92 @@ function createMockCanvas(width = 300, height = 150) {
1920
1920
  canvas2.height = height;
1921
1921
  return canvas2;
1922
1922
  }
1923
- const canvas = new Canvas2(width, height);
1924
- const originalGetContext = canvas.getContext.bind(canvas);
1925
- canvas.getContext = function(contextId, options) {
1926
- if (contextId === "webgl2") {
1927
- return createMockWebGL2Context(canvas);
1928
- }
1929
- if (contextId === "2d") {
1930
- return originalGetContext("2d", options);
1931
- }
1932
- return originalGetContext(contextId, options);
1923
+ const napiCanvas = new Canvas2(width, height);
1924
+ const canvas = {
1925
+ width,
1926
+ height,
1927
+ getContext: (contextId, options) => {
1928
+ if (contextId === "2d") {
1929
+ return napiCanvas.getContext("2d", options);
1930
+ }
1931
+ if (contextId === "webgl2") {
1932
+ return createMockWebGL2Context(canvas);
1933
+ }
1934
+ return null;
1935
+ },
1936
+ toDataURL: () => napiCanvas.toDataURL(),
1937
+ toBuffer: (mime) => napiCanvas.toBuffer(mime)
1938
+ // Add other properties as needed
1933
1939
  };
1934
1940
  return canvas;
1935
1941
  }
1936
1942
  function createMockCanvasContext2D(canvas) {
1937
- if (!canvas) {
1938
- canvas = createMockCanvas();
1943
+ const c = canvas || createMockCanvas();
1944
+ const ctx = c.getContext("2d");
1945
+ if (!ctx) {
1946
+ throw new Error("Failed to create 2D context");
1939
1947
  }
1940
- return canvas.getContext("2d");
1948
+ return ctx;
1941
1949
  }
1942
1950
  function captureCanvasDrawCalls(context) {
1943
- const drawCalls = [];
1944
- const methodsToSpy = [
1945
- "fillRect",
1946
- "strokeRect",
1947
- "clearRect",
1948
- "fillText",
1949
- "strokeText",
1950
- "drawImage",
1951
- "beginPath",
1952
- "closePath",
1953
- "moveTo",
1954
- "lineTo",
1955
- "arc",
1956
- "arcTo",
1957
- "bezierCurveTo",
1958
- "quadraticCurveTo",
1959
- "stroke",
1960
- "fill",
1961
- "putImageData"
1962
- ];
1963
- methodsToSpy.forEach((method) => {
1964
- const original = context[method];
1965
- if (typeof original === "function") {
1966
- context[method] = function(...args) {
1967
- drawCalls.push({ method, args });
1968
- return original.apply(this, args);
1951
+ const calls = [];
1952
+ const proto = Object.getPrototypeOf(context);
1953
+ for (const key of Object.getOwnPropertyNames(proto)) {
1954
+ const value = context[key];
1955
+ if (typeof value === "function") {
1956
+ context[key] = function(...args) {
1957
+ calls.push({ method: key, args });
1958
+ return value.apply(context, args);
1969
1959
  };
1970
1960
  }
1971
- });
1972
- return drawCalls;
1961
+ }
1962
+ return calls;
1973
1963
  }
1974
1964
  function createMockImageData(width, height, fillColor) {
1975
- const imageData = new ImageData2(width, height);
1965
+ if (typeof global.ImageData !== "undefined") {
1966
+ const data2 = new Uint8ClampedArray(width * height * 4);
1967
+ if (fillColor) {
1968
+ for (let i = 0; i < data2.length; i += 4) {
1969
+ data2[i] = fillColor[0];
1970
+ data2[i + 1] = fillColor[1];
1971
+ data2[i + 2] = fillColor[2];
1972
+ data2[i + 3] = fillColor[3];
1973
+ }
1974
+ }
1975
+ return new global.ImageData(data2, width, height);
1976
+ }
1977
+ const data = new Uint8ClampedArray(width * height * 4);
1976
1978
  if (fillColor) {
1977
- const [r, g, b, a] = fillColor;
1978
- for (let i = 0; i < imageData.data.length; i += 4) {
1979
- imageData.data[i] = r;
1980
- imageData.data[i + 1] = g;
1981
- imageData.data[i + 2] = b;
1982
- imageData.data[i + 3] = a;
1979
+ for (let i = 0; i < data.length; i += 4) {
1980
+ data[i] = fillColor[0];
1981
+ data[i + 1] = fillColor[1];
1982
+ data[i + 2] = fillColor[2];
1983
+ data[i + 3] = fillColor[3];
1983
1984
  }
1984
1985
  }
1985
- return imageData;
1986
+ return new ImageData2(data, width, height);
1986
1987
  }
1987
- function createMockImage(width, height, src) {
1988
- const img = new Image2();
1989
- if (width) img.width = width;
1990
- if (height) img.height = height;
1991
- if (src) img.src = src;
1988
+ function createMockImage(width = 100, height = 100, src = "") {
1989
+ if (typeof document !== "undefined" && document.createElement) {
1990
+ const img2 = document.createElement("img");
1991
+ img2.width = width;
1992
+ img2.height = height;
1993
+ if (src) img2.src = src;
1994
+ return img2;
1995
+ }
1996
+ const img = {
1997
+ width,
1998
+ height,
1999
+ src,
2000
+ complete: true,
2001
+ onload: null,
2002
+ onerror: null
2003
+ };
2004
+ if (src) {
2005
+ setTimeout(() => {
2006
+ if (img.onload) img.onload();
2007
+ }, 0);
2008
+ }
1992
2009
  return img;
1993
2010
  }
1994
2011
 
@@ -2056,376 +2073,285 @@ function setupWebGPUMocks() {
2056
2073
  }
2057
2074
 
2058
2075
  // src/setup/timing.ts
2059
- var activeMockRAF;
2060
2076
  function createMockRAF() {
2061
2077
  let callbacks = [];
2062
- let nextId = 1;
2078
+ let lastId = 0;
2063
2079
  let currentTime = 0;
2064
2080
  const originalRAF = global.requestAnimationFrame;
2065
2081
  const originalCancelRAF = global.cancelAnimationFrame;
2066
- const raf = (callback) => {
2067
- const id = nextId++;
2068
- callbacks.push({ id, callback });
2069
- return id;
2082
+ global.requestAnimationFrame = (callback) => {
2083
+ lastId++;
2084
+ callbacks.push({ id: lastId, callback });
2085
+ return lastId;
2070
2086
  };
2071
- const cancel = (id) => {
2087
+ global.cancelAnimationFrame = (id) => {
2072
2088
  callbacks = callbacks.filter((cb) => cb.id !== id);
2073
2089
  };
2074
- const mock = {
2075
- tick(timestamp) {
2076
- if (typeof timestamp !== "number") {
2077
- currentTime += 16.6;
2078
- } else {
2079
- currentTime = timestamp;
2080
- }
2090
+ return {
2091
+ tick(time) {
2092
+ if (time) currentTime = time;
2093
+ else currentTime += 16.66;
2081
2094
  const currentCallbacks = [...callbacks];
2082
2095
  callbacks = [];
2083
- currentCallbacks.forEach(({ callback }) => {
2084
- callback(currentTime);
2085
- });
2096
+ currentCallbacks.forEach((cb) => cb.callback(currentTime));
2086
2097
  },
2087
- advance(deltaMs = 16.6) {
2088
- this.tick(currentTime + deltaMs);
2098
+ advance(ms) {
2099
+ currentTime += ms;
2100
+ this.tick(currentTime);
2089
2101
  },
2090
2102
  getCallbacks() {
2091
- return callbacks.map((c) => c.callback);
2092
- },
2093
- reset() {
2094
- callbacks = [];
2095
- nextId = 1;
2096
- currentTime = 0;
2097
- },
2098
- enable() {
2099
- activeMockRAF = this;
2100
- global.requestAnimationFrame = raf;
2101
- global.cancelAnimationFrame = cancel;
2102
- },
2103
- disable() {
2104
- if (activeMockRAF === this) {
2105
- activeMockRAF = void 0;
2106
- }
2107
- if (originalRAF) {
2108
- global.requestAnimationFrame = originalRAF;
2109
- } else {
2110
- delete global.requestAnimationFrame;
2111
- }
2112
- if (originalCancelRAF) {
2113
- global.cancelAnimationFrame = originalCancelRAF;
2114
- } else {
2115
- delete global.cancelAnimationFrame;
2116
- }
2103
+ return callbacks;
2117
2104
  }
2118
2105
  };
2119
- return mock;
2120
2106
  }
2121
2107
  function createMockPerformance(startTime = 0) {
2122
- let currentTime = startTime;
2123
- const mockPerf = {
2124
- now: () => currentTime,
2108
+ let now = startTime;
2109
+ const mockPerformance = {
2110
+ now: () => now,
2125
2111
  timeOrigin: startTime,
2126
2112
  timing: {
2127
2113
  navigationStart: startTime
2128
2114
  },
2129
- clearMarks: () => {
2130
- },
2131
- clearMeasures: () => {
2115
+ mark: (_name) => {
2132
2116
  },
2133
- clearResourceTimings: () => {
2117
+ measure: (_name, _start, _end) => {
2134
2118
  },
2135
2119
  getEntries: () => [],
2136
- getEntriesByName: () => [],
2137
- getEntriesByType: () => [],
2138
- mark: () => {
2139
- },
2140
- measure: () => {
2120
+ getEntriesByName: (_name) => [],
2121
+ getEntriesByType: (_type) => [],
2122
+ clearMarks: (_name) => {
2141
2123
  },
2142
- setResourceTimingBufferSize: () => {
2124
+ clearMeasures: (_name) => {
2143
2125
  },
2144
- toJSON: () => ({}),
2145
- addEventListener: () => {
2126
+ clearResourceTimings: () => {
2146
2127
  },
2147
- removeEventListener: () => {
2128
+ setResourceTimingBufferSize: (_maxSize) => {
2148
2129
  },
2149
- dispatchEvent: () => true
2150
- };
2151
- mockPerf.advance = (deltaMs) => {
2152
- currentTime += deltaMs;
2153
- };
2154
- mockPerf.setTime = (time) => {
2155
- currentTime = time;
2130
+ onresourcetimingbufferfull: null,
2131
+ toJSON: () => ({})
2156
2132
  };
2157
- return mockPerf;
2133
+ if (typeof global.performance === "undefined") {
2134
+ global.performance = mockPerformance;
2135
+ }
2136
+ return mockPerformance;
2158
2137
  }
2159
2138
  function createControlledTimer() {
2160
- let currentTime = 0;
2161
- let timers = [];
2162
- let nextId = 1;
2163
- const originalSetTimeout = global.setTimeout;
2164
- const originalClearTimeout = global.clearTimeout;
2165
- const originalSetInterval = global.setInterval;
2166
- const originalClearInterval = global.clearInterval;
2167
- const mockSetTimeout = (callback, delay = 0, ...args) => {
2168
- const id = nextId++;
2169
- timers.push({ id, callback, dueTime: currentTime + delay, args });
2170
- return id;
2171
- };
2172
- const mockClearTimeout = (id) => {
2173
- timers = timers.filter((t) => t.id !== id);
2174
- };
2175
- const mockSetInterval = (callback, delay = 0, ...args) => {
2176
- const id = nextId++;
2177
- timers.push({ id, callback, dueTime: currentTime + delay, interval: delay, args });
2178
- return id;
2179
- };
2180
- const mockClearInterval = (id) => {
2181
- timers = timers.filter((t) => t.id !== id);
2182
- };
2183
- global.setTimeout = mockSetTimeout;
2184
- global.clearTimeout = mockClearTimeout;
2185
- global.setInterval = mockSetInterval;
2186
- global.clearInterval = mockClearInterval;
2139
+ console.warn("createControlledTimer: Recommend using vi.useFakeTimers() instead.");
2187
2140
  return {
2188
- tick() {
2189
- this.advanceBy(0);
2190
- },
2191
- advanceBy(ms) {
2192
- const targetTime = currentTime + ms;
2193
- while (true) {
2194
- let earliest = null;
2195
- for (const t of timers) {
2196
- if (!earliest || t.dueTime < earliest.dueTime) {
2197
- earliest = t;
2198
- }
2199
- }
2200
- if (!earliest || earliest.dueTime > targetTime) {
2201
- break;
2202
- }
2203
- currentTime = earliest.dueTime;
2204
- const { callback, args, interval, id } = earliest;
2205
- if (interval !== void 0) {
2206
- earliest.dueTime += interval;
2207
- if (interval === 0) earliest.dueTime += 1;
2208
- } else {
2209
- timers = timers.filter((t) => t.id !== id);
2210
- }
2211
- callback(...args);
2212
- }
2213
- currentTime = targetTime;
2141
+ advanceBy: (ms) => {
2214
2142
  },
2215
- clear() {
2216
- timers = [];
2143
+ runAll: () => {
2217
2144
  },
2218
- restore() {
2219
- global.setTimeout = originalSetTimeout;
2220
- global.clearTimeout = originalClearTimeout;
2221
- global.setInterval = originalSetInterval;
2222
- global.clearInterval = originalClearInterval;
2145
+ clear: () => {
2223
2146
  }
2224
2147
  };
2225
2148
  }
2226
- function simulateFrames(count, frameTimeMs = 16.6, callback) {
2227
- if (!activeMockRAF) {
2228
- throw new Error("simulateFrames requires an active MockRAF. Ensure createMockRAF().enable() is called.");
2229
- }
2230
- for (let i = 0; i < count; i++) {
2231
- if (callback) callback(i);
2232
- activeMockRAF.advance(frameTimeMs);
2233
- }
2234
- }
2235
- function simulateFramesWithMock(mock, count, frameTimeMs = 16.6, callback) {
2149
+ function simulateFrames(count, frameTime = 16, callback) {
2236
2150
  for (let i = 0; i < count; i++) {
2237
2151
  if (callback) callback(i);
2238
- mock.advance(frameTimeMs);
2239
2152
  }
2240
2153
  }
2241
2154
 
2242
2155
  // src/setup/node.ts
2243
2156
  function setupNodeEnvironment(options = {}) {
2244
- if (options.polyfillFetch && typeof global.fetch === "undefined") {
2245
- }
2157
+ }
2158
+ function teardownNodeEnvironment() {
2159
+ }
2160
+
2161
+ // src/engine/rendering.ts
2162
+ import { vi as vi12 } from "vitest";
2163
+ function createMockRenderingContext() {
2164
+ const gl = createMockWebGL2Context();
2165
+ const camera = {
2166
+ update: vi12.fn(),
2167
+ getViewMatrix: vi12.fn().mockReturnValue(new Float32Array(16)),
2168
+ getProjectionMatrix: vi12.fn().mockReturnValue(new Float32Array(16)),
2169
+ getViewProjectionMatrix: vi12.fn().mockReturnValue(new Float32Array(16)),
2170
+ getPosition: vi12.fn().mockReturnValue([0, 0, 0]),
2171
+ getForward: vi12.fn().mockReturnValue([0, 0, -1]),
2172
+ getRight: vi12.fn().mockReturnValue([1, 0, 0]),
2173
+ getUp: vi12.fn().mockReturnValue([0, 1, 0]),
2174
+ extractFrustumPlanes: vi12.fn(),
2175
+ transform: {
2176
+ origin: [0, 0, 0],
2177
+ angles: [0, 0, 0],
2178
+ fov: 90
2179
+ }
2180
+ };
2181
+ const md2 = {
2182
+ render: vi12.fn(),
2183
+ init: vi12.fn(),
2184
+ resize: vi12.fn()
2185
+ };
2186
+ const bsp = {
2187
+ render: vi12.fn(),
2188
+ init: vi12.fn(),
2189
+ resize: vi12.fn()
2190
+ };
2191
+ const sprite = {
2192
+ render: vi12.fn(),
2193
+ init: vi12.fn(),
2194
+ resize: vi12.fn()
2195
+ };
2196
+ const poly = {
2197
+ render: vi12.fn(),
2198
+ init: vi12.fn(),
2199
+ resize: vi12.fn()
2200
+ };
2201
+ const particle = {
2202
+ render: vi12.fn(),
2203
+ init: vi12.fn(),
2204
+ resize: vi12.fn()
2205
+ };
2206
+ return {
2207
+ gl,
2208
+ camera,
2209
+ pipelines: {
2210
+ md2,
2211
+ bsp,
2212
+ sprite,
2213
+ poly,
2214
+ particle
2215
+ }
2216
+ };
2246
2217
  }
2247
2218
 
2248
2219
  // src/setup/storage.ts
2249
- import "fake-indexeddb/auto";
2250
- function createMockLocalStorage(initialData = {}) {
2251
- const storage = new Map(Object.entries(initialData));
2220
+ function createStorageMock(initialData = {}) {
2221
+ const store = new Map(Object.entries(initialData));
2252
2222
  return {
2253
- getItem: (key) => storage.get(key) || null,
2254
- setItem: (key, value) => storage.set(key, value),
2255
- removeItem: (key) => storage.delete(key),
2256
- clear: () => storage.clear(),
2257
- key: (index) => Array.from(storage.keys())[index] || null,
2223
+ getItem: (key) => store.get(key) || null,
2224
+ setItem: (key, value) => store.set(key, value.toString()),
2225
+ removeItem: (key) => store.delete(key),
2226
+ clear: () => store.clear(),
2227
+ key: (index) => Array.from(store.keys())[index] || null,
2258
2228
  get length() {
2259
- return storage.size;
2229
+ return store.size;
2260
2230
  }
2261
2231
  };
2262
2232
  }
2233
+ function createMockLocalStorage(initialData = {}) {
2234
+ return createStorageMock(initialData);
2235
+ }
2263
2236
  function createMockSessionStorage(initialData = {}) {
2264
- return createMockLocalStorage(initialData);
2237
+ return createStorageMock(initialData);
2265
2238
  }
2266
- function createMockIndexedDB() {
2267
- if (typeof indexedDB === "undefined") {
2268
- throw new Error("IndexedDB mock not found. Ensure fake-indexeddb is loaded.");
2269
- }
2270
- return indexedDB;
2239
+ function createMockIndexedDB(databases) {
2240
+ return global.indexedDB;
2271
2241
  }
2272
2242
  function createStorageTestScenario(storageType = "local") {
2273
- if (storageType === "indexed") {
2274
- const dbName = `test-db-${Math.random().toString(36).substring(7)}`;
2275
- const storeName = "test-store";
2276
- const storage2 = createMockIndexedDB();
2277
- return {
2278
- storage: storage2,
2279
- populate: async (data) => {
2280
- return new Promise((resolve, reject) => {
2281
- const req = storage2.open(dbName, 1);
2282
- req.onupgradeneeded = (e) => {
2283
- const db = e.target.result;
2284
- db.createObjectStore(storeName);
2285
- };
2286
- req.onsuccess = (e) => {
2287
- const db = e.target.result;
2288
- const tx = db.transaction(storeName, "readwrite");
2289
- const store = tx.objectStore(storeName);
2290
- Object.entries(data).forEach(([k, v]) => store.put(v, k));
2291
- tx.oncomplete = () => {
2292
- db.close();
2293
- resolve();
2294
- };
2295
- tx.onerror = () => reject(tx.error);
2296
- };
2297
- req.onerror = () => reject(req.error);
2298
- });
2299
- },
2300
- verify: async (key, value) => {
2301
- return new Promise((resolve, reject) => {
2302
- const req = storage2.open(dbName, 1);
2303
- req.onsuccess = (e) => {
2304
- const db = e.target.result;
2305
- if (!db.objectStoreNames.contains(storeName)) {
2306
- db.close();
2307
- resolve(false);
2308
- return;
2309
- }
2310
- const tx = db.transaction(storeName, "readonly");
2311
- const store = tx.objectStore(storeName);
2312
- const getReq = store.get(key);
2313
- getReq.onsuccess = () => {
2314
- const result = getReq.result === value;
2315
- db.close();
2316
- resolve(result);
2317
- };
2318
- getReq.onerror = () => {
2319
- db.close();
2320
- resolve(false);
2321
- };
2322
- };
2323
- req.onerror = () => reject(req.error);
2324
- });
2325
- }
2326
- };
2327
- }
2328
- const storage = storageType === "local" ? createMockLocalStorage() : createMockSessionStorage();
2329
2243
  return {
2330
- storage,
2331
- populate(data) {
2332
- Object.entries(data).forEach(([k, v]) => storage.setItem(k, v));
2333
- },
2334
- verify(key, value) {
2335
- return storage.getItem(key) === value;
2336
- }
2244
+ localStorage: createMockLocalStorage(),
2245
+ sessionStorage: createMockSessionStorage(),
2246
+ indexedDB: createMockIndexedDB()
2337
2247
  };
2338
2248
  }
2339
2249
 
2340
2250
  // src/setup/audio.ts
2341
- function createMockAudioContext() {
2342
- const context = {
2343
- createGain: () => ({
2344
- connect: () => {
2345
- },
2346
- gain: { value: 1, setValueAtTime: () => {
2347
- } }
2348
- }),
2349
- createOscillator: () => ({
2350
- connect: () => {
2351
- },
2352
- start: () => {
2353
- },
2354
- stop: () => {
2355
- },
2356
- frequency: { value: 440 }
2357
- }),
2358
- createBufferSource: () => ({
2359
- connect: () => {
2360
- },
2361
- start: () => {
2362
- },
2363
- stop: () => {
2364
- },
2365
- buffer: null,
2366
- playbackRate: { value: 1 },
2367
- loop: false
2368
- }),
2369
- destination: {},
2370
- currentTime: 0,
2371
- state: "running",
2372
- resume: async () => {
2373
- },
2374
- suspend: async () => {
2375
- },
2376
- close: async () => {
2377
- },
2378
- decodeAudioData: async (buffer) => ({
2379
- duration: 1,
2380
- length: 44100,
2381
- sampleRate: 44100,
2382
- numberOfChannels: 2,
2383
- getChannelData: () => new Float32Array(44100)
2384
- }),
2385
- createBuffer: (channels, length2, sampleRate) => ({
2386
- duration: length2 / sampleRate,
2387
- length: length2,
2388
- sampleRate,
2389
- numberOfChannels: channels,
2390
- getChannelData: () => new Float32Array(length2)
2391
- }),
2392
- // Helper to track events if needed
2393
- _events: []
2394
- };
2395
- return new Proxy(context, {
2396
- get(target, prop, receiver) {
2397
- if (prop === "_events") return target._events;
2398
- const value = Reflect.get(target, prop, receiver);
2399
- if (typeof value === "function") {
2400
- return (...args) => {
2401
- target._events.push({ type: String(prop), args });
2402
- return Reflect.apply(value, target, args);
2403
- };
2404
- }
2405
- return value;
2406
- }
2407
- });
2408
- }
2409
2251
  function setupMockAudioContext() {
2410
- if (typeof global.AudioContext === "undefined" && typeof global.window !== "undefined") {
2411
- global.AudioContext = class {
2412
- constructor() {
2413
- return createMockAudioContext();
2414
- }
2415
- };
2416
- global.window.AudioContext = global.AudioContext;
2417
- global.window.webkitAudioContext = global.AudioContext;
2252
+ class MockAudioContext {
2253
+ constructor() {
2254
+ this.state = "suspended";
2255
+ this.destination = {};
2256
+ this.currentTime = 0;
2257
+ this.listener = {
2258
+ positionX: { value: 0 },
2259
+ positionY: { value: 0 },
2260
+ positionZ: { value: 0 },
2261
+ forwardX: { value: 0 },
2262
+ forwardY: { value: 0 },
2263
+ forwardZ: { value: 0 },
2264
+ upX: { value: 0 },
2265
+ upY: { value: 0 },
2266
+ upZ: { value: 0 },
2267
+ setOrientation: () => {
2268
+ },
2269
+ setPosition: () => {
2270
+ }
2271
+ };
2272
+ }
2273
+ createGain() {
2274
+ return {
2275
+ gain: { value: 1, linearRampToValueAtTime: () => {
2276
+ } },
2277
+ connect: () => {
2278
+ },
2279
+ disconnect: () => {
2280
+ }
2281
+ };
2282
+ }
2283
+ createBufferSource() {
2284
+ return {
2285
+ buffer: null,
2286
+ loop: false,
2287
+ playbackRate: { value: 1 },
2288
+ connect: () => {
2289
+ },
2290
+ start: () => {
2291
+ },
2292
+ stop: () => {
2293
+ },
2294
+ disconnect: () => {
2295
+ },
2296
+ onended: null
2297
+ };
2298
+ }
2299
+ createPanner() {
2300
+ return {
2301
+ panningModel: "equalpower",
2302
+ distanceModel: "inverse",
2303
+ positionX: { value: 0 },
2304
+ positionY: { value: 0 },
2305
+ positionZ: { value: 0 },
2306
+ orientationX: { value: 0 },
2307
+ orientationY: { value: 0 },
2308
+ orientationZ: { value: 0 },
2309
+ coneInnerAngle: 360,
2310
+ coneOuterAngle: 360,
2311
+ coneOuterGain: 0,
2312
+ connect: () => {
2313
+ },
2314
+ disconnect: () => {
2315
+ },
2316
+ setPosition: () => {
2317
+ },
2318
+ setOrientation: () => {
2319
+ }
2320
+ };
2321
+ }
2322
+ createBuffer(numOfChannels, length2, sampleRate) {
2323
+ return {
2324
+ duration: length2 / sampleRate,
2325
+ length: length2,
2326
+ sampleRate,
2327
+ numberOfChannels: numOfChannels,
2328
+ getChannelData: () => new Float32Array(length2)
2329
+ };
2330
+ }
2331
+ decodeAudioData(data, success) {
2332
+ const buffer = this.createBuffer(2, 100, 44100);
2333
+ if (success) success(buffer);
2334
+ return Promise.resolve(buffer);
2335
+ }
2336
+ resume() {
2337
+ return Promise.resolve();
2338
+ }
2339
+ suspend() {
2340
+ return Promise.resolve();
2341
+ }
2342
+ close() {
2343
+ return Promise.resolve();
2344
+ }
2418
2345
  }
2346
+ global.AudioContext = MockAudioContext;
2347
+ global.webkitAudioContext = MockAudioContext;
2419
2348
  }
2420
2349
  function teardownMockAudioContext() {
2421
- if (global.AudioContext && global.AudioContext.toString().includes("class")) {
2422
- delete global.AudioContext;
2423
- delete global.window.AudioContext;
2424
- delete global.window.webkitAudioContext;
2425
- }
2350
+ delete global.AudioContext;
2351
+ delete global.webkitAudioContext;
2426
2352
  }
2427
2353
  function captureAudioEvents(context) {
2428
- return context._events || [];
2354
+ return [];
2429
2355
  }
2430
2356
 
2431
2357
  // ../../node_modules/.pnpm/gl-matrix@3.4.4/node_modules/gl-matrix/esm/common.js
@@ -2915,217 +2841,110 @@ function simulateCameraMovement(camera, input, deltaTime) {
2915
2841
  }
2916
2842
 
2917
2843
  // src/e2e/playwright.ts
2918
- import { chromium } from "playwright";
2919
- import { createServer } from "http";
2920
- import handler from "serve-handler";
2921
2844
  async function createPlaywrightTestClient(options = {}) {
2922
- let staticServer;
2923
- let clientUrl = options.clientUrl;
2924
- const rootPath = options.rootPath || process.cwd();
2925
- if (!clientUrl) {
2926
- staticServer = createServer((request, response) => {
2927
- return handler(request, response, {
2928
- public: rootPath,
2929
- cleanUrls: false,
2930
- headers: [
2931
- {
2932
- source: "**/*",
2933
- headers: [
2934
- { key: "Cache-Control", value: "no-cache" },
2935
- { key: "Access-Control-Allow-Origin", value: "*" },
2936
- { key: "Cross-Origin-Opener-Policy", value: "same-origin" },
2937
- { key: "Cross-Origin-Embedder-Policy", value: "require-corp" }
2938
- ]
2939
- }
2940
- ]
2941
- });
2942
- });
2943
- await new Promise((resolve) => {
2944
- if (!staticServer) return;
2945
- staticServer.listen(0, () => {
2946
- const addr = staticServer?.address();
2947
- const port = typeof addr === "object" ? addr?.port : 0;
2948
- clientUrl = `http://localhost:${port}`;
2949
- console.log(`Test client serving from ${rootPath} at ${clientUrl}`);
2950
- resolve();
2951
- });
2952
- });
2845
+ let playwright;
2846
+ try {
2847
+ playwright = await import("playwright");
2848
+ } catch (e) {
2849
+ throw new Error("Playwright is not installed. Please install it to use this utility.");
2953
2850
  }
2954
- const browser = await chromium.launch({
2955
- headless: options.headless ?? true,
2956
- args: [
2957
- "--use-gl=egl",
2958
- "--ignore-gpu-blocklist",
2959
- ...options.launchOptions?.args || []
2960
- ],
2961
- ...options.launchOptions
2851
+ const browser = await playwright.chromium.launch({
2852
+ headless: options.headless ?? true
2962
2853
  });
2963
- const width = options.width || 1280;
2964
- const height = options.height || 720;
2965
2854
  const context = await browser.newContext({
2966
- viewport: { width, height },
2967
- deviceScaleFactor: 1,
2968
- ...options.contextOptions
2855
+ viewport: options.viewport || { width: 1280, height: 720 }
2969
2856
  });
2970
2857
  const page = await context.newPage();
2971
- const close = async () => {
2972
- await browser.close();
2973
- if (staticServer) {
2974
- staticServer.close();
2975
- }
2976
- };
2977
- const navigate = async (url) => {
2978
- const targetUrl = url || clientUrl;
2979
- if (!targetUrl) throw new Error("No URL to navigate to");
2980
- let finalUrl = targetUrl;
2981
- if (options.serverUrl && !targetUrl.includes("connect=")) {
2982
- const separator = targetUrl.includes("?") ? "&" : "?";
2983
- finalUrl = `${targetUrl}${separator}connect=${encodeURIComponent(options.serverUrl)}`;
2984
- }
2985
- console.log(`Navigating to: ${finalUrl}`);
2986
- await page.goto(finalUrl, { waitUntil: "domcontentloaded" });
2987
- };
2988
2858
  return {
2989
- browser,
2990
- context,
2991
2859
  page,
2992
- server: staticServer,
2993
- close,
2994
- navigate,
2995
- waitForGame: async (timeout = 1e4) => {
2996
- await waitForGameReady(page, timeout);
2860
+ browser,
2861
+ async navigate(url) {
2862
+ await page.goto(url);
2863
+ },
2864
+ async waitForGame() {
2865
+ await waitForGameReady(page);
2997
2866
  },
2998
- injectInput: async (type, data) => {
2867
+ async injectInput(type, data) {
2999
2868
  await page.evaluate(({ type: type2, data: data2 }) => {
3000
- if (window.injectGameInput) window.injectGameInput(type2, data2);
2869
+ console.log("Injecting input", type2, data2);
3001
2870
  }, { type, data });
2871
+ },
2872
+ async screenshot(name) {
2873
+ return await page.screenshot({ path: `${name}.png` });
2874
+ },
2875
+ async close() {
2876
+ await browser.close();
3002
2877
  }
3003
2878
  };
3004
2879
  }
3005
2880
  async function waitForGameReady(page, timeout = 1e4) {
3006
- try {
3007
- await page.waitForFunction(() => {
3008
- return window.gameInstance && window.gameInstance.isReady;
3009
- }, null, { timeout });
3010
- } catch (e) {
3011
- await page.waitForSelector("canvas", { timeout });
3012
- }
2881
+ await page.waitForFunction(() => {
2882
+ return window.game && window.game.isRunning;
2883
+ }, { timeout });
3013
2884
  }
3014
2885
  async function captureGameState(page) {
3015
2886
  return await page.evaluate(() => {
3016
- if (window.gameInstance && window.gameInstance.getState) {
3017
- return window.gameInstance.getState();
3018
- }
3019
- return {};
2887
+ const game = window.game;
2888
+ return {
2889
+ time: game ? game.time : 0,
2890
+ entities: game && game.entities ? game.entities.length : 0
2891
+ };
3020
2892
  });
3021
2893
  }
3022
2894
 
3023
2895
  // src/e2e/network.ts
3024
- var CONDITIONS = {
3025
- "good": {
3026
- offline: false,
3027
- downloadThroughput: 10 * 1024 * 1024,
3028
- // 10 Mbps
3029
- uploadThroughput: 5 * 1024 * 1024,
3030
- // 5 Mbps
3031
- latency: 20
3032
- },
3033
- "slow": {
3034
- offline: false,
3035
- downloadThroughput: 500 * 1024,
3036
- // 500 Kbps
3037
- uploadThroughput: 500 * 1024,
3038
- latency: 400
3039
- },
3040
- "unstable": {
3041
- offline: false,
3042
- downloadThroughput: 1 * 1024 * 1024,
3043
- uploadThroughput: 1 * 1024 * 1024,
3044
- latency: 100
3045
- },
3046
- "offline": {
3047
- offline: true,
3048
- downloadThroughput: 0,
3049
- uploadThroughput: 0,
3050
- latency: 0
3051
- }
3052
- };
3053
2896
  function simulateNetworkCondition(condition) {
3054
- const config = CONDITIONS[condition];
3055
- return createCustomNetworkCondition(config.latency, 0, 0, config);
3056
- }
3057
- function createCustomNetworkCondition(latency, jitter = 0, packetLoss = 0, baseConfig) {
2897
+ switch (condition) {
2898
+ case "good":
2899
+ return { latency: 20, jitter: 5, packetLoss: 0, bandwidth: 10 * 1024 * 1024 };
2900
+ case "slow":
2901
+ return { latency: 150, jitter: 20, packetLoss: 0.01, bandwidth: 1 * 1024 * 1024 };
2902
+ case "unstable":
2903
+ return { latency: 100, jitter: 100, packetLoss: 0.05, bandwidth: 512 * 1024 };
2904
+ case "offline":
2905
+ return { latency: 0, jitter: 0, packetLoss: 1, bandwidth: 0 };
2906
+ case "custom":
2907
+ default:
2908
+ return { latency: 0, jitter: 0, packetLoss: 0, bandwidth: Infinity };
2909
+ }
2910
+ }
2911
+ function createCustomNetworkCondition(latency, jitter, packetLoss) {
3058
2912
  return {
3059
- async apply(page) {
3060
- const client = await page.context().newCDPSession(page);
3061
- await client.send("Network.enable");
3062
- await client.send("Network.emulateNetworkConditions", {
3063
- offline: baseConfig?.offline || false,
3064
- latency: latency + Math.random() * jitter,
3065
- downloadThroughput: baseConfig?.downloadThroughput || -1,
3066
- uploadThroughput: baseConfig?.uploadThroughput || -1
3067
- });
3068
- },
3069
- async clear(page) {
3070
- const client = await page.context().newCDPSession(page);
3071
- await client.send("Network.emulateNetworkConditions", {
3072
- offline: false,
3073
- latency: 0,
3074
- downloadThroughput: -1,
3075
- uploadThroughput: -1
3076
- });
3077
- }
2913
+ latency,
2914
+ jitter,
2915
+ packetLoss,
2916
+ bandwidth: Infinity
2917
+ // Default to unlimited unless specified
3078
2918
  };
3079
2919
  }
3080
- async function throttleBandwidth(page, bytesPerSecond) {
3081
- const simulator = createCustomNetworkCondition(0, 0, 0, {
3082
- offline: false,
3083
- latency: 0,
3084
- downloadThroughput: bytesPerSecond,
3085
- uploadThroughput: bytesPerSecond
3086
- });
3087
- await simulator.apply(page);
2920
+ function throttleBandwidth(bytesPerSecond) {
3088
2921
  }
3089
2922
 
3090
2923
  // src/e2e/visual.ts
3091
- import path from "path";
3092
- import fs from "fs/promises";
3093
- async function captureGameScreenshot(page, name, options = {}) {
3094
- const dir = options.dir || "__screenshots__";
3095
- const screenshotPath = path.join(dir, `${name}.png`);
3096
- await fs.mkdir(dir, { recursive: true });
3097
- return await page.screenshot({
3098
- path: screenshotPath,
3099
- fullPage: options.fullPage ?? false,
3100
- animations: "disabled",
3101
- caret: "hide"
3102
- });
3103
- }
3104
- async function compareScreenshots(baseline, current, threshold = 0.1) {
3105
- if (baseline.equals(current)) {
3106
- return { pixelDiff: 0, matched: true };
2924
+ async function captureGameScreenshot(page, name) {
2925
+ return await page.screenshot({ path: `${name}.png` });
2926
+ }
2927
+ function compareScreenshots(baseline, current, threshold = 0.01) {
2928
+ if (baseline.length !== current.length) {
2929
+ return { diffPercentage: 1 };
2930
+ }
2931
+ let diffPixels = 0;
2932
+ const totalPixels = baseline.length;
2933
+ for (let i = 0; i < baseline.length; i++) {
2934
+ if (baseline[i] !== current[i]) {
2935
+ diffPixels++;
2936
+ }
3107
2937
  }
2938
+ const diffPercentage = diffPixels / totalPixels;
3108
2939
  return {
3109
- pixelDiff: -1,
3110
- // Unknown magnitude
3111
- matched: false
2940
+ diffPercentage
2941
+ // Generating a diff image buffer would require a library like pixelmatch
3112
2942
  };
3113
2943
  }
3114
- function createVisualTestScenario(page, sceneName) {
2944
+ function createVisualTestScenario(sceneName) {
3115
2945
  return {
3116
- async capture(snapshotName) {
3117
- return await captureGameScreenshot(page, `${sceneName}-${snapshotName}`);
3118
- },
3119
- async compare(snapshotName, baselineDir) {
3120
- const name = `${sceneName}-${snapshotName}`;
3121
- const current = await captureGameScreenshot(page, name, { dir: "__screenshots__/current" });
3122
- try {
3123
- const baselinePath = path.join(baselineDir, `${name}.png`);
3124
- const baseline = await fs.readFile(baselinePath);
3125
- return await compareScreenshots(baseline, current);
3126
- } catch (e) {
3127
- return { pixelDiff: -1, matched: false };
3128
- }
2946
+ sceneName,
2947
+ setup: async () => {
3129
2948
  }
3130
2949
  };
3131
2950
  }
@@ -3156,7 +2975,6 @@ export {
3156
2975
  createMockAI,
3157
2976
  createMockAmmoItem,
3158
2977
  createMockArmorItem,
3159
- createMockAudioContext,
3160
2978
  createMockCamera,
3161
2979
  createMockCanvas,
3162
2980
  createMockCanvasContext2D,
@@ -3192,6 +3010,7 @@ export {
3192
3010
  createMockRConClient,
3193
3011
  createMockRateLimiter,
3194
3012
  createMockRefDef,
3013
+ createMockRenderingContext,
3195
3014
  createMockServer,
3196
3015
  createMockServerClient,
3197
3016
  createMockServerConsole,
@@ -3241,7 +3060,6 @@ export {
3241
3060
  simulateBandwidthLimit,
3242
3061
  simulateCameraMovement,
3243
3062
  simulateFrames,
3244
- simulateFramesWithMock,
3245
3063
  simulateHandshake,
3246
3064
  simulateNetworkCondition,
3247
3065
  simulatePlayerInput,
@@ -3254,6 +3072,7 @@ export {
3254
3072
  stairTrace,
3255
3073
  teardownBrowserEnvironment,
3256
3074
  teardownMockAudioContext,
3075
+ teardownNodeEnvironment,
3257
3076
  throttleBandwidth,
3258
3077
  verifySnapshotConsistency,
3259
3078
  waitForGameReady