diff --git a/traque-back/zone_manager.js b/traque-back/zone_manager.js index e2e8203..2cd6598 100644 --- a/traque-back/zone_manager.js +++ b/traque-back/zone_manager.js @@ -38,6 +38,8 @@ export default { updateIntervalId: null, nextZoneTimeoutId: null, + nextZoneDate: null, + /** * Test if a given configuration object is valid, i.e if all needed values are well defined * @param {Object} settings Settings object describing a config of a zone manager @@ -143,6 +145,7 @@ export default { * Wait for the appropriate duration before starting a new zone reduction if needed */ setNextZone() { + this.nextZoneDate = Date.now() + this.zoneSettings.reductionInterval * 60 * 1000; //At this point, nextZone == currentZone, we need to update the next zone, the raidus decrement, and start a timer before the next shrink //last zone if (this.currentZoneCount == this.zoneSettings.reductionCount) { @@ -168,7 +171,8 @@ export default { this.onZoneUpdate(JSON.parse(JSON.stringify(this.currentStartZone))) this.onNextZoneUpdate({ begin: JSON.parse(JSON.stringify(this.currentStartZone)), - end: JSON.parse(JSON.stringify(this.nextZone)) + end: JSON.parse(JSON.stringify(this.nextZone)), + endDate: JSON.parse(JSON.stringify(this.nextZoneDate)), }) return true; }, @@ -179,6 +183,8 @@ export default { * If the reduction is over this function will call setNextZone */ startShrinking() { + this.nextZoneDate = Date.now() + this.zoneSettings.reductionDuration * 60 * 1000; + this.onZoneUpdateStart(JSON.parse(JSON.stringify(this.nextZoneDate))); const startTime = new Date(); this.updateIntervalId = setInterval(() => { const completed = ((new Date() - startTime) / (1000 * 60)) / this.zoneSettings.reductionDuration; @@ -202,6 +208,12 @@ export default { secureAdminBroadcast("new_zone", newZone) }, + //a call to onZoneUpdateStart will be made when the zone reduction starts + onZoneUpdateStart(date) { + playersBroadcast("zone_start", date) + secureAdminBroadcast("zone_start", date) + }, + //a call to onZoneUpdate will be made every updateIntervalSeconds when the zone is changing onZoneUpdate(zone) { playersBroadcast("zone", zone) diff --git a/traque-front/components/admin/mapPicker.jsx b/traque-front/components/admin/mapPicker.jsx index 6d58c30..24e07a5 100644 --- a/traque-front/components/admin/mapPicker.jsx +++ b/traque-front/components/admin/mapPicker.jsx @@ -105,30 +105,55 @@ export function ZonePicker({ minZone, setMinZone, maxZone, setMaxZone, editMode, export function LiveMap() { const location = useLocation(Infinity); - const { zone, zoneExtremities, teams, getTeamName } = useAdmin(); + const [timeLeftNextZone, setTimeLeftNextZone] = useState(null); + const { zone, zoneExtremities, teams, getTeamName, nextZoneDate, isShrinking } = useAdmin(); + + // Remaining time before sending position + useEffect(() => { + const updateTime = () => { + setTimeLeftNextZone(Math.max(0, Math.floor((nextZoneDate - Date.now()) / 1000))); + }; + + updateTime(); + const interval = setInterval(updateTime, 1000); + + return () => clearInterval(interval); + }, [nextZoneDate]); + + function formatTime(time) { + // time is in seconds + if (time < 0) return "00:00"; + const minutes = Math.floor(time / 60); + const seconds = Math.floor(time % 60); + return String(minutes).padStart(2,"0") + ":" + String(seconds).padStart(2,"0"); + } + return ( - - - - {zone && } - {zoneExtremities && } - {zoneExtremities && } - {teams.map((team) => team.currentLocation && !team.captured && - - {team.name} -

Chasing : {getTeamName(team.chasing)}

-

Chased by : {getTeamName(team.chased)}

-
-
)} -
+
+

{`${isShrinking ? "Fin" : "Début"} du rétrécissement de la zone dans : ${formatTime(timeLeftNextZone)}`}

+ + + + {zone && } + {zoneExtremities && } + {zoneExtremities && } + {teams.map((team) => team.currentLocation && !team.captured && + + {team.name} +

Chasing : {getTeamName(team.chasing)}

+

Chased by : {getTeamName(team.chased)}

+
+
)} +
+
) } \ No newline at end of file diff --git a/traque-front/context/adminContext.jsx b/traque-front/context/adminContext.jsx index 0c94189..6c7bcef 100644 --- a/traque-front/context/adminContext.jsx +++ b/traque-front/context/adminContext.jsx @@ -14,6 +14,8 @@ function AdminProvider({ children }) { const [gameSettings, setGameSettings] = useState(null); const [zone, setZone] = useState(null); const [zoneExtremities, setZoneExtremities] = useState(null); + const [nextZoneDate, setNextZoneDate] = useState(null); + const [isShrinking, setIsShrinking] = useState(false); const { adminSocket } = useSocket(); const { loggedIn } = useAdminConnexion(); const [gameState, setGameState] = useState(GameState.SETUP); @@ -24,15 +26,27 @@ function AdminProvider({ children }) { adminSocket.emit("get_teams"); }, [loggedIn]); + function waiting(data) { + setIsShrinking(false); + setZoneExtremities({begin: data.begin, end: data.end}); + setNextZoneDate(data.endDate); + } + + function shrinking(data) { + setIsShrinking(true); + setNextZoneDate(data); + } + //Bind listeners to update the team list and the game status on socket message useSocketListener(adminSocket, "teams", setTeams); useSocketListener(adminSocket, "zone_settings", setZoneSettings); useSocketListener(adminSocket, "game_settings", setGameSettings); useSocketListener(adminSocket, "penalty_settings", setPenaltySettings); useSocketListener(adminSocket, "zone", setZone); - useSocketListener(adminSocket, "new_zone", setZoneExtremities); + useSocketListener(adminSocket, "zone_start", shrinking); + useSocketListener(adminSocket, "new_zone", waiting); - const value = useMemo(() => ({ zone, zoneExtremities, teams, zoneSettings, penaltySettings, gameSettings, gameState }), [zoneSettings, teams, gameState, zone, zoneExtremities, penaltySettings, gameSettings]); + const value = useMemo(() => ({ zone, zoneExtremities, teams, zoneSettings, penaltySettings, gameSettings, gameState, nextZoneDate, isShrinking }), [zoneSettings, teams, gameState, zone, zoneExtremities, penaltySettings, gameSettings, nextZoneDate, isShrinking]); return ( {children}