mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-01 02:33:54 +03:00
In traffic=none mode, allow recording (most of) the manually specified
trips as a Scenario to later re-run. This is useful for quickly defining "test cases" for development, and it's a start to a UI for letting players specify (and eventually share) traffic patterns they define.
This commit is contained in:
parent
3ed8b9cf81
commit
e6c1d960ec
@ -1,7 +1,7 @@
|
||||
use crate::app::{App, ShowEverything};
|
||||
use crate::common::{CityPicker, CommonState};
|
||||
use crate::edit::EditMode;
|
||||
use crate::game::{ChooseSomething, State, Transition};
|
||||
use crate::game::{ChooseSomething, PopupMsg, PromptInput, State, Transition};
|
||||
use crate::helpers::{nice_map_name, ID};
|
||||
use crate::sandbox::gameplay::{GameplayMode, GameplayState};
|
||||
use crate::sandbox::SandboxControls;
|
||||
@ -72,6 +72,32 @@ impl GameplayState for Freeform {
|
||||
GameplayMode::Freeform(abstutil::path_map(app.primary.map.get_name())),
|
||||
))),
|
||||
"Start a new trip" => Some(Transition::Push(AgentSpawner::new(ctx, None))),
|
||||
"Record trips as a scenario" => Some(Transition::Push(PromptInput::new(
|
||||
ctx,
|
||||
"Name this scenario",
|
||||
Box::new(|name, ctx, app| {
|
||||
if abstutil::file_exists(abstutil::path_scenario(
|
||||
app.primary.map.get_name(),
|
||||
&name,
|
||||
)) {
|
||||
Transition::Push(PopupMsg::new(
|
||||
ctx,
|
||||
"Error",
|
||||
vec![format!(
|
||||
"A scenario called \"{}\" already exists, please pick another \
|
||||
name",
|
||||
name
|
||||
)],
|
||||
))
|
||||
} else {
|
||||
app.primary
|
||||
.sim
|
||||
.generate_scenario(&app.primary.map, name)
|
||||
.save();
|
||||
Transition::Pop
|
||||
}
|
||||
}),
|
||||
))),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
_ => None,
|
||||
@ -99,9 +125,11 @@ fn make_top_center(ctx: &mut EventCtx, app: &App) -> Composite {
|
||||
Btn::svg_def("system/assets/tools/edit_map.svg").build(ctx, "edit map", lctrl(Key::E)),
|
||||
])
|
||||
.centered(),
|
||||
Btn::text_fg("Start a new trip")
|
||||
.build_def(ctx, None)
|
||||
.centered_horiz(),
|
||||
Widget::row(vec![
|
||||
Btn::text_fg("Start a new trip").build_def(ctx, None),
|
||||
Btn::text_fg("Record trips as a scenario").build_def(ctx, None),
|
||||
])
|
||||
.centered(),
|
||||
Text::from_all(vec![
|
||||
Line("Select an intersection and press "),
|
||||
Line(Key::Z.describe()).fg(ctx.style().hotkey_color),
|
||||
|
@ -3,9 +3,9 @@ use crate::{
|
||||
AgentID, AgentType, AlertLocation, Analytics, CarID, Command, CreateCar, DrawCarInput,
|
||||
DrawPedCrowdInput, DrawPedestrianInput, DrivingSimState, Event, GetDrawAgents,
|
||||
IntersectionSimState, OrigPersonID, PandemicModel, ParkedCar, ParkingSimState, ParkingSpot,
|
||||
PedestrianID, Person, PersonID, PersonState, Router, Scheduler, SidewalkPOI, SidewalkSpot,
|
||||
TransitSimState, TripID, TripInfo, TripManager, TripPhaseType, TripResult, TripSpawner,
|
||||
UnzoomedAgent, Vehicle, VehicleSpec, VehicleType, WalkingSimState, BUS_LENGTH,
|
||||
PedestrianID, Person, PersonID, PersonState, Router, Scenario, Scheduler, SidewalkPOI,
|
||||
SidewalkSpot, TransitSimState, TripID, TripInfo, TripManager, TripPhaseType, TripResult,
|
||||
TripSpawner, UnzoomedAgent, Vehicle, VehicleSpec, VehicleType, WalkingSimState, BUS_LENGTH,
|
||||
LIGHT_RAIL_LENGTH, MIN_CAR_LENGTH, SPAWN_DIST,
|
||||
};
|
||||
use abstutil::{prettyprint_usize, serialized_size_bytes, Counter, Parallelism, Timer};
|
||||
@ -1192,6 +1192,10 @@ impl Sim {
|
||||
) -> &Vec<(PedestrianID, BusRouteID, Option<BusStopID>, Time)> {
|
||||
self.transit.get_people_waiting_at_stop(at)
|
||||
}
|
||||
|
||||
pub fn generate_scenario(&self, map: &Map, name: String) -> Scenario {
|
||||
self.trips.generate_scenario(map, name)
|
||||
}
|
||||
}
|
||||
|
||||
// Invasive debugging
|
||||
|
@ -1,8 +1,9 @@
|
||||
use crate::{
|
||||
AgentID, AgentType, AlertLocation, CarID, Command, CreateCar, CreatePedestrian, DrivingGoal,
|
||||
Event, OffMapLocation, OrigPersonID, ParkedCar, ParkingSimState, ParkingSpot, PedestrianID,
|
||||
PersonID, Scheduler, SidewalkPOI, SidewalkSpot, TransitSimState, TripID, TripPhaseType,
|
||||
TripSpec, Vehicle, VehicleSpec, VehicleType, WalkingSimState,
|
||||
Event, IndividTrip, OffMapLocation, OrigPersonID, ParkedCar, ParkingSimState, ParkingSpot,
|
||||
PedestrianID, PersonID, PersonSpec, Scenario, Scheduler, SidewalkPOI, SidewalkSpot, SpawnTrip,
|
||||
TransitSimState, TripID, TripPhaseType, TripSpec, Vehicle, VehicleSpec, VehicleType,
|
||||
WalkingSimState,
|
||||
};
|
||||
use abstutil::{deserialize_btreemap, serialize_btreemap, Counter};
|
||||
use geom::{Duration, Speed, Time};
|
||||
@ -1326,6 +1327,35 @@ impl TripManager {
|
||||
times.sort();
|
||||
times
|
||||
}
|
||||
|
||||
// TODO This could be lossy. There are a few layers in spawning trips, and things like
|
||||
// spawn_agents_around reach into one of the middle layers directly. So here in TripManager, we
|
||||
// might not have retained enough state to create a proper scenario. But this should work
|
||||
// reasonably for most cases.
|
||||
pub fn generate_scenario(&self, map: &Map, name: String) -> Scenario {
|
||||
let mut scenario = Scenario::empty(map, &name);
|
||||
for p in &self.people {
|
||||
scenario.people.push(PersonSpec {
|
||||
id: p.id,
|
||||
orig_id: p.orig_id,
|
||||
trips: p
|
||||
.trips
|
||||
.iter()
|
||||
.filter_map(|t| {
|
||||
let trip = &self.trips[t.0];
|
||||
SpawnTrip::new(
|
||||
trip.info.start.clone(),
|
||||
trip.info.end.clone(),
|
||||
trip.info.mode,
|
||||
map,
|
||||
)
|
||||
.map(|spawn| IndividTrip::new(trip.info.departure, spawn))
|
||||
})
|
||||
.collect(),
|
||||
});
|
||||
}
|
||||
scenario
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
|
||||
|
Loading…
Reference in New Issue
Block a user