mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-09-15 17:12:59 -04:00
111 lines
3.8 KiB
React
111 lines
3.8 KiB
React
// Hud Overlay
|
|
// Purpose: Defines the Hud Overlay module and the local helpers/components used in this file.
|
|
// Scope: Keeps behavior unchanged while isolating this concern into a clear, single-responsibility unit.
|
|
import React from 'react';
|
|
import { useHudMapSetting } from '../../../hooks/useHudMapSetting.js';
|
|
import { useSessionSelector } from '../../../context/SessionContext.jsx';
|
|
import { useTelemetryFrame } from '../../../context/TelemetryContext.jsx';
|
|
import RoverLabelOverlay from './RoverLabelOverlay.jsx';
|
|
import SpectatorTelemetryOverlay from './SpectatorTelemetryOverlay.jsx';
|
|
import HudMapOverlay from './HudMapOverlay.jsx';
|
|
|
|
function HudOverlay({
|
|
roverId = null,
|
|
sensors,
|
|
label,
|
|
roverColor = null,
|
|
layoutFormat = 'desktop',
|
|
variant = 'default',
|
|
driverLabel = null,
|
|
showTopDown = undefined,
|
|
mobileHud = false,
|
|
mapPosition = null,
|
|
labelScale = 1,
|
|
}) {
|
|
const assignedRoverId = useSessionSelector((state) => state.session?.assignment?.roverId ?? null);
|
|
const effectiveRoverId = roverId ?? assignedRoverId;
|
|
const frame = useTelemetryFrame(effectiveRoverId);
|
|
const rosterInfo = useSessionSelector((state) => {
|
|
if (!effectiveRoverId) return { label: null, roverColor: null };
|
|
const roster = state.session?.roster || [];
|
|
const rover = roster.find((entry) => String(entry.id) === String(effectiveRoverId));
|
|
return {
|
|
label: rover?.name || null,
|
|
roverColor: rover?.color || null,
|
|
};
|
|
});
|
|
const derivedDriverLabel = useSessionSelector((state) => {
|
|
if (!effectiveRoverId || variant !== 'spectator') return null;
|
|
const activeId = state.session?.activeDrivers?.[effectiveRoverId] || null;
|
|
const users = state.session?.users || [];
|
|
const match = users.find((u) => String(u.socketId || '') === String(activeId || ''));
|
|
return match?.nickname || match?.name || null;
|
|
});
|
|
const resolvedSensors = sensors ?? frame?.sensors ?? null;
|
|
const resolvedLabel = label ?? rosterInfo.label ?? null;
|
|
const resolvedRoverColor = roverColor ?? rosterInfo.roverColor ?? null;
|
|
const resolvedDriverLabel = driverLabel ?? derivedDriverLabel;
|
|
const isMobile = mobileHud;
|
|
const [showHudMapDesktop] = useHudMapSetting();
|
|
const resolvedShowTopDown =
|
|
typeof showTopDown === 'boolean'
|
|
? showTopDown
|
|
: variant === 'spectator'
|
|
? true
|
|
: isMobile
|
|
? true
|
|
: showHudMapDesktop;
|
|
const resolvedMapPosition =
|
|
mapPosition || (variant === 'spectator' ? 'top-center' : isMobile ? 'top-right' : 'top-center');
|
|
|
|
if (variant === 'none') {
|
|
return null;
|
|
}
|
|
|
|
if (variant === 'spectator') {
|
|
return (
|
|
<>
|
|
<div className="pointer-events-none absolute inset-0 flex items-center justify-center">
|
|
<SpectatorTelemetryOverlay sensors={resolvedSensors} mobileHud={isMobile} />
|
|
<RoverLabelOverlay
|
|
variant="spectator"
|
|
label={resolvedLabel}
|
|
roverColor={resolvedRoverColor}
|
|
driverLabel={resolvedDriverLabel}
|
|
mobileHud={isMobile}
|
|
labelScale={labelScale}
|
|
/>
|
|
</div>
|
|
<HudMapOverlay
|
|
sensors={resolvedSensors}
|
|
show={resolvedShowTopDown}
|
|
mapPosition={resolvedMapPosition}
|
|
layoutFormat={layoutFormat}
|
|
mobileHud={isMobile}
|
|
/>
|
|
</>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="pointer-events-none absolute inset-0 flex items-center justify-center">
|
|
<RoverLabelOverlay
|
|
variant="default"
|
|
label={resolvedLabel}
|
|
roverColor={resolvedRoverColor}
|
|
mobileHud={isMobile}
|
|
labelScale={labelScale}
|
|
/>
|
|
<HudMapOverlay
|
|
sensors={resolvedSensors}
|
|
show={resolvedShowTopDown && variant !== 'spectator'}
|
|
mapPosition={resolvedMapPosition}
|
|
layoutFormat={layoutFormat}
|
|
mobileHud={isMobile}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default React.memo(HudOverlay);
|