mirror of
https://github.com/dcs-liberation/dcs_liberation.git
synced 2025-11-10 14:22:26 +00:00
operation_ids give us better function names when generating the typescript API from the openapi.json. BaseModel.Config.title does the same for type names. Response models (or 204 status codes) need to be explicit or the API will be declared as returning any.
115 lines
3.6 KiB
Python
115 lines
3.6 KiB
Python
from dcs import Point
|
|
from dcs.mapping import LatLng
|
|
from fastapi import APIRouter, Body, Depends, HTTPException, status
|
|
|
|
from game import Game
|
|
from .models import ControlPointJs
|
|
from .. import EventStream
|
|
from ..dependencies import GameContext
|
|
from ..leaflet import LeafletPoint
|
|
from ...sim import GameUpdateEvents
|
|
|
|
router: APIRouter = APIRouter(prefix="/control-points")
|
|
|
|
|
|
@router.get(
|
|
"/", operation_id="list_control_points", response_model=list[ControlPointJs]
|
|
)
|
|
def list_control_points(
|
|
game: Game = Depends(GameContext.require),
|
|
) -> list[ControlPointJs]:
|
|
return ControlPointJs.all_in_game(game)
|
|
|
|
|
|
@router.get(
|
|
"/{cp_id}", operation_id="get_control_point_by_id", response_model=ControlPointJs
|
|
)
|
|
def get_control_point(
|
|
cp_id: int, game: Game = Depends(GameContext.require)
|
|
) -> ControlPointJs:
|
|
cp = game.theater.find_control_point_by_id(cp_id)
|
|
if cp is None:
|
|
raise HTTPException(
|
|
status.HTTP_404_NOT_FOUND,
|
|
detail=f"Game has no control point with ID {cp_id}",
|
|
)
|
|
return ControlPointJs.for_control_point(cp)
|
|
|
|
|
|
@router.get(
|
|
"/{cp_id}/destination-in-range",
|
|
operation_id="control_point_destination_in_range",
|
|
response_model=bool,
|
|
)
|
|
def destination_in_range(
|
|
cp_id: int, lat: float, lng: float, game: Game = Depends(GameContext.require)
|
|
) -> bool:
|
|
cp = game.theater.find_control_point_by_id(cp_id)
|
|
if cp is None:
|
|
raise HTTPException(
|
|
status.HTTP_404_NOT_FOUND,
|
|
detail=f"Game has no control point with ID {cp_id}",
|
|
)
|
|
|
|
point = Point.from_latlng(LatLng(lat, lng), game.theater.terrain)
|
|
return cp.destination_in_range(point)
|
|
|
|
|
|
@router.put(
|
|
"/{cp_id}/destination",
|
|
operation_id="set_control_point_destination",
|
|
status_code=status.HTTP_204_NO_CONTENT,
|
|
)
|
|
def set_destination(
|
|
cp_id: int,
|
|
destination: LeafletPoint = Body(..., title="destination"),
|
|
game: Game = Depends(GameContext.require),
|
|
) -> None:
|
|
cp = game.theater.find_control_point_by_id(cp_id)
|
|
if cp is None:
|
|
raise HTTPException(
|
|
status.HTTP_404_NOT_FOUND,
|
|
detail=f"Game has no control point with ID {cp_id}",
|
|
)
|
|
if not cp.moveable:
|
|
raise HTTPException(status.HTTP_403_FORBIDDEN, detail=f"{cp} is not mobile")
|
|
if not cp.captured:
|
|
raise HTTPException(
|
|
status.HTTP_403_FORBIDDEN, detail=f"{cp} is not owned by the player"
|
|
)
|
|
|
|
point = Point.from_latlng(
|
|
LatLng(destination.lat, destination.lng), game.theater.terrain
|
|
)
|
|
if not cp.destination_in_range(point):
|
|
raise HTTPException(
|
|
status.HTTP_400_BAD_REQUEST,
|
|
detail=f"Cannot move {cp} more than "
|
|
f"{cp.max_move_distance.nautical_miles}nm.",
|
|
)
|
|
cp.target_position = point
|
|
EventStream.put_nowait(GameUpdateEvents().update_control_point(cp))
|
|
|
|
|
|
@router.put(
|
|
"/{cp_id}/cancel-travel",
|
|
operation_id="clear_control_point_destination",
|
|
status_code=status.HTTP_204_NO_CONTENT,
|
|
)
|
|
def cancel_travel(cp_id: int, game: Game = Depends(GameContext.require)) -> None:
|
|
cp = game.theater.find_control_point_by_id(cp_id)
|
|
if cp is None:
|
|
raise HTTPException(
|
|
status.HTTP_404_NOT_FOUND,
|
|
detail=f"Game has no control point with ID {cp_id}",
|
|
)
|
|
if not cp.moveable:
|
|
raise HTTPException(status.HTTP_403_FORBIDDEN, detail=f"{cp} is not mobile")
|
|
if not cp.captured:
|
|
raise HTTPException(
|
|
status.HTTP_403_FORBIDDEN, detail=f"{cp} is not owned by the player"
|
|
)
|
|
|
|
cp.target_position = None
|
|
EventStream.put_nowait(GameUpdateEvents().update_control_point(cp))
|