From cbd90a5e364de9586a909b81b866b6e95942396d Mon Sep 17 00:00:00 2001 From: Raffson Date: Sat, 18 May 2024 21:11:28 +0200 Subject: [PATCH] Sync MapZones when changing campaigns --- client/src/api/_liberationApi.ts | 1 + client/src/api/mapZonesSlice.ts | 35 +++++++++++++++++++ client/src/app/store.ts | 2 ++ .../terrainzones/TerrainZonesLayers.tsx | 17 ++++----- game/server/game/models.py | 8 ++++- game/server/mapzones/models.py | 12 +++++++ 6 files changed, 64 insertions(+), 11 deletions(-) create mode 100644 client/src/api/mapZonesSlice.ts diff --git a/client/src/api/_liberationApi.ts b/client/src/api/_liberationApi.ts index 8f527a49..3f33a591 100644 --- a/client/src/api/_liberationApi.ts +++ b/client/src/api/_liberationApi.ts @@ -466,6 +466,7 @@ export type Game = { navmeshes: NavMeshes; map_center?: LatLng; unculled_zones: UnculledZone[]; + map_zones: MapZones; }; export type MapZones = { inclusion: LatLng[][][]; diff --git a/client/src/api/mapZonesSlice.ts b/client/src/api/mapZonesSlice.ts new file mode 100644 index 00000000..d92e80cc --- /dev/null +++ b/client/src/api/mapZonesSlice.ts @@ -0,0 +1,35 @@ +import { RootState } from "../app/store"; +import { gameLoaded, gameUnloaded } from "./actions"; +import { createSlice } from "@reduxjs/toolkit"; +import { LatLngLiteral } from "leaflet"; +import { MapZones } from "./_liberationApi"; + +interface MapZonesState { + mapZones: MapZones; +} + +const initialState: MapZonesState = { + mapZones: { inclusion: [], exclusion: [], sea: [] }, +}; + +const mapZonesSlice = createSlice({ + name: "map", + initialState: initialState, + reducers: {}, + extraReducers: (builder) => { + builder.addCase(gameLoaded, (state, action) => { + if (action.payload != null) { + state.mapZones.exclusion = action.payload.map_zones.exclusion; + state.mapZones.inclusion = action.payload.map_zones.inclusion; + state.mapZones.sea = action.payload.map_zones.sea; + } + }); + builder.addCase(gameUnloaded, (state) => { + state.mapZones = initialState.mapZones; + }); + }, +}); + +export const selectMapZones = (state: RootState) => state.mapZones; + +export default mapZonesSlice.reducer; diff --git a/client/src/app/store.ts b/client/src/app/store.ts index bbb6eb83..1000c5fa 100644 --- a/client/src/app/store.ts +++ b/client/src/app/store.ts @@ -10,6 +10,7 @@ import supplyRoutesReducer from "../api/supplyRoutesSlice"; import tgosReducer from "../api/tgosSlice"; import threatZonesReducer from "../api/threatZonesSlice"; import unculledZonesReducer from "../api/unculledZonesSlice"; +import mapZonesReducer from "../api/mapZonesSlice"; import { Action, PreloadedState, @@ -31,6 +32,7 @@ const rootReducer = combineReducers({ threatZones: threatZonesReducer, [baseApi.reducerPath]: baseApi.reducer, unculledZones: unculledZonesReducer, + mapZones: mapZonesReducer, }); export function setupStore(preloadedState?: PreloadedState) { diff --git a/client/src/components/terrainzones/TerrainZonesLayers.tsx b/client/src/components/terrainzones/TerrainZonesLayers.tsx index 5d5bb2c3..d254ac92 100644 --- a/client/src/components/terrainzones/TerrainZonesLayers.tsx +++ b/client/src/components/terrainzones/TerrainZonesLayers.tsx @@ -1,6 +1,8 @@ import { useGetTerrainZonesQuery } from "../../api/liberationApi"; +import { useAppSelector } from "../../app/hooks"; import { LatLngLiteral } from "leaflet"; import { LayerGroup, LayersControl, Polygon } from "react-leaflet"; +import { selectMapZones } from "../../api/mapZonesSlice"; interface TerrainZoneLayerProps { zones: LatLngLiteral[][][]; @@ -28,33 +30,28 @@ function TerrainZoneLayer(props: TerrainZoneLayerProps) { } export default function TerrainZonesLayers() { - const { data, error, isLoading } = useGetTerrainZonesQuery(); + const zones = useAppSelector(selectMapZones).mapZones; var exclusion = <>; var inclusion = <>; var sea = <>; - if (error) { - console.error("Error while loading terrain zones", error); - } else if (isLoading) { - } else if (!data) { - console.log("Empty response when loading terrain zones"); - } else { + if (zones) { exclusion = ( ); inclusion = ( ); sea = ( - + ); } return ( diff --git a/game/server/game/models.py b/game/server/game/models.py index 610f2ae1..9454e1a3 100644 --- a/game/server/game/models.py +++ b/game/server/game/models.py @@ -9,7 +9,11 @@ from game.server.flights.models import FlightJs from game.server.frontlines.models import FrontLineJs from game.server.iadsnetwork.models import IadsNetworkJs from game.server.leaflet import LeafletPoint -from game.server.mapzones.models import ThreatZoneContainerJs, UnculledZoneJs +from game.server.mapzones.models import ( + ThreatZoneContainerJs, + UnculledZoneJs, + MapZonesJs, +) from game.server.navmesh.models import NavMeshesJs from game.server.supplyroutes.models import SupplyRouteJs from game.server.tgos.models import TgoJs @@ -29,6 +33,7 @@ class GameJs(BaseModel): navmeshes: NavMeshesJs map_center: LeafletPoint | None unculled_zones: list[UnculledZoneJs] + map_zones: MapZonesJs class Config: title = "Game" @@ -46,4 +51,5 @@ class GameJs(BaseModel): navmeshes=NavMeshesJs.from_game(game), map_center=game.theater.terrain.map_view_default.position.latlng(), unculled_zones=UnculledZoneJs.from_game(game), + map_zones=MapZonesJs.from_game(game), ) diff --git a/game/server/mapzones/models.py b/game/server/mapzones/models.py index f83f43e0..33eb6ba6 100644 --- a/game/server/mapzones/models.py +++ b/game/server/mapzones/models.py @@ -24,6 +24,18 @@ class MapZonesJs(BaseModel): def empty(cls) -> MapZonesJs: return MapZonesJs(inclusion=[], exclusion=[], sea=[]) + @classmethod + def from_game(cls, game: Game) -> MapZonesJs: + zones = game.theater.landmap + if zones is None: + return cls.empty() + + return MapZonesJs( + inclusion=ShapelyUtil.polys_to_leaflet(zones.inclusion_zones, game.theater), + exclusion=ShapelyUtil.polys_to_leaflet(zones.exclusion_zones, game.theater), + sea=ShapelyUtil.polys_to_leaflet(zones.sea_zones, game.theater), + ) + class UnculledZoneJs(BaseModel): position: LeafletPoint