Skip to content

Commit 87fc08f

Browse files
authored
feature: map assets are built for every seeded map and any other map some mode enables, so prophunt overlays are skipped (#648)
1 parent 672093a commit 87fc08f

5 files changed

Lines changed: 117 additions & 8 deletions

File tree

‎hasura/enums/maps.sql‎

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,8 @@ insert into maps (
243243
"workshop_map_id",
244244
"poster",
245245
"patch",
246-
"label"
246+
"label",
247+
"seeded"
247248
)
248249
SELECT
249250
name,
@@ -252,14 +253,22 @@ SELECT
252253
workshop_map_id,
253254
poster,
254255
patch,
255-
label
256+
label,
257+
true
256258
FROM all_maps
257259
on conflict("name", "type") do update set
258260
"active_pool" = EXCLUDED."active_pool",
259261
"workshop_map_id" = EXCLUDED."workshop_map_id",
260262
"poster" = EXCLUDED."poster",
261263
"patch" = EXCLUDED."patch",
262-
"label" = EXCLUDED."label"
264+
"label" = EXCLUDED."label",
265+
"seeded" = true
266+
),
267+
unseeded AS (
268+
UPDATE maps
269+
SET seeded = false
270+
WHERE seeded
271+
AND name NOT IN (SELECT name FROM map_data)
263272
)
264273
-- A map's details belong to the map, not one mode, so the mode rows the seed does not list (an
265274
-- admin's, or one it retired) carry them too; only a retired mode is switched off.
@@ -268,6 +277,7 @@ SET workshop_map_id = md.workshop_map_id,
268277
poster = md.poster,
269278
patch = md.patch,
270279
label = md.label,
280+
seeded = true,
271281
enabled = m.enabled AND NOT EXISTS (
272282
SELECT 1 FROM retired_map_types r WHERE r.name = m.name AND r.type = m.type
273283
)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ALTER TABLE public.maps DROP COLUMN IF EXISTS seeded;
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
-- Whether hasura/enums/maps.sql ships the map. Every instance seeds the same
2+
-- maps, and their map assets are built once on 5stack.gg for all of them, so a
3+
-- seeded map is built whatever this instance's own modes enable.
4+
ALTER TABLE public.maps ADD COLUMN IF NOT EXISTS seeded boolean NOT NULL DEFAULT false;

‎src/map-assets/map-assets.service.ts‎

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -980,18 +980,27 @@ export class MapAssetsService {
980980
});
981981
}
982982

