Track when a map is edited and update things better, in both the game's edit mode and the new tool.

This commit is contained in:
Dustin Carlino 2021-08-08 09:22:32 -07:00
parent 100b068086
commit 9b4107f061
7 changed files with 29 additions and 23 deletions

View File

@ -40,8 +40,7 @@ pub struct EditMode {
// Retained state from the SandboxMode that spawned us // Retained state from the SandboxMode that spawned us
mode: GameplayMode, mode: GameplayMode,
// edits name, number of commands map_edit_key: usize,
changelist_key: (String, usize),
unzoomed: Drawable, unzoomed: Drawable,
zoomed: Drawable, zoomed: Drawable,
@ -52,16 +51,15 @@ impl EditMode {
let orig_dirty = app.primary.dirty_from_edits; let orig_dirty = app.primary.dirty_from_edits;
assert!(app.primary.suspended_sim.is_none()); assert!(app.primary.suspended_sim.is_none());
app.primary.suspended_sim = Some(app.primary.clear_sim()); app.primary.suspended_sim = Some(app.primary.clear_sim());
let edits = app.primary.map.get_edits();
let layer = crate::layer::map::Static::edits(ctx, app); let layer = crate::layer::map::Static::edits(ctx, app);
Box::new(EditMode { Box::new(EditMode {
tool_panel: tool_panel(ctx), tool_panel: tool_panel(ctx),
top_center: make_topcenter(ctx, app), top_center: make_topcenter(ctx, app),
changelist: make_changelist(ctx, app), changelist: make_changelist(ctx, app),
orig_edits: edits.clone(), orig_edits: app.primary.map.get_edits().clone(),
orig_dirty, orig_dirty,
mode, mode,
changelist_key: (edits.edits_name.clone(), edits.commands.len()), map_edit_key: app.primary.map.get_edits_change_key(),
unzoomed: layer.unzoomed, unzoomed: layer.unzoomed,
zoomed: layer.zoomed, zoomed: layer.zoomed,
}) })
@ -146,10 +144,11 @@ impl EditMode {
impl State<App> for EditMode { impl State<App> for EditMode {
fn event(&mut self, ctx: &mut EventCtx, app: &mut App) -> Transition { fn event(&mut self, ctx: &mut EventCtx, app: &mut App) -> Transition {
{ {
let edits = app.primary.map.get_edits(); // We would normally use Cached, but so many values depend on one key, so this is more
let changelist_key = (edits.edits_name.clone(), edits.commands.len()); // clear.
if self.changelist_key != changelist_key { let key = app.primary.map.get_edits_change_key();
self.changelist_key = changelist_key; if self.map_edit_key != key {
self.map_edit_key = key;
self.changelist = make_changelist(ctx, app); self.changelist = make_changelist(ctx, app);
let layer = crate::layer::map::Static::edits(ctx, app); let layer = crate::layer::map::Static::edits(ctx, app);
self.unzoomed = layer.unzoomed; self.unzoomed = layer.unzoomed;

View File

@ -31,16 +31,12 @@ pub struct ExploreMap {
// TODO Also cache Nearby, but recalculate it after edits // TODO Also cache Nearby, but recalculate it after edits
nearby: Option<Nearby>, nearby: Option<Nearby>,
// edits name, number of commands map_edit_key: usize,
// TODO Brittle -- could undo and add a new command. Add a proper edit counter to map. Refactor
// with EditMode. Use Cached.
changelist_key: (String, usize),
} }
impl ExploreMap { impl ExploreMap {
pub fn new_state(ctx: &mut EventCtx, app: &mut App) -> Box<dyn State<App>> { pub fn new_state(ctx: &mut EventCtx, app: &mut App) -> Box<dyn State<App>> {
app.opts.show_building_driveways = false; app.opts.show_building_driveways = false;
let edits = app.primary.map.get_edits();
Box::new(ExploreMap { Box::new(ExploreMap {
top_panel: make_top_panel(ctx, app), top_panel: make_top_panel(ctx, app),
@ -51,7 +47,7 @@ impl ExploreMap {
elevation: false, elevation: false,
nearby: None, nearby: None,
changelist_key: (edits.edits_name.clone(), edits.commands.len()), map_edit_key: app.primary.map.get_edits_change_key(),
}) })
} }
} }
@ -59,10 +55,11 @@ impl ExploreMap {
impl State<App> for ExploreMap { impl State<App> for ExploreMap {
fn event(&mut self, ctx: &mut EventCtx, app: &mut App) -> Transition { fn event(&mut self, ctx: &mut EventCtx, app: &mut App) -> Transition {
{ {
let edits = app.primary.map.get_edits(); // We would normally use Cached, but so many values depend on one key, so this is more
let changelist_key = (edits.edits_name.clone(), edits.commands.len()); // clear.
if self.changelist_key != changelist_key { let key = app.primary.map.get_edits_change_key();
self.changelist_key = changelist_key; if self.map_edit_key != key {
self.map_edit_key = key;
self.network_layer = render_network_layer(ctx, app); self.network_layer = render_network_layer(ctx, app);
self.edits_layer = render_edits(ctx, app); self.edits_layer = render_edits(ctx, app);
self.top_panel = make_top_panel(ctx, app); self.top_panel = make_top_panel(ctx, app);

View File

@ -85,8 +85,8 @@ impl State<App> for QuickSketch {
fn event(&mut self, ctx: &mut EventCtx, app: &mut App) -> Transition { fn event(&mut self, ctx: &mut EventCtx, app: &mut App) -> Transition {
self.magnifying_glass.event(ctx, app); self.magnifying_glass.event(ctx, app);
match self.top_panel.event(ctx) { if let Outcome::Clicked(x) = self.top_panel.event(ctx) {
Outcome::Clicked(x) => match x.as_ref() { match x.as_ref() {
"Cancel" => { "Cancel" => {
return Transition::Pop; return Transition::Pop;
} }
@ -100,8 +100,7 @@ impl State<App> for QuickSketch {
return Transition::Replace(PopupMsg::new_state(ctx, "Changes made", messages)); return Transition::Replace(PopupMsg::new_state(ctx, "Changes made", messages));
} }
_ => unreachable!(), _ => unreachable!(),
}, }
_ => {}
} }
if self.route_sketcher.event(ctx, app) { if self.route_sketcher.event(ctx, app) {

View File

@ -774,6 +774,8 @@ impl Map {
// new_edits don't necessarily have to be valid; this could be used for speculatively testing // new_edits don't necessarily have to be valid; this could be used for speculatively testing
// edits. Doesn't update pathfinding yet. // edits. Doesn't update pathfinding yet.
fn apply_edits(&mut self, mut new_edits: MapEdits, enforce_valid: bool) -> EditEffects { fn apply_edits(&mut self, mut new_edits: MapEdits, enforce_valid: bool) -> EditEffects {
self.edits_generation += 1;
let mut effects = EditEffects { let mut effects = EditEffects {
changed_roads: BTreeSet::new(), changed_roads: BTreeSet::new(),
deleted_lanes: BTreeSet::new(), deleted_lanes: BTreeSet::new(),
@ -907,4 +909,9 @@ impl Map {
); );
self.traffic_signals.insert(signal.id, signal); self.traffic_signals.insert(signal.id, signal);
} }
/// If you need to regenerate anything when the map is edited, use this key to detect edits.
pub fn get_edits_change_key(&self) -> usize {
self.edits_generation
}
} }

View File

@ -116,5 +116,7 @@ pub struct Map {
#[serde(skip_serializing, skip_deserializing)] #[serde(skip_serializing, skip_deserializing)]
edits: MapEdits, edits: MapEdits,
#[serde(skip_serializing, skip_deserializing)] #[serde(skip_serializing, skip_deserializing)]
edits_generation: usize,
#[serde(skip_serializing, skip_deserializing)]
road_to_buildings: MultiMap<RoadID, BuildingID>, road_to_buildings: MultiMap<RoadID, BuildingID>,
} }

View File

@ -86,6 +86,7 @@ impl Map {
routing_params: RoutingParams::default(), routing_params: RoutingParams::default(),
name: raw.name.clone(), name: raw.name.clone(),
edits: MapEdits::new(), edits: MapEdits::new(),
edits_generation: 0,
road_to_buildings: MultiMap::new(), road_to_buildings: MultiMap::new(),
}; };
map.edits = map.new_edits(); map.edits = map.new_edits();

View File

@ -179,6 +179,7 @@ impl Map {
routing_params: RoutingParams::default(), routing_params: RoutingParams::default(),
name: MapName::new("zz", "blank city", "blank"), name: MapName::new("zz", "blank city", "blank"),
edits: MapEdits::new(), edits: MapEdits::new(),
edits_generation: 0,
road_to_buildings: MultiMap::new(), road_to_buildings: MultiMap::new(),
} }
} }