edit electricienne + poto
This commit is contained in:
+32
-32
@@ -39340,41 +39340,41 @@
|
|||||||
"rotation": [0, 0.0027, 0.0819],
|
"rotation": [0, 0.0027, 0.0819],
|
||||||
"scale": [1, 1, 1]
|
"scale": [1, 1, 1]
|
||||||
}
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "pylone",
|
||||||
|
"type": "Object3D",
|
||||||
|
"position": [-22.8219, 6.7669, 28.1767],
|
||||||
|
"rotation": [0, 0.0027, 0.0819],
|
||||||
|
"scale": [1, 1, 1],
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"name": "pylone",
|
||||||
|
"type": "Mesh",
|
||||||
|
"position": [-22.8219, 6.7669, 28.1767],
|
||||||
|
"rotation": [0, 0.0027, 0.0819],
|
||||||
|
"scale": [1, 1, 1]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "pylone",
|
||||||
|
"type": "Object3D",
|
||||||
|
"position": [-31.5396, 5.5095, 36.2489],
|
||||||
|
"rotation": [0, 0.0027, 0.0819],
|
||||||
|
"scale": [1, 1, 1],
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"name": "pylone",
|
||||||
|
"type": "Mesh",
|
||||||
|
"position": [-31.5396, 5.5095, 36.2489],
|
||||||
|
"rotation": [0, 0.0027, 0.0819],
|
||||||
|
"scale": [1, 1, 1]
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"id": "repair:pylon"
|
"id": "repair:pylon"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "pylone",
|
|
||||||
"type": "Object3D",
|
|
||||||
"position": [-22.8219, 6.7669, 28.1767],
|
|
||||||
"rotation": [0, 0.0027, 0.0819],
|
|
||||||
"scale": [1, 1, 1],
|
|
||||||
"children": [
|
|
||||||
{
|
|
||||||
"name": "pylone",
|
|
||||||
"type": "Mesh",
|
|
||||||
"position": [-22.8219, 6.7669, 28.1767],
|
|
||||||
"rotation": [0, 0.0027, 0.0819],
|
|
||||||
"scale": [1, 1, 1]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "pylone",
|
|
||||||
"type": "Object3D",
|
|
||||||
"position": [-31.5396, 5.5095, 36.2489],
|
|
||||||
"rotation": [0, 0.0027, 0.0819],
|
|
||||||
"scale": [1, 1, 1],
|
|
||||||
"children": [
|
|
||||||
{
|
|
||||||
"name": "pylone",
|
|
||||||
"type": "Mesh",
|
|
||||||
"position": [-31.5396, 5.5095, 36.2489],
|
|
||||||
"rotation": [0, 0.0027, 0.0819],
|
|
||||||
"scale": [1, 1, 1]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "pylone",
|
"name": "pylone",
|
||||||
"type": "Object3D",
|
"type": "Object3D",
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import { useGLTF } from "@react-three/drei";
|
|||||||
import * as THREE from "three";
|
import * as THREE from "three";
|
||||||
import { InteractableObject } from "@/components/three/interaction/InteractableObject";
|
import { InteractableObject } from "@/components/three/interaction/InteractableObject";
|
||||||
import { useGameStore } from "@/managers/stores/useGameStore";
|
import { useGameStore } from "@/managers/stores/useGameStore";
|
||||||
|
import { useRepairMissionAnchorStore } from "@/managers/stores/useRepairMissionAnchorStore";
|
||||||
|
import { useTerrainSnappedPosition } from "@/hooks/three/useTerrainHeight";
|
||||||
import { loadDialogueManifest } from "@/utils/dialogues/loadDialogueManifest";
|
import { loadDialogueManifest } from "@/utils/dialogues/loadDialogueManifest";
|
||||||
import { playDialogueById } from "@/utils/dialogues/playDialogue";
|
import { playDialogueById } from "@/utils/dialogues/playDialogue";
|
||||||
import {
|
import {
|
||||||
@@ -14,6 +16,7 @@ import {
|
|||||||
PYLON_UPRIGHT_ROTATION,
|
PYLON_UPRIGHT_ROTATION,
|
||||||
PYLON_WORLD_POSITION,
|
PYLON_WORLD_POSITION,
|
||||||
} from "@/data/gameplay/pylonConfig";
|
} from "@/data/gameplay/pylonConfig";
|
||||||
|
import { isRepairGameStep } from "@/types/gameplay/repairMission";
|
||||||
import { pylonStraighteningSignal } from "@/components/gameplay/pylon/pylonSignals";
|
import { pylonStraighteningSignal } from "@/components/gameplay/pylon/pylonSignals";
|
||||||
|
|
||||||
const PYLON_MODEL_PATH = "/models/pylone/model.glb";
|
const PYLON_MODEL_PATH = "/models/pylone/model.glb";
|
||||||
@@ -22,6 +25,15 @@ export function PylonDownedPylon(): React.JSX.Element | null {
|
|||||||
const mainState = useGameStore((state) => state.mainState);
|
const mainState = useGameStore((state) => state.mainState);
|
||||||
const step = useGameStore((state) => state.pylon.currentStep);
|
const step = useGameStore((state) => state.pylon.currentStep);
|
||||||
const setCanMove = useGameStore((state) => state.setCanMove);
|
const setCanMove = useGameStore((state) => state.setCanMove);
|
||||||
|
// Use the repair:pylon anchor from the store so the downed pylon is always
|
||||||
|
// co-located with the instanced mesh it replaces. Falls back to the
|
||||||
|
// hard-coded constant while the map is loading or unavailable.
|
||||||
|
const pylonAnchor = useRepairMissionAnchorStore(
|
||||||
|
(state) => state.anchors.pylon,
|
||||||
|
);
|
||||||
|
// Snap to terrain so the downed/upright model sits flush on the ground,
|
||||||
|
// matching the Y adjustment that InstancedMapAsset applies to the same node.
|
||||||
|
const position = useTerrainSnappedPosition(pylonAnchor ?? PYLON_WORLD_POSITION);
|
||||||
const [isStraightening, setIsStraightening] = useState(false);
|
const [isStraightening, setIsStraightening] = useState(false);
|
||||||
// Keeps the pylon upright after the animation completes while
|
// Keeps the pylon upright after the animation completes while
|
||||||
// PylonFarmerNPC plays the post-raise audio sequence.
|
// PylonFarmerNPC plays the post-raise audio sequence.
|
||||||
@@ -30,6 +42,10 @@ export function PylonDownedPylon(): React.JSX.Element | null {
|
|||||||
const straightenStartRef = useRef<number | null>(null);
|
const straightenStartRef = useRef<number | null>(null);
|
||||||
const hasPlayedFirstAudioRef = useRef(false);
|
const hasPlayedFirstAudioRef = useRef(false);
|
||||||
|
|
||||||
|
// Hidden outside the pylon mission and once the pylon has been raised
|
||||||
|
// (repair-game steps take over from there).
|
||||||
|
const shouldRender = mainState === "pylon" && !isRepairGameStep(step);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (step === "arrived") {
|
if (step === "arrived") {
|
||||||
hasPlayedFirstAudioRef.current = false;
|
hasPlayedFirstAudioRef.current = false;
|
||||||
@@ -44,7 +60,7 @@ export function PylonDownedPylon(): React.JSX.Element | null {
|
|||||||
if (!group) return;
|
if (!group) return;
|
||||||
|
|
||||||
if (!isStraightening || straightenStartRef.current === null) {
|
if (!isStraightening || straightenStartRef.current === null) {
|
||||||
group.rotation.set(...(showUpright ? PYLON_UPRIGHT_ROTATION : PYLON_DOWNED_ROTATION));
|
group.rotation.set(...(isRaised ? PYLON_UPRIGHT_ROTATION : PYLON_DOWNED_ROTATION));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,18 +76,6 @@ export function PylonDownedPylon(): React.JSX.Element | null {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
const showUpright =
|
|
||||||
isRaised ||
|
|
||||||
mainState !== "pylon" ||
|
|
||||||
step === "waiting" ||
|
|
||||||
step === "inspected" ||
|
|
||||||
step === "fragmented" ||
|
|
||||||
step === "scanning" ||
|
|
||||||
step === "repairing" ||
|
|
||||||
step === "reassembling" ||
|
|
||||||
step === "done" ||
|
|
||||||
step === "narrator-outro";
|
|
||||||
|
|
||||||
const isPylonInteractive = step === "arrived" || step === "npc-return";
|
const isPylonInteractive = step === "arrived" || step === "npc-return";
|
||||||
|
|
||||||
const beginStraighten = (): void => {
|
const beginStraighten = (): void => {
|
||||||
@@ -94,10 +98,12 @@ export function PylonDownedPylon(): React.JSX.Element | null {
|
|||||||
}, PYLON_STRAIGHTEN_ANIMATION_DURATION_MS);
|
}, PYLON_STRAIGHTEN_ANIMATION_DURATION_MS);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (!shouldRender) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<group
|
<group
|
||||||
ref={groupRef}
|
ref={groupRef}
|
||||||
position={PYLON_WORLD_POSITION}
|
position={position}
|
||||||
rotation={PYLON_DOWNED_ROTATION}
|
rotation={PYLON_DOWNED_ROTATION}
|
||||||
>
|
>
|
||||||
<primitive object={scene.clone(true)} />
|
<primitive object={scene.clone(true)} />
|
||||||
@@ -107,7 +113,7 @@ export function PylonDownedPylon(): React.JSX.Element | null {
|
|||||||
label={
|
label={
|
||||||
step === "arrived" ? "Inspecter le pylône" : "Redresser le pylône"
|
step === "arrived" ? "Inspecter le pylône" : "Redresser le pylône"
|
||||||
}
|
}
|
||||||
position={PYLON_WORLD_POSITION}
|
position={position}
|
||||||
radius={PYLON_NARRATIVE_INTERACT_RADIUS}
|
radius={PYLON_NARRATIVE_INTERACT_RADIUS}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
if (step === "arrived") {
|
if (step === "arrived") {
|
||||||
|
|||||||
@@ -40,9 +40,32 @@ function faceToward(from: THREE.Vector3, to: readonly [number, number, number]):
|
|||||||
return Math.atan2(dx, dz);
|
return Math.atan2(dx, dz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Outer shell — only checks visibility conditions.
|
||||||
|
* Rendering is delegated to PylonFarmerNPCContent so that the heavy hooks
|
||||||
|
* (useFrame, useAnimations) are only active while the NPC is actually shown.
|
||||||
|
*/
|
||||||
export function PylonFarmerNPC(): React.JSX.Element | null {
|
export function PylonFarmerNPC(): React.JSX.Element | null {
|
||||||
const mainState = useGameStore((state) => state.mainState);
|
const mainState = useGameStore((state) => state.mainState);
|
||||||
const step = useGameStore((state) => state.pylon.currentStep);
|
const step = useGameStore((state) => state.pylon.currentStep);
|
||||||
|
|
||||||
|
if (mainState !== "pylon") return null;
|
||||||
|
// Visible during narrative + at repair completion (hides during repair steps)
|
||||||
|
if (
|
||||||
|
step !== "arrived" &&
|
||||||
|
step !== "npc-return" &&
|
||||||
|
step !== "inspected" &&
|
||||||
|
step !== "done"
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return <PylonFarmerNPCContent />;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─── Inner component — heavy hooks only run when NPC is mounted ──────────────
|
||||||
|
function PylonFarmerNPCContent(): React.JSX.Element {
|
||||||
|
const step = useGameStore((state) => state.pylon.currentStep);
|
||||||
const setMissionStep = useGameStore((state) => state.setMissionStep);
|
const setMissionStep = useGameStore((state) => state.setMissionStep);
|
||||||
const camera = useThree((state) => state.camera);
|
const camera = useThree((state) => state.camera);
|
||||||
|
|
||||||
@@ -69,8 +92,6 @@ export function PylonFarmerNPC(): React.JSX.Element | null {
|
|||||||
const { actions } = useAnimations(animations, model);
|
const { actions } = useAnimations(animations, model);
|
||||||
|
|
||||||
// ─── playAnim ─────────────────────────────────────────────────────────────
|
// ─── playAnim ─────────────────────────────────────────────────────────────
|
||||||
// NOTE: actions is intentionally in the dep array so this callback is
|
|
||||||
// recreated when drei's internal state populates the actions map.
|
|
||||||
const playAnim = useCallback(
|
const playAnim = useCallback(
|
||||||
(name: NPCAnimation, fade = ANIM_FADE): void => {
|
(name: NPCAnimation, fade = ANIM_FADE): void => {
|
||||||
if (currentAnimRef.current === name) return;
|
if (currentAnimRef.current === name) return;
|
||||||
@@ -94,7 +115,6 @@ export function PylonFarmerNPC(): React.JSX.Element | null {
|
|||||||
const playPostRaiseAudioAndAdvance = useCallback(async () => {
|
const playPostRaiseAudioAndAdvance = useCallback(async () => {
|
||||||
const manifest = await loadDialogueManifest();
|
const manifest = await loadDialogueManifest();
|
||||||
if (manifest) {
|
if (manifest) {
|
||||||
// "N'hésite pas, si tu as besoin d'autre chose !"
|
|
||||||
const audio = await playDialogueById(
|
const audio = await playDialogueById(
|
||||||
manifest,
|
manifest,
|
||||||
PYLON_NARRATIVE_DIALOGUES.electricienneApresMontage,
|
PYLON_NARRATIVE_DIALOGUES.electricienneApresMontage,
|
||||||
@@ -111,7 +131,6 @@ export function PylonFarmerNPC(): React.JSX.Element | null {
|
|||||||
}, [setMissionStep]);
|
}, [setMissionStep]);
|
||||||
|
|
||||||
// ─── Step-driven animation ────────────────────────────────────────────────
|
// ─── Step-driven animation ────────────────────────────────────────────────
|
||||||
// Fires when step changes OR when playAnim changes (i.e. when actions load).
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
currentAnimRef.current = null;
|
currentAnimRef.current = null;
|
||||||
if (step === "arrived") {
|
if (step === "arrived") {
|
||||||
@@ -124,6 +143,15 @@ export function PylonFarmerNPC(): React.JSX.Element | null {
|
|||||||
playAnim("walk");
|
playAnim("walk");
|
||||||
} else if (step === "inspected") {
|
} else if (step === "inspected") {
|
||||||
playAnim("idle");
|
playAnim("idle");
|
||||||
|
} else if (step === "done") {
|
||||||
|
// NPC reappears at repair completion — position at the post-raise spot,
|
||||||
|
// facing the pylon, playing idle.
|
||||||
|
currentPosRef.current.set(...PYLON_FARMER_NPC_AFTER_POSITION_pylone_straight);
|
||||||
|
savedRotationYRef.current = faceToward(
|
||||||
|
currentPosRef.current,
|
||||||
|
PYLON_WORLD_POSITION,
|
||||||
|
);
|
||||||
|
playAnim("idle");
|
||||||
}
|
}
|
||||||
}, [step, playAnim]);
|
}, [step, playAnim]);
|
||||||
|
|
||||||
@@ -171,7 +199,7 @@ export function PylonFarmerNPC(): React.JSX.Element | null {
|
|||||||
savedRotationYRef.current = faceToward(currentPosRef.current, PYLON_WORLD_POSITION);
|
savedRotationYRef.current = faceToward(currentPosRef.current, PYLON_WORLD_POSITION);
|
||||||
}
|
}
|
||||||
group.position.copy(currentPosRef.current);
|
group.position.copy(currentPosRef.current);
|
||||||
} else if (step === "inspected") {
|
} else if (step === "inspected" || step === "done") {
|
||||||
group.position.set(...PYLON_FARMER_NPC_AFTER_POSITION_pylone_straight);
|
group.position.set(...PYLON_FARMER_NPC_AFTER_POSITION_pylone_straight);
|
||||||
} else if (isCompleted) {
|
} else if (isCompleted) {
|
||||||
group.position.copy(currentPosRef.current);
|
group.position.copy(currentPosRef.current);
|
||||||
@@ -190,10 +218,6 @@ export function PylonFarmerNPC(): React.JSX.Element | null {
|
|||||||
group.scale.setScalar(PYLON_FARMER_NPC_AFTER_SCALE);
|
group.scale.setScalar(PYLON_FARMER_NPC_AFTER_SCALE);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (mainState !== "pylon") return null;
|
|
||||||
if (step !== "arrived" && step !== "npc-return" && step !== "inspected")
|
|
||||||
return null;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<group ref={groupRef} position={PYLON_FARMER_NPC_POSITION}>
|
<group ref={groupRef} position={PYLON_FARMER_NPC_POSITION}>
|
||||||
<primitive object={model} />
|
<primitive object={model} />
|
||||||
@@ -204,6 +228,13 @@ export function PylonFarmerNPC(): React.JSX.Element | null {
|
|||||||
position={PYLON_FARMER_NPC_POSITION}
|
position={PYLON_FARMER_NPC_POSITION}
|
||||||
radius={PYLON_NARRATIVE_INTERACT_RADIUS}
|
radius={PYLON_NARRATIVE_INTERACT_RADIUS}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
|
// Turn to face the player the moment they engage the NPC
|
||||||
|
savedRotationYRef.current = faceToward(currentPosRef.current, [
|
||||||
|
camera.position.x,
|
||||||
|
camera.position.y,
|
||||||
|
camera.position.z,
|
||||||
|
]);
|
||||||
|
|
||||||
void (async () => {
|
void (async () => {
|
||||||
const manifest = await loadDialogueManifest();
|
const manifest = await loadDialogueManifest();
|
||||||
if (!manifest) {
|
if (!manifest) {
|
||||||
|
|||||||
@@ -45,7 +45,12 @@ export function PylonNarrativeFlow(): React.JSX.Element | null {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (step === "arrived" || step === "npc-return" || step === "inspected") {
|
if (
|
||||||
|
step === "arrived" ||
|
||||||
|
step === "npc-return" ||
|
||||||
|
step === "inspected" ||
|
||||||
|
step === "done"
|
||||||
|
) {
|
||||||
return <PylonFarmerNPC />;
|
return <PylonFarmerNPC />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ export interface MapNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface MapNodeInstanceTransform {
|
export interface MapNodeInstanceTransform {
|
||||||
|
/** Node id from map.json — preserved so specific instances can be excluded at runtime. */
|
||||||
|
id?: string;
|
||||||
position: Vector3Tuple;
|
position: Vector3Tuple;
|
||||||
rotation: Vector3Tuple;
|
rotation: Vector3Tuple;
|
||||||
scale: Vector3Tuple;
|
scale: Vector3Tuple;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ export function mapNodeToInstanceTransform(
|
|||||||
node: MapNode,
|
node: MapNode,
|
||||||
): MapNodeInstanceTransform {
|
): MapNodeInstanceTransform {
|
||||||
return {
|
return {
|
||||||
|
id: node.id,
|
||||||
position: node.position,
|
position: node.position,
|
||||||
rotation: node.rotation,
|
rotation: node.rotation,
|
||||||
scale: node.scale,
|
scale: node.scale,
|
||||||
|
|||||||
@@ -264,7 +264,7 @@ export function TestMap({ onOctreeReady }: TestMapProps): React.JSX.Element {
|
|||||||
</mesh>
|
</mesh>
|
||||||
*/}
|
*/}
|
||||||
{/* GPS Map screen plane */}
|
{/* GPS Map screen plane */}
|
||||||
<group position={[0, 0, 0.06]}>
|
<group position={[0, -8, 0.06]}>
|
||||||
<EbikeGPSMap
|
<EbikeGPSMap
|
||||||
width={4}
|
width={4}
|
||||||
height={4}
|
height={4}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import {
|
|||||||
isMapModelVisible,
|
isMapModelVisible,
|
||||||
useMapPerformanceStore,
|
useMapPerformanceStore,
|
||||||
} from "@/managers/stores/useMapPerformanceStore";
|
} from "@/managers/stores/useMapPerformanceStore";
|
||||||
|
import { useGameStore } from "@/managers/stores/useGameStore";
|
||||||
import { InstancedMapAsset } from "@/world/map-instancing/InstancedMapAsset";
|
import { InstancedMapAsset } from "@/world/map-instancing/InstancedMapAsset";
|
||||||
import {
|
import {
|
||||||
MAP_INSTANCING_ASSETS,
|
MAP_INSTANCING_ASSETS,
|
||||||
@@ -27,6 +28,8 @@ import {
|
|||||||
type MapInstancingAssetConfig,
|
type MapInstancingAssetConfig,
|
||||||
type MapInstancingAssetType,
|
type MapInstancingAssetType,
|
||||||
} from "@/data/world/mapInstancingConfig";
|
} from "@/data/world/mapInstancingConfig";
|
||||||
|
import { REPAIR_MISSION_ANCHOR_IDS } from "@/data/gameplay/repairMissionAnchors";
|
||||||
|
import { isRepairGameStep } from "@/types/gameplay/repairMission";
|
||||||
import { useMapInstancingData } from "@/hooks/world/useMapInstancingData";
|
import { useMapInstancingData } from "@/hooks/world/useMapInstancingData";
|
||||||
import type { MapAssetInstance } from "@/types/map/mapScene";
|
import type { MapAssetInstance } from "@/types/map/mapScene";
|
||||||
import type { GraphicsPreset } from "@/data/world/graphicsConfig";
|
import type { GraphicsPreset } from "@/data/world/graphicsConfig";
|
||||||
@@ -146,6 +149,8 @@ export function MapInstancingSystem({
|
|||||||
const groups = useMapPerformanceStore((state) => state.groups);
|
const groups = useMapPerformanceStore((state) => state.groups);
|
||||||
const models = useMapPerformanceStore((state) => state.models);
|
const models = useMapPerformanceStore((state) => state.models);
|
||||||
const { data, isLoading } = useMapInstancingData();
|
const { data, isLoading } = useMapInstancingData();
|
||||||
|
const mainState = useGameStore((state) => state.mainState);
|
||||||
|
const pylonStep = useGameStore((state) => state.pylon.currentStep);
|
||||||
const streamingEnabled =
|
const streamingEnabled =
|
||||||
streaming &&
|
streaming &&
|
||||||
CHUNK_CONFIG.enabled &&
|
CHUNK_CONFIG.enabled &&
|
||||||
@@ -153,6 +158,15 @@ export function MapInstancingSystem({
|
|||||||
sceneMode === "game" &&
|
sceneMode === "game" &&
|
||||||
cameraMode === "player";
|
cameraMode === "player";
|
||||||
|
|
||||||
|
// During the pylon narrative phase (before the pylon is raised), hide the
|
||||||
|
// repair:pylon instanced mesh so the PylonDownedPylon component takes its place.
|
||||||
|
// Once the pylon is raised (repair-game steps), restore it so the normal model
|
||||||
|
// appears upright in the world while the repair mini-game runs.
|
||||||
|
const hidePylonAnchorId =
|
||||||
|
mainState === "pylon" && !isRepairGameStep(pylonStep)
|
||||||
|
? REPAIR_MISSION_ANCHOR_IDS.pylon
|
||||||
|
: undefined;
|
||||||
|
|
||||||
const chunks = useMemo(() => {
|
const chunks = useMemo(() => {
|
||||||
if (!data) return [];
|
if (!data) return [];
|
||||||
|
|
||||||
@@ -168,12 +182,18 @@ export function MapInstancingSystem({
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const instances = data.get(type);
|
let instances = data.get(type);
|
||||||
if (!instances || instances.length === 0) return [];
|
if (!instances || instances.length === 0) return [];
|
||||||
|
|
||||||
|
// Filter out the repair-mission pylon instance during the narrative phase
|
||||||
|
if (hidePylonAnchorId && config.mapName === "pylone") {
|
||||||
|
instances = instances.filter((inst) => inst.id !== hidePylonAnchorId);
|
||||||
|
if (instances.length === 0) return [];
|
||||||
|
}
|
||||||
|
|
||||||
return createMapAssetChunks(type, config, instances);
|
return createMapAssetChunks(type, config, instances);
|
||||||
});
|
});
|
||||||
}, [data, groups, models, onlyMapName]);
|
}, [data, groups, models, onlyMapName, hidePylonAnchorId]);
|
||||||
|
|
||||||
const visibleChunks = useVisibleWorldChunks(chunks, streamingEnabled, {
|
const visibleChunks = useVisibleWorldChunks(chunks, streamingEnabled, {
|
||||||
loadRadius: graphicsPresetConfig.chunkLoadRadius,
|
loadRadius: graphicsPresetConfig.chunkLoadRadius,
|
||||||
|
|||||||
Reference in New Issue
Block a user