| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182 |
- import { describe, expect, it } from 'vitest';
- import { readMapFiles } from '../src/server/assets';
- import { buildTerrain, MapValidationError, parseMapDefinition, type MapDefinition, type RgbaImage } from '../src/shared/maps/loader';
- import { ASSETS, realMaterials } from './helpers';
- const materials = realMaterials();
- function def(overrides: Partial<MapDefinition> = {}): MapDefinition {
- return parseMapDefinition({
- id: 'test',
- name: 'Test',
- size: [4, 4],
- materialPalette: { '#000000': 0, '#F2C46D': 1, '#8899AA': 255 },
- spawns: [[1, 0]],
- cherrySpawn: [2, 0],
- custard: { startY: 3, speed: 1, finalRushSpeed: 2 },
- items: { interval: [1, 2], weights: { candle: 1 } },
- ...overrides,
- });
- }
- /** Rows of 0xRRGGBB pixels -> RGBA image. */
- function image(rows: number[][]): RgbaImage {
- const h = rows.length;
- const w = rows[0].length;
- const data = new Uint8Array(w * h * 4);
- rows.flat().forEach((c, i) => {
- data.set([c >> 16, (c >> 8) & 0xff, c & 0xff, 255], i * 4);
- });
- return { width: w, height: h, data };
- }
- const E = 0x000000;
- const S = 0xf2c46d;
- const P = 0x8899aa;
- const valid = [
- [E, E, E, E],
- [E, E, E, E],
- [S, S, S, S],
- [P, P, P, P],
- ];
- describe('map loader', () => {
- it('loads a valid map', () => {
- const bm = buildTerrain(def(), image(valid), materials);
- expect(bm.get(0, 2)).toBe(1);
- expect(bm.get(0, 3)).toBe(255);
- });
- it('rejects colors outside the palette', () => {
- const bad = valid.map((r) => [...r]);
- bad[2][1] = 0x123456;
- expect(() => buildTerrain(def(), image(bad), materials)).toThrow(/#123456.*not in the palette/);
- });
- it('rejects a map without plate', () => {
- const noPlate = valid.map((r) => r.map((c) => (c === P ? S : c)));
- expect(() => buildTerrain(def(), image(noPlate), materials)).toThrow(/no plate/);
- });
- it('rejects spawns inside terrain or above nothing', () => {
- expect(() => buildTerrain(def({ spawns: [[1, 2]] }), image(valid), materials)).toThrow(/inside solid/);
- const hole = valid.map((r) => [...r]);
- hole[2][0] = E;
- hole[3][0] = E;
- expect(() => buildTerrain(def({ spawns: [[0, 0]] }), image(hole), materials)).toThrow(/no ground/);
- });
- it('rejects size mismatches and malformed map.json', () => {
- expect(() => buildTerrain(def({ size: [5, 4] }), image(valid), materials)).toThrow(/terrain.png is 4x4/);
- expect(() => parseMapDefinition({ id: 'x' }, 'x')).toThrow(MapValidationError);
- expect(() => parseMapDefinition({ ...def(), id: 'other' }, 'test')).toThrow(/folder/);
- });
- it('the reference map gateau-etages is valid', () => {
- const raw = readMapFiles(ASSETS, 'gateau-etages');
- const map = parseMapDefinition(raw.definition, 'gateau-etages');
- const bm = buildTerrain(map, raw.terrain, materials);
- expect(bm.width).toBe(2048);
- expect(bm.height).toBe(1024);
- });
- });
|