asset-coordinator.test.ts 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. import { describe, expect, it } from "vitest";
  2. import type { AssetEntry } from "@nengine/core";
  3. import { AssetCoordinator, MAX_ASSET_REQUEST_IDS } from "../src/sync/asset-coordinator.js";
  4. const index = (ids: string[]): Record<string, { kind: "image" | "audio"; mime: string; size: number }> => {
  5. const out: Record<string, { kind: "image" | "audio"; mime: string; size: number }> = {};
  6. for (const id of ids) out[id] = { kind: "image", mime: "image/png", size: 1 };
  7. return out;
  8. };
  9. const entry = (id: string): Record<string, AssetEntry> => ({ [id]: { kind: "image", mime: "image/png", data: "x" } });
  10. describe("AssetCoordinator (D37 on-demand asset requests)", () => {
  11. it("requests only wanted ids known to the server index", () => {
  12. const c = new AssetCoordinator();
  13. c.setIndex(index(["grass-1", "water-1"]));
  14. c.want(["grass-1", "water-1", "missing-asset"]);
  15. expect(c.requestBatch()).toEqual(["grass-1", "water-1"]);
  16. expect(c.requestBatch()).toEqual([]);
  17. });
  18. it("dedupes: never re-requests ids that are pending or loaded", () => {
  19. const c = new AssetCoordinator();
  20. c.setIndex(index(["a", "b", "c"]));
  21. c.want(["a", "b", "c"]);
  22. const batch1 = c.requestBatch();
  23. expect(batch1).toEqual(["a", "b", "c"]);
  24. // all pending — nothing new
  25. expect(c.requestBatch()).toEqual([]);
  26. // a response for a and b arrives; c's request is still in flight
  27. c.applyAssets({ ...entry("a"), ...entry("b") });
  28. expect(c.has("a")).toBe(true);
  29. expect(c.has("b")).toBe(true);
  30. expect(c.has("c")).toBe(false);
  31. expect(c.requestBatch()).toEqual([]); // c still pending
  32. // c's response arrives — nothing left to request
  33. c.applyAssets(entry("c"));
  34. expect(c.has("c")).toBe(true);
  35. expect(c.requestBatch()).toEqual([]);
  36. });
  37. it("caps a batch at MAX_ASSET_REQUEST_IDS", () => {
  38. const ids = Array.from({ length: MAX_ASSET_REQUEST_IDS + 10 }, (_, i) => `a${i}`);
  39. const c = new AssetCoordinator();
  40. c.setIndex(index(ids));
  41. c.want(ids);
  42. const batch = c.requestBatch();
  43. expect(batch).toHaveLength(MAX_ASSET_REQUEST_IDS);
  44. const rest = c.requestBatch();
  45. expect(rest).toHaveLength(10);
  46. });
  47. it("new wanted ids from a later snapshot are requested after a prior batch resolved", () => {
  48. const c = new AssetCoordinator();
  49. c.setIndex(index(["a"]));
  50. c.want(["a"]);
  51. expect(c.requestBatch()).toEqual(["a"]);
  52. c.applyAssets(entry("a"));
  53. // a fresh snapshot adds a new referenced asset
  54. c.setIndex(index(["a", "b"]));
  55. c.want(["b"]);
  56. expect(c.requestBatch()).toEqual(["b"]);
  57. });
  58. it("applyAssets with an empty frame changes nothing", () => {
  59. const c = new AssetCoordinator();
  60. c.setIndex(index(["a"]));
  61. c.want(["a"]);
  62. expect(c.requestBatch()).toEqual(["a"]);
  63. c.applyAssets({});
  64. expect(c.has("a")).toBe(false);
  65. expect(c.requestBatch()).toEqual([]); // still pending until a response arrives
  66. });
  67. });