Files
La-Fabrik/src/world/map-instancing/MapInstancingSystem.tsx
T
Tom Boullay 093ffd726d
🔍 Lint / 🪄 Check lint (pull_request) Has been cancelled
🔍 Lint / 🎨 Check format (pull_request) Has been cancelled
🔍 Lint / 🔎 Typecheck (pull_request) Has been cancelled
📊 Quality / 🔒 Security Audit (pull_request) Has been cancelled
📊 Quality / 📋 Dependency Freshness (pull_request) Has been cancelled
📊 Quality / 📦 Bundle Size (pull_request) Has been cancelled
🔍 Lint / 🏗 Build (pull_request) Has been cancelled
fix(review): address audit findings before merge
2026-05-29 01:23:08 +02:00

109 lines
3.2 KiB
TypeScript

import { Suspense, useMemo } from "react";
import { CHUNK_CONFIG } from "@/data/world/chunkStreamingConfig";
import { useCameraMode } from "@/hooks/debug/useCameraMode";
import { useSceneMode } from "@/hooks/debug/useSceneMode";
import { useVisibleWorldChunks } from "@/hooks/world/useVisibleWorldChunks";
import {
isMapModelVisible,
useMapPerformanceStore,
} from "@/managers/stores/useMapPerformanceStore";
import { InstancedMapAsset } from "@/world/map-instancing/InstancedMapAsset";
import {
MAP_INSTANCING_ASSETS,
MAP_INSTANCING_ASSET_TYPES,
type MapInstancingAssetConfig,
type MapInstancingAssetType,
} from "@/data/world/mapInstancingConfig";
import { useMapInstancingData } from "@/hooks/world/useMapInstancingData";
import type { MapAssetInstance } from "@/types/map/mapScene";
import { createWorldInstanceChunks } from "@/utils/world/chunkInstances";
interface MapInstancingSystemProps {
onlyMapName?: string | null;
streaming?: boolean;
}
interface MapAssetChunk {
key: string;
config: MapInstancingAssetConfig;
centerX: number;
centerZ: number;
instances: MapAssetInstance[];
}
function createMapAssetChunks(
type: MapInstancingAssetType,
config: MapInstancingAssetConfig,
instances: MapAssetInstance[],
): MapAssetChunk[] {
return createWorldInstanceChunks(instances).map((chunk) => {
return {
key: `${type}:${chunk.chunkKey}`,
config,
centerX: chunk.centerX,
centerZ: chunk.centerZ,
instances: chunk.instances,
};
});
}
export function MapInstancingSystem({
onlyMapName = null,
streaming = true,
}: MapInstancingSystemProps): React.JSX.Element | null {
const cameraMode = useCameraMode();
const sceneMode = useSceneMode();
const groups = useMapPerformanceStore((state) => state.groups);
const models = useMapPerformanceStore((state) => state.models);
const { data, isLoading } = useMapInstancingData();
const streamingEnabled =
streaming &&
CHUNK_CONFIG.enabled &&
sceneMode === "game" &&
cameraMode === "player";
const chunks = useMemo(() => {
if (!data) return [];
return MAP_INSTANCING_ASSET_TYPES.flatMap((type) => {
const config = MAP_INSTANCING_ASSETS[type];
if (onlyMapName && config.mapName !== onlyMapName) return [];
if (
!config.enabled ||
!isMapModelVisible(config.mapName, { groups, models })
) {
return [];
}
const instances = data.get(type);
if (!instances || instances.length === 0) return [];
return createMapAssetChunks(type, config, instances);
});
}, [data, groups, models, onlyMapName]);
const visibleChunks = useVisibleWorldChunks(chunks, streamingEnabled);
if (isLoading || !data) {
return null;
}
return (
<group name="map-instancing-system">
{visibleChunks.map((chunk) => (
<Suspense key={chunk.key} fallback={null}>
<InstancedMapAsset
modelPath={chunk.config.modelPath}
instances={chunk.instances}
scaleMultiplier={chunk.config.scaleMultiplier}
castShadow={chunk.config.castShadow}
receiveShadow={chunk.config.receiveShadow}
/>
</Suspense>
))}
</group>
);
}