983-
// Only maps with a row are built and published. Every instance seeds the
984-
// same maps, so this instance's table speaks for all of them. A row with a
983+
// Every instance seeds the same maps and reads the assets built here, so a
984+
// seeded map is always built, whatever this instance's modes enable. Any
985+
// other map is built only while some mode enables it: one disabled in every
986+
// mode, like a prophunt overlay that only a public server's rotation loads,
987+
// is never played as a match and so never rendered. A row with a
985988
// workshop_map_id is built from the node's workshop downloads when the
986-
// install does not carry it; one the node never downloaded keeps whatever
987-
// is already published.
989+
// install does not carry it; one the node never downloaded keeps whatever is
990+
// already published.
988991
private async knownMaps(): Promise<{
989992
names: Array<string>;
990993
workshop: Array<MapAssetsWorkshopMap>;
991994
}> {
992995
const rows = await this.postgres.query<
993996
Array<{ name: string; workshop_map_id: string | null }>
994-
>(`SELECT DISTINCT name, workshop_map_id FROM public.maps ORDER BY name`);
997+
>(
998+
`SELECT name, workshop_map_id
999+
FROM public.maps
1000+
WHERE seeded
1001+
OR (enabled AND deleted_at IS NULL)
1002+
ORDER BY name, enabled DESC`,
1003+
);
9951004

9961005
const names = [...new Set(rows.map(({ name }) => name))];
9971006
const workshop = new Map<string, string>();

‎test/map-asset-builds.spec.ts‎

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { readFileSync } from "fs";
2+
import { join } from "path";
13
import { Logger } from "@nestjs/common";
24
import { PostgresService } from "./../src/postgres/postgres.service";
35
import { MapAssetsService } from "./../src/map-assets/map-assets.service";
@@ -206,6 +208,89 @@ describe("map asset builds (SQL-driven)", () => {
206208
expect(queue.add).not.toHaveBeenCalled();
207209
});
208210

211+
it("builds every seeded map, and any other only while some mode enables it", async () => {
212+
await postgres.query(
213+
`INSERT INTO maps (name, type, enabled, active_pool, workshop_map_id, deleted_at, seeded)
214+
VALUES ('de_assets_playable', 'Competitive', true, false, NULL, NULL, false),
215+
('de_assets_one_mode', 'Competitive', false, false, '9101', NULL, true),
216+
('de_assets_one_mode', 'Duel', true, false, '9100', NULL, true),
217+
('9200', 'Competitive', false, false, '9200', NULL, false),
218+
('de_assets_deleted', 'Competitive', true, false, '9300', now(), false)`,
219+
);
220+
await postgres.query(
221+
`UPDATE maps SET enabled = false WHERE name = 'cs_office'`,
222+
);
223+
const mapAssets = service();
224+
225+
try {
226+
await (mapAssets as any).startJob("node-a", "25537370", false);
227+
} finally {
228+
await postgres.query(
229+
`DELETE FROM maps WHERE name IN ('de_assets_playable', 'de_assets_one_mode', '9200', 'de_assets_deleted')`,
230+
);
231+
await postgres.query(
232+
`UPDATE maps SET enabled = true WHERE name = 'cs_office'`,
233+
);
234+
}
235+
236+
const [[{ body }]] = (mapAssets as any).batchApi.createNamespacedJob.mock
237+
.calls;
238+
const args: Array<string> = body.spec.template.spec.containers[0].args;
239+
const only = args[args.indexOf("--only-maps") + 1].split(",");
240+
const workshop = args[args.indexOf("--workshop-maps") + 1].split(",");
241+
expect(only).toEqual(
242+
expect.arrayContaining([
243+
"cs_office",
244+
"de_assets_playable",
245+
"de_assets_one_mode",
246+
]),
247+
);
248+
expect(only).not.toContain("9200");
249+
expect(only).not.toContain("de_assets_deleted");
250+
expect(workshop).toContain("de_assets_one_mode=9100");
251+
expect(workshop).not.toContain("de_assets_one_mode=9101");
252+
expect(workshop).not.toContain("9200=9200");
253+
expect(workshop).not.toContain("de_assets_deleted=9300");
254+
});
255+
256+
it("marks every mode of the maps the seed ships, and only those", async () => {
257+
// As the migration leaves every existing row on upgrade.
258+
await postgres.query(`UPDATE maps SET seeded = false`);
259+
await postgres.query(
260+
`INSERT INTO maps (name, type, active_pool, seeded)
261+
VALUES ('de_mirage', 'Duel', false, false),
262+
('de_assets_retired', 'Competitive', false, true),
263+
('de_assets_custom', 'Competitive', false, false)`,
264+
);
265+
266+
try {
267+
await postgres.query(
268+
readFileSync(join(__dirname, "../hasura/enums/maps.sql"), "utf8"),
269+
);
270+
const seeded = await postgres.query<
271+
Array<{ name: string; type: string; seeded: boolean }>
272+
>(
273+
`SELECT name, type, seeded FROM maps
274+
WHERE (name = 'de_mirage' AND type IN ('Competitive', 'Duel'))
275+
OR name IN ('cs_office', 'de_assets_retired', 'de_assets_custom')
276+
ORDER BY name, type`,
277+
);
278+
expect(seeded).toEqual([
279+
{ name: "cs_office", type: "Competitive", seeded: true },
280+
{ name: "de_assets_custom", type: "Competitive", seeded: false },
281+
{ name: "de_assets_retired", type: "Competitive", seeded: false },
282+
{ name: "de_mirage", type: "Competitive", seeded: true },
283+
{ name: "de_mirage", type: "Duel", seeded: true },
284+
]);
285+
} finally {
286+
await postgres.query(
287+
`DELETE FROM maps
288+
WHERE (name = 'de_mirage' AND type = 'Duel')
289+
OR name IN ('de_assets_retired', 'de_assets_custom')`,
290+
);
291+
}
292+
});
293+
209294
it("records a published build and the manifest revision it came from", async () => {
210295
const maps = { de_mirage: { tri: "25000000/de_mirage.tri.gz" } };
211296
await postgres.query(

0 commit comments

Comments
 (0)