fix: match Kinglet aircraft exactly
This commit is contained in:
@@ -36,6 +36,7 @@ type PointerEventLike = { pointerId?: number; clientX?: number; clientY?: number
|
|||||||
const scumMapLayerImages = { terrain: new URL("../assets/map/scum-map-terrain-4096.webp", import.meta.url).href, topo: new URL("../assets/map/scum-map-topo-4096.webp", import.meta.url).href, night: new URL("../assets/map/scum-map-night-4096.webp", import.meta.url).href, zones: new URL("../assets/map/scum-map-building-zones-4096.png", import.meta.url).href } as const;
|
const scumMapLayerImages = { terrain: new URL("../assets/map/scum-map-terrain-4096.webp", import.meta.url).href, topo: new URL("../assets/map/scum-map-topo-4096.webp", import.meta.url).href, night: new URL("../assets/map/scum-map-night-4096.webp", import.meta.url).href, zones: new URL("../assets/map/scum-map-building-zones-4096.png", import.meta.url).href } as const;
|
||||||
const scumMapBaseLayers: ReadonlyArray<readonly [ScumMapLayer, string]> = [["terrain", "地形"], ["topo", "等高线"], ["night", "夜间"]];
|
const scumMapBaseLayers: ReadonlyArray<readonly [ScumMapLayer, string]> = [["terrain", "地形"], ["topo", "等高线"], ["night", "夜间"]];
|
||||||
const scumMapVehicleFilters: ReadonlyArray<readonly [MapVehicleFilter, string]> = [["all", "全部载具"], ["land", "陆地载具"], ["water", "水上载具"], ["air", "飞行类载具"], ["other", "其他载具"]];
|
const scumMapVehicleFilters: ReadonlyArray<readonly [MapVehicleFilter, string]> = [["all", "全部载具"], ["land", "陆地载具"], ["water", "水上载具"], ["air", "飞行类载具"], ["other", "其他载具"]];
|
||||||
|
const scumFlightVehicleKeys = new Set(["kinglet_duster", "kinglet_mariner", "kinglet_scout"]);
|
||||||
const scumCatalogKinds: ReadonlyArray<readonly [string, string]> = [["all", "全部"], ["item", "物品"], ["vehicle", "载具"], ["zombie", "丧尸"], ["animal", "动物"], ["armed-npc", "NPC"]];
|
const scumCatalogKinds: ReadonlyArray<readonly [string, string]> = [["all", "全部"], ["item", "物品"], ["vehicle", "载具"], ["zombie", "丧尸"], ["animal", "动物"], ["armed-npc", "NPC"]];
|
||||||
const scumCatalogPickLimit = 48;
|
const scumCatalogPickLimit = 48;
|
||||||
const scumMapSize = 4096;
|
const scumMapSize = 4096;
|
||||||
@@ -1408,14 +1409,16 @@ function positionOf(row: RecordMap | undefined): RecordMap | undefined { const n
|
|||||||
function hasCoordinates(row: RecordMap | undefined): row is RecordMap { return Boolean(row) && Number.isFinite(Number(field(row, "x", "locationX"))) && Number.isFinite(Number(field(row, "y", "locationY"))); }
|
function hasCoordinates(row: RecordMap | undefined): row is RecordMap { return Boolean(row) && Number.isFinite(Number(field(row, "x", "locationX"))) && Number.isFinite(Number(field(row, "y", "locationY"))); }
|
||||||
function layerOf(point: RecordMap): MapLayer { const value = textField(point, "layer", "subjectType", "type").toLowerCase(); if (value.includes("player") || value.includes("user")) return "players"; if (value.includes("vehicle")) return "vehicles"; if (value.includes("flag")) return "flags"; if (value.includes("region") || value.includes("zone") || value === "base") return "regions"; return "other"; }
|
function layerOf(point: RecordMap): MapLayer { const value = textField(point, "layer", "subjectType", "type").toLowerCase(); if (value.includes("player") || value.includes("user")) return "players"; if (value.includes("vehicle")) return "vehicles"; if (value.includes("flag")) return "flags"; if (value.includes("region") || value.includes("zone") || value === "base") return "regions"; return "other"; }
|
||||||
function layerLabel(layer: MapLayer): string { return layer === "players" ? "用户" : layer === "vehicles" ? "载具" : layer === "flags" ? "旗帜" : layer === "regions" ? "区域" : "其他"; }
|
function layerLabel(layer: MapLayer): string { return layer === "players" ? "用户" : layer === "vehicles" ? "载具" : layer === "flags" ? "旗帜" : layer === "regions" ? "区域" : "其他"; }
|
||||||
function mapVehicleCategory(point: RecordMap): MapVehicleFilter {
|
export function mapVehicleCategory(point: RecordMap): MapVehicleFilter {
|
||||||
const entry = scumVehicleEntry(textField(point, "className", "vehicleClass", "entityClass", "vehicleType", "name", "label"));
|
const entry = scumVehicleEntry(textField(point, "className", "vehicleClass", "entityClass", "vehicleType", "name", "label"));
|
||||||
const value = [textField(point, "vehicleType", "className", "vehicleClass", "entityClass", "name", "label"), entry?.code || "", entry?.name || ""].join(" ").toLowerCase();
|
const values = [textField(point, "vehicleType", "className", "vehicleClass", "entityClass", "name", "label"), entry?.code || "", entry?.name || ""];
|
||||||
if (/kinglet|duster|mariner|scout|aircraft|airplane|aeroplane|helicopter|plane|flight|飞行/.test(value)) return "air";
|
if (values.some((value) => scumFlightVehicleKeys.has(mapVehicleKey(value)))) return "air";
|
||||||
|
const value = values.join(" ").toLowerCase();
|
||||||
if (/boat|dinghy|raft|motorboat|barba|sup|water|船|水上/.test(value)) return "water";
|
if (/boat|dinghy|raft|motorboat|barba|sup|water|船|水上/.test(value)) return "water";
|
||||||
if (/bike|bicycle|motorcycle|sidecar|cruiser|laika|rager|ris|wolfswagen|tractor|pickup|suv|quad|sportbike|wheelbarrow|car|land|陆地/.test(value)) return "land";
|
if (/bike|bicycle|motorcycle|sidecar|cruiser|laika|rager|ris|wolfswagen|tractor|pickup|suv|quad|sportbike|wheelbarrow|car|land|陆地/.test(value)) return "land";
|
||||||
return "other";
|
return "other";
|
||||||
}
|
}
|
||||||
|
function mapVehicleKey(value: string): string { return normalizedVehicleClass(value.replace(/^#spawnvehicle\s+/i, "")).replace(/^(?:bpc_|bp_)/i, "").replace(/[^a-z0-9]+/gi, "_").replace(/^_+|_+$/g, "").toLowerCase(); }
|
||||||
function pointTitle(point: RecordMap): string { return textField(point, "displayName", "name", "label", "subjectName") || textField(point, "subjectType", "type") || textField(point, "subjectId", "id") || "地图点"; }
|
function pointTitle(point: RecordMap): string { return textField(point, "displayName", "name", "label", "subjectName") || textField(point, "subjectType", "type") || textField(point, "subjectId", "id") || "地图点"; }
|
||||||
function mapPointIdentity(point: RecordMap): string { const subject = textField(point, "subjectId", "gamePlayerId", "vehicleId", "flagId", "regionId"); if (subject) return `${layerOf(point)}:${subject}`; const record = textField(point, "id", "_recordKey"); if (record) return `${layerOf(point)}:${record}`; return `${layerOf(point)}:${pointTitle(point).toLowerCase()}:${numField(point, "x", "locationX")}:${numField(point, "y", "locationY")}`; }
|
function mapPointIdentity(point: RecordMap): string { const subject = textField(point, "subjectId", "gamePlayerId", "vehicleId", "flagId", "regionId"); if (subject) return `${layerOf(point)}:${subject}`; const record = textField(point, "id", "_recordKey"); if (record) return `${layerOf(point)}:${record}`; return `${layerOf(point)}:${pointTitle(point).toLowerCase()}:${numField(point, "x", "locationX")}:${numField(point, "y", "locationY")}`; }
|
||||||
export function mapScenePoint(point: RecordMap, bounds: RecordMap): { x: number; y: number } {
|
export function mapScenePoint(point: RecordMap, bounds: RecordMap): { x: number; y: number } {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { fileURLToPath } from "node:url";
|
|||||||
|
|
||||||
import { migrateConfigurationRecord, migrateGiftGrantRecord, migratePlayerProfileRecord, migratePlayerRecord, migrateStatePatchRecord, migrateTrajectoryHistoryRecord, migrateTrajectoryRecord, migrationStatus } from "../examples/scum-server-plugin/features/migration.js";
|
import { migrateConfigurationRecord, migrateGiftGrantRecord, migratePlayerProfileRecord, migratePlayerRecord, migrateStatePatchRecord, migrateTrajectoryHistoryRecord, migrateTrajectoryRecord, migrationStatus } from "../examples/scum-server-plugin/features/migration.js";
|
||||||
import { createGiftDelivery, deleteGiftDefinition, loadSCUMSurface, parseGiftCommands, parseGiftItems, queueGiftDelivery, resetGiftClaim, resetPendingGift, resolveMapBounds, saveEventProduce, saveGiftDefinition, saveMapSettings, scumCollections, startEvent, type RecordMap, type SCUMSurfaceData, type SCUMWorkspaceActions } from "../examples/scum-server-plugin/features/page-data.js";
|
import { createGiftDelivery, deleteGiftDefinition, loadSCUMSurface, parseGiftCommands, parseGiftItems, queueGiftDelivery, resetGiftClaim, resetPendingGift, resolveMapBounds, saveEventProduce, saveGiftDefinition, saveMapSettings, scumCollections, startEvent, type RecordMap, type SCUMSurfaceData, type SCUMWorkspaceActions } from "../examples/scum-server-plugin/features/page-data.js";
|
||||||
import { advanceMapPlayback, bundledVehicleImageUrl, collectMapPoints, mapPointStyle, playbackStartView, playbackFollowView } from "../examples/scum-server-plugin/features/page.js";
|
import { advanceMapPlayback, bundledVehicleImageUrl, collectMapPoints, mapPointStyle, mapVehicleCategory, playbackStartView, playbackFollowView } from "../examples/scum-server-plugin/features/page.js";
|
||||||
import type { MapTrack, MapTrackPoint } from "../examples/scum-server-plugin/features/contracts.js";
|
import type { MapTrack, MapTrackPoint } from "../examples/scum-server-plugin/features/contracts.js";
|
||||||
import { renderPluginPage } from "../examples/scum-server-plugin/page-bundle/index.js";
|
import { renderPluginPage } from "../examples/scum-server-plugin/page-bundle/index.js";
|
||||||
import { configurationCatalog, validateConfigPatch, validateStatePatch, validateVehicleSpawn, vehicleSpawnCatalog } from "../examples/scum-server-plugin/features/schemas.js";
|
import { configurationCatalog, validateConfigPatch, validateStatePatch, validateVehicleSpawn, vehicleSpawnCatalog } from "../examples/scum-server-plugin/features/schemas.js";
|
||||||
@@ -346,6 +346,14 @@ describe("SCUM plugin feature module", () => {
|
|||||||
expect(view.texts).toContain("Mira · 4 点");
|
expect(view.texts).toContain("Mira · 4 点");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("recognizes only the three Kinglet aircraft names in the flight filter", () => {
|
||||||
|
expect(mapVehicleCategory({ className: "Kinglet_Duster_ES" })).toBe("air");
|
||||||
|
expect(mapVehicleCategory({ className: "BPC_Kinglet_Mariner_C" })).toBe("air");
|
||||||
|
expect(mapVehicleCategory({ label: "Kinglet Scout" })).toBe("air");
|
||||||
|
expect(mapVehicleCategory({ className: "BPC_Laika_C" })).not.toBe("air");
|
||||||
|
expect(mapVehicleCategory({ className: "Scout_ES" })).not.toBe("air");
|
||||||
|
});
|
||||||
|
|
||||||
it("keeps the extracted icon catalog closed until an editor asks for it", () => {
|
it("keeps the extracted icon catalog closed until an editor asks for it", () => {
|
||||||
const gifts = renderAndCollect({ pageKey: "gifts", pageTitle: "礼包管理" });
|
const gifts = renderAndCollect({ pageKey: "gifts", pageTitle: "礼包管理" });
|
||||||
expect(gifts.texts).not.toContain("从 SCUM 目录选择礼包物品");
|
expect(gifts.texts).not.toContain("从 SCUM 目录选择礼包物品");
|
||||||
|
|||||||
Reference in New Issue
Block a user