fix: improve SCUM map playback filters

This commit is contained in:
npc0-hue
2026-09-20 10:45:32 +08:00
parent 60d479db71
commit 312804c55e
32 changed files with 770 additions and 293 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

@@ -36,4 +36,17 @@ export type SCUMTrajectoryPoint = { occurredAt: string; subjectId: string; subje
export type SCUMTrajectory = { subjectId: string; subjectType: "player" | "vehicle"; points: SCUMTrajectoryPoint[]; provenance: SCUMMigrationProvenance };
export type SCUMTrajectoryCollection = { available: boolean; reason?: string; trajectories: SCUMTrajectory[] };
export type MapViewState = { zoom: number; x: number; y: number };
export type MapPlaybackState = { playing: boolean; value: number; speed: number; startedAt: number; startValue: number };
export type MapTimeWindow = { from: number; to: number; label: string };
export type MapTrackPoint = { key: string; row: Record<string, unknown>; x: number; y: number; time: number; riding: boolean; rideCode: string };
export type MapTrackSegment = { key: string; mode: "walk" | "ride"; points: MapTrackPoint[] };
export type MapTrack = { key: string; kind: "player" | "vehicle"; label: string; color: string; points: MapTrackPoint[]; walk: number; ride: number; from: number; to: number; vehicles: string[] };
export type MapPlaybackFrame = { tracks: MapTrack[]; span: { from: number; to: number } };
export type MapSceneData = MapPlaybackFrame & {
points: Record<string, unknown>[]; settings?: Record<string, unknown>; bounds: Record<string, unknown>; window: MapTimeWindow;
catalog: Map<string, string>; users: Array<{ key: string; label: string; count: number }>; playerLabels: Map<string, string>;
segments: Map<string, MapTrackSegment[]>;
};
export type SCUMFeatureWorkspace = { defaultDirectoryKey?: string; directories?: SCUMLogicalDirectory[]; files?: SCUMLogicalFile[]; configFields?: SCUMConfigField[]; map?: { mapId: string; mapVersion: string; precision: number; sampleDistance: number; sampleIntervalSeconds: number; retentionSeconds: number } };
@@ -0,0 +1,29 @@
import { scumVehicleFallbackIconUrl, scumVehicleIconPathFor } from "./scum-catalog.js";
// 48px thumbnails for 20px map markers and 26px playback markers. Catalog originals stay separate.
const icons: Record<string, string> = {
"items/vehicles/ico_bicycle_01_a.webp": new URL("../assets/map/vehicles/ico_bicycle_01_a.webp", import.meta.url).href,
"items/vehicles/ico_bicycle_02_a.webp": new URL("../assets/map/vehicles/ico_bicycle_02_a.webp", import.meta.url).href,
"items/vehicles/ico_cruiser.webp": new URL("../assets/map/vehicles/ico_cruiser.webp", import.meta.url).href,
"items/vehicles/ico_improraftbig.webp": new URL("../assets/map/vehicles/ico_improraftbig.webp", import.meta.url).href,
"items/vehicles/ico_improsmallraft.webp": new URL("../assets/map/vehicles/ico_improsmallraft.webp", import.meta.url).href,
"items/vehicles/ico_improwheelbarrow.webp": new URL("../assets/map/vehicles/ico_improwheelbarrow.webp", import.meta.url).href,
"items/vehicles/ico_kinglet_duster_a.webp": new URL("../assets/map/vehicles/ico_kinglet_duster_a.webp", import.meta.url).href,
"items/vehicles/ico_kinglet_mariner.webp": new URL("../assets/map/vehicles/ico_kinglet_mariner.webp", import.meta.url).href,
"items/vehicles/ico_laika.webp": new URL("../assets/map/vehicles/ico_laika.webp", import.meta.url).href,
"items/vehicles/ico_motorboat_02.webp": new URL("../assets/map/vehicles/ico_motorboat_02.webp", import.meta.url).href,
"items/vehicles/ico_motorcycle_01_a.webp": new URL("../assets/map/vehicles/ico_motorcycle_01_a.webp", import.meta.url).href,
"items/vehicles/ico_rager.webp": new URL("../assets/map/vehicles/ico_rager.webp", import.meta.url).href,
"items/vehicles/ico_ris.webp": new URL("../assets/map/vehicles/ico_ris.webp", import.meta.url).href,
"items/vehicles/ico_sidecarbike.webp": new URL("../assets/map/vehicles/ico_sidecarbike.webp", import.meta.url).href,
"items/vehicles/ico_sup_inhands.webp": new URL("../assets/map/vehicles/ico_sup_inhands.webp", import.meta.url).href,
"items/vehicles/ico_sup_vicinity.webp": new URL("../assets/map/vehicles/ico_sup_vicinity.webp", import.meta.url).href,
"items/vehicles/ico_tractor_01_a.webp": new URL("../assets/map/vehicles/ico_tractor_01_a.webp", import.meta.url).href,
"items/vehicles/ico_wheelbarrow.webp": new URL("../assets/map/vehicles/ico_wheelbarrow.webp", import.meta.url).href,
"items/vehicles/ico_wolfswagen.webp": new URL("../assets/map/vehicles/ico_wolfswagen.webp", import.meta.url).href,
"items/vehicles/motoredboat_a.webp": new URL("../assets/map/vehicles/motoredboat_a.webp", import.meta.url).href,
};
export function scumMapVehicleIconUrl(code: string): string {
return icons[scumVehicleIconPathFor(code)] || scumVehicleFallbackIconUrl(code);
}
@@ -83,10 +83,12 @@ type PageKey = "players" | "squads" | "live-map" | "gifts" | "workflows";
type PluginCollectionSurfaceKey = keyof typeof scumCollections;
type SCUMPlatformSurfaceKey = "players" | "vehicles" | "trajectories" | "vehicleLocks";
// Call budget per live-map load/15s refresh: 7 bounded plugin collections + 1 typed SCUM surface.
// Squads and members load once per refresh; hovering, selecting and playback issue 0 API calls.
const pageCollections: Record<PageKey, PluginCollectionSurfaceKey[]> = {
players: ["members", "activityEvents", "giftClaims", "pendingGifts", "giftDeliveries"],
squads: ["squads", "members", "flags"],
"live-map": ["mapPoints", "mapRegions", "mapSettings", "flags", "tradeGoods"],
"live-map": ["mapPoints", "mapRegions", "mapSettings", "flags", "squads", "members", "tradeGoods"],
gifts: ["gifts", "giftClaims", "pendingGifts", "giftDeliveries", "timedGiftEvents", "tradeGoods"],
workflows: ["events", "eventProduces", "eventRuns", "nativeEventRounds", "tasks", "activityEvents", "tradeGoods", "tradeEvents"]
};
File diff suppressed because it is too large Load Diff
@@ -5155,8 +5155,10 @@ export function vehicleAliasKeys(code: string): string[] {
}
const vehicleIconAliases: Record<string, string> = {};
const vehicleEntriesByIcon = new Map<string, ScumCatalogEntry>();
for (const entry of scumCatalogEntries) {
if (entry.kind !== "vehicle" || !entry.icon) continue;
if (!vehicleEntriesByIcon.has(entry.icon)) vehicleEntriesByIcon.set(entry.icon, entry);
for (const key of vehicleAliasKeys(entry.code)) vehicleIconAliases[key] = entry.icon;
}
@@ -5239,7 +5241,7 @@ export function scumVehicleEntry(vehicleCode: string): ScumCatalogEntry | undefi
for (const key of vehicleAliasKeys(vehicleCode)) {
const icon = vehicleIconAliases[key];
if (!icon) continue;
const entry = scumCatalogEntries.find((value) => value.kind === "vehicle" && value.icon === icon);
const entry = vehicleEntriesByIcon.get(icon);
if (entry) return entry;
}
return scumCatalogEntryFor(vehicleCode);