diff --git a/src/main/smoke.ts b/src/main/smoke.ts index d514cfa..9a918ef 100644 --- a/src/main/smoke.ts +++ b/src/main/smoke.ts @@ -132,6 +132,7 @@ import * as areasMod2 from './core/chunkAreas' import * as tilesMod from './core/worldTiles' import * as tex from '@shared/textures' import { MAP_CSS, MAP_HTML } from '@shared/mapUi' +import { getMapPageHtml } from './web/mapPageHtml' import * as pngMod from './core/png' import { deflateSync } from 'node:zlib' import * as assetsMod from './core/clientAssets' @@ -6782,6 +6783,49 @@ export async function runWebSmoke(): Promise { current: { id, name: 'S', scopes: ['view', 'store'], status: 'stopped' } }) site = runPageScript(getPublicSiteHtml()) + + // The map page is the FOURTH host of the shared map engine, and until + // #153 the smoke never ran its script — so it shipped missing half the + // host contract. With structures switched on, `mapDraw` threw + // "MAP_ICONS is not defined" and took the whole draw down with it: the + // map simply stopped updating, on the page whose entire purpose is the + // map. + // + // Every setting ON, because the defect only appeared with structures + // enabled and a page tested at its defaults would still pass. + const mapPage = runPageScript( + getMapPageHtml( + normalizeMapPage({ + enabled: true, + serverId: id, + structures: true, + areas: true, + heatmap: true, + world: true, + players: true, + names: true, + heads: true + }) + ) + ) + const mctx = mapPage.ctx as Record + // What MAP_JS reaches for and this page has to supply. Naming them is + // the point: a missing one is a ReferenceError at draw time, which is + // silent until somebody opens the page with that layer on. + for (const need of [ + 'mapGet', 'mapPost', 'mapServerId', 'mapFeedUrl', 'mapTilesUrl', + 'mapAvatarUrl', 'mapIconFor', 'mapIconSvg', 'MAP_ICONS', 'STRUCTURE_ICONS' + ]) { + if (mctx[need] === undefined) return fail('the map page never defines ' + need) + } + // ...and then actually draw, which is what threw. Structures on, so the + // icon key is built rather than skipped. + try { + ;(mctx['MAP'] as { marksOn: boolean; areasOn: boolean }).marksOn = true + ;(mctx['mapDraw'] as () => void)() + } catch (e) { + return fail('the map page threw while drawing: ' + String(e)) + } } catch (e) { return fail('a served page threw on load: ' + String(e)) } diff --git a/src/main/web/mapPageHtml.ts b/src/main/web/mapPageHtml.ts index 6dcaf78..ff62841 100644 --- a/src/main/web/mapPageHtml.ts +++ b/src/main/web/mapPageHtml.ts @@ -2,6 +2,8 @@ import { MAP_CSS, MAP_HTML, MAP_JS } from '@shared/mapUi' import { mapPagePublic } from '@shared/mapPage' import type { MapPageConfig } from '@shared/mapPage' import { avatarUrl } from '@shared/profile' +import { iconSvg, STRUCTURE_ICONS } from '@shared/mapIcons' +import type { SiteTheme } from '@shared/web' /** * The map page (#146). @@ -21,8 +23,18 @@ const esc = (s: string): string => c === '&' ? '&' : c === '<' ? '<' : c === '>' ? '>' : c === '"' ? '"' : ''' ) -export function getMapPageHtml(cfg: MapPageConfig): string { +export function getMapPageHtml(cfg: MapPageConfig, theme?: SiteTheme): string { const pub = mapPagePublic(cfg) + // The operator already chose colours for their website; a map page in a + // different red would look like somebody else's site. Falls back to the same + // defaults the site uses when nothing is configured. + const t: Partial = theme ?? {} + const hex = (v: unknown, d: string): string => + typeof v === 'string' && /^#[0-9a-fA-F]{6}$/.test(v) ? v : d + const accent = hex(t.accent, '#dc2727') + const bg = hex(t.bg, '#0b0b10') + const card = hex(t.card, '#16151b') + const text = hex(t.text, '#e7e9ee') return ` @@ -32,10 +44,15 @@ export function getMapPageHtml(cfg: MapPageConfig): string { ${esc(pub.title)}