mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-25 11:44:25 +03:00
converting abtest mode
This commit is contained in:
parent
6f2f6a3a75
commit
859429a493
@ -1,13 +1,11 @@
|
||||
mod score;
|
||||
mod setup;
|
||||
pub mod setup;
|
||||
|
||||
use crate::common::{CommonState, SpeedControls};
|
||||
use crate::game::{GameState, Mode};
|
||||
use crate::render::{DrawOptions, MIN_ZOOM_FOR_DETAIL};
|
||||
use crate::render::MIN_ZOOM_FOR_DETAIL;
|
||||
use crate::state::{State, Transition};
|
||||
use crate::ui::{PerMapUI, ShowEverything, UI};
|
||||
use ezgui::{
|
||||
hotkey, Color, EventCtx, EventLoopMode, GeomBatch, GfxCtx, Key, ModalMenu, Text, Wizard,
|
||||
};
|
||||
use ezgui::{hotkey, Color, EventCtx, EventLoopMode, GeomBatch, GfxCtx, Key, ModalMenu, Text};
|
||||
use geom::{Circle, Distance, Duration, Line, PolyLine};
|
||||
use map_model::{Map, LANE_THICKNESS};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
@ -16,9 +14,8 @@ use sim::{Sim, TripID};
|
||||
pub struct ABTestMode {
|
||||
menu: ModalMenu,
|
||||
speed: SpeedControls,
|
||||
pub state: State,
|
||||
// TODO Urgh, hack. Need to be able to take() it to switch states sometimes.
|
||||
pub secondary: Option<PerMapUI>,
|
||||
secondary: Option<PerMapUI>,
|
||||
diff_trip: Option<DiffOneTrip>,
|
||||
diff_all: Option<DiffAllTrips>,
|
||||
// TODO Not present in Setup state.
|
||||
@ -26,14 +23,13 @@ pub struct ABTestMode {
|
||||
test_name: String,
|
||||
}
|
||||
|
||||
pub enum State {
|
||||
Setup(setup::ABTestSetup),
|
||||
Playing,
|
||||
Scoreboard(score::Scoreboard),
|
||||
}
|
||||
|
||||
impl ABTestMode {
|
||||
pub fn new(ctx: &mut EventCtx, ui: &mut UI, test_name: &str) -> ABTestMode {
|
||||
pub fn new(
|
||||
ctx: &mut EventCtx,
|
||||
ui: &mut UI,
|
||||
test_name: &str,
|
||||
secondary: PerMapUI,
|
||||
) -> ABTestMode {
|
||||
ui.primary.current_selection = None;
|
||||
|
||||
ABTestMode {
|
||||
@ -58,148 +54,133 @@ impl ABTestMode {
|
||||
ctx,
|
||||
),
|
||||
speed: SpeedControls::new(ctx, None),
|
||||
state: State::Setup(setup::ABTestSetup::Pick(Wizard::new())),
|
||||
secondary: None,
|
||||
secondary: Some(secondary),
|
||||
diff_trip: None,
|
||||
diff_all: None,
|
||||
common: CommonState::new(),
|
||||
test_name: test_name.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn event(state: &mut GameState, ctx: &mut EventCtx) -> EventLoopMode {
|
||||
match state.mode {
|
||||
Mode::ABTest(ref mut mode) => {
|
||||
match mode.state {
|
||||
State::Setup(_) => {
|
||||
setup::ABTestSetup::event(state, ctx);
|
||||
EventLoopMode::InputOnly
|
||||
}
|
||||
State::Scoreboard(ref mut s) => {
|
||||
if s.event(ctx, &state.ui.primary, mode.secondary.as_ref().unwrap()) {
|
||||
mode.state = State::Playing;
|
||||
mode.speed.pause();
|
||||
}
|
||||
EventLoopMode::InputOnly
|
||||
}
|
||||
State::Playing => {
|
||||
let mut txt = Text::prompt("A/B Test Mode");
|
||||
txt.add_line(state.ui.primary.map.get_edits().edits_name.clone());
|
||||
if let Some(ref diff) = mode.diff_trip {
|
||||
txt.add_line(format!("Showing diff for {}", diff.trip));
|
||||
} else if let Some(ref diff) = mode.diff_all {
|
||||
txt.add_line(format!(
|
||||
"Showing diffs for all. {} trips same, {} differ",
|
||||
diff.same_trips,
|
||||
diff.lines.len()
|
||||
));
|
||||
}
|
||||
txt.add_line(state.ui.primary.sim.summary());
|
||||
mode.menu.handle_event(ctx, Some(txt));
|
||||
impl State for ABTestMode {
|
||||
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> (Transition, EventLoopMode) {
|
||||
let mut txt = Text::prompt("A/B Test Mode");
|
||||
txt.add_line(ui.primary.map.get_edits().edits_name.clone());
|
||||
if let Some(ref diff) = self.diff_trip {
|
||||
txt.add_line(format!("Showing diff for {}", diff.trip));
|
||||
} else if let Some(ref diff) = self.diff_all {
|
||||
txt.add_line(format!(
|
||||
"Showing diffs for all. {} trips same, {} differ",
|
||||
diff.same_trips,
|
||||
diff.lines.len()
|
||||
));
|
||||
}
|
||||
txt.add_line(ui.primary.sim.summary());
|
||||
self.menu.handle_event(ctx, Some(txt));
|
||||
|
||||
ctx.canvas.handle_event(ctx.input);
|
||||
if ctx.redo_mouseover() {
|
||||
state.ui.primary.current_selection =
|
||||
state.ui.recalculate_current_selection(
|
||||
ctx,
|
||||
&state.ui.primary.sim,
|
||||
&ShowEverything::new(),
|
||||
false,
|
||||
);
|
||||
}
|
||||
if let Some(evmode) = mode.common.event(ctx, &mut state.ui, &mut mode.menu)
|
||||
{
|
||||
return evmode;
|
||||
}
|
||||
ctx.canvas.handle_event(ctx.input);
|
||||
if ctx.redo_mouseover() {
|
||||
ui.primary.current_selection = ui.recalculate_current_selection(
|
||||
ctx,
|
||||
&ui.primary.sim,
|
||||
&ShowEverything::new(),
|
||||
false,
|
||||
);
|
||||
}
|
||||
if let Some(evmode) = self.common.event(ctx, ui, &mut self.menu) {
|
||||
return (Transition::Keep, evmode);
|
||||
}
|
||||
|
||||
if mode.menu.action("quit") {
|
||||
// TODO This shouldn't be necessary when we plumb state around instead of
|
||||
// sharing it in the old structure.
|
||||
state.ui.primary.reset_sim();
|
||||
// Note destroying mode.secondary has some noticeable delay.
|
||||
state.mode = Mode::SplashScreen(Wizard::new(), None);
|
||||
return EventLoopMode::InputOnly;
|
||||
}
|
||||
if self.menu.action("quit") {
|
||||
// TODO Should we clear edits too?
|
||||
ui.primary.reset_sim();
|
||||
// Note destroying mode.secondary has some noticeable delay.
|
||||
return (Transition::Pop, EventLoopMode::InputOnly);
|
||||
}
|
||||
|
||||
if mode.menu.action("swap") {
|
||||
let secondary = mode.secondary.take().unwrap();
|
||||
let primary = std::mem::replace(&mut state.ui.primary, secondary);
|
||||
mode.secondary = Some(primary);
|
||||
mode.recalculate_stuff(&mut state.ui, ctx);
|
||||
}
|
||||
if self.menu.action("swap") {
|
||||
let secondary = self.secondary.take().unwrap();
|
||||
let primary = std::mem::replace(&mut ui.primary, secondary);
|
||||
self.secondary = Some(primary);
|
||||
self.recalculate_stuff(ui, ctx);
|
||||
}
|
||||
|
||||
if mode.menu.action("scoreboard") {
|
||||
mode.state = State::Scoreboard(score::Scoreboard::new(
|
||||
ctx,
|
||||
&state.ui.primary,
|
||||
mode.secondary.as_ref().unwrap(),
|
||||
));
|
||||
return EventLoopMode::InputOnly;
|
||||
}
|
||||
if self.menu.action("scoreboard") {
|
||||
self.speed.pause();
|
||||
return (
|
||||
Transition::Push(Box::new(score::Scoreboard::new(
|
||||
ctx,
|
||||
&ui.primary,
|
||||
self.secondary.as_ref().unwrap(),
|
||||
))),
|
||||
EventLoopMode::InputOnly,
|
||||
);
|
||||
}
|
||||
|
||||
if mode.menu.action("save state") {
|
||||
mode.savestate(&mut state.ui.primary);
|
||||
}
|
||||
if self.menu.action("save state") {
|
||||
self.savestate(&mut ui.primary);
|
||||
}
|
||||
|
||||
if mode.diff_trip.is_some() {
|
||||
if mode.menu.action("stop diffing trips") {
|
||||
mode.diff_trip = None;
|
||||
}
|
||||
} else if mode.diff_all.is_some() {
|
||||
if mode.menu.action("stop diffing trips") {
|
||||
mode.diff_all = None;
|
||||
}
|
||||
} else {
|
||||
if state.ui.primary.current_selection.is_none()
|
||||
&& mode.menu.action("diff all trips")
|
||||
{
|
||||
mode.diff_all = Some(DiffAllTrips::new(
|
||||
&mut state.ui.primary,
|
||||
mode.secondary.as_mut().unwrap(),
|
||||
));
|
||||
} else if let Some(agent) = state
|
||||
.ui
|
||||
.primary
|
||||
.current_selection
|
||||
.and_then(|id| id.agent_id())
|
||||
{
|
||||
if let Some(trip) = state.ui.primary.sim.agent_to_trip(agent) {
|
||||
if ctx.input.contextual_action(
|
||||
Key::B,
|
||||
&format!("Show {}'s parallel world", agent),
|
||||
) {
|
||||
mode.diff_trip = Some(DiffOneTrip::new(
|
||||
trip,
|
||||
&state.ui.primary,
|
||||
mode.secondary.as_ref().unwrap(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(dt) =
|
||||
mode.speed
|
||||
.event(ctx, &mut mode.menu, state.ui.primary.sim.time())
|
||||
{
|
||||
mode.step(dt, &mut state.ui, ctx);
|
||||
}
|
||||
|
||||
if mode.speed.is_paused() {
|
||||
if mode.menu.action("step forwards 0.1s") {
|
||||
mode.step(Duration::seconds(0.1), &mut state.ui, ctx);
|
||||
}
|
||||
EventLoopMode::InputOnly
|
||||
} else {
|
||||
EventLoopMode::Animation
|
||||
}
|
||||
if self.diff_trip.is_some() {
|
||||
if self.menu.action("stop diffing trips") {
|
||||
self.diff_trip = None;
|
||||
}
|
||||
} else if self.diff_all.is_some() {
|
||||
if self.menu.action("stop diffing trips") {
|
||||
self.diff_all = None;
|
||||
}
|
||||
} else {
|
||||
if ui.primary.current_selection.is_none() && self.menu.action("diff all trips") {
|
||||
self.diff_all = Some(DiffAllTrips::new(
|
||||
&mut ui.primary,
|
||||
self.secondary.as_mut().unwrap(),
|
||||
));
|
||||
} else if let Some(agent) = ui.primary.current_selection.and_then(|id| id.agent_id()) {
|
||||
if let Some(trip) = ui.primary.sim.agent_to_trip(agent) {
|
||||
if ctx
|
||||
.input
|
||||
.contextual_action(Key::B, &format!("Show {}'s parallel world", agent))
|
||||
{
|
||||
self.diff_trip = Some(DiffOneTrip::new(
|
||||
trip,
|
||||
&ui.primary,
|
||||
self.secondary.as_ref().unwrap(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
if let Some(dt) = self.speed.event(ctx, &mut self.menu, ui.primary.sim.time()) {
|
||||
self.step(dt, ui, ctx);
|
||||
}
|
||||
|
||||
if self.speed.is_paused() {
|
||||
if self.menu.action("step forwards 0.1s") {
|
||||
self.step(Duration::seconds(0.1), ui, ctx);
|
||||
}
|
||||
(Transition::Keep, EventLoopMode::InputOnly)
|
||||
} else {
|
||||
(Transition::Keep, EventLoopMode::Animation)
|
||||
}
|
||||
}
|
||||
|
||||
fn draw(&self, g: &mut GfxCtx, ui: &UI) {
|
||||
self.common.draw(g, ui);
|
||||
|
||||
if let Some(ref diff) = self.diff_trip {
|
||||
diff.draw(g, ui);
|
||||
}
|
||||
if let Some(ref diff) = self.diff_all {
|
||||
diff.draw(g, ui);
|
||||
}
|
||||
self.menu.draw(g);
|
||||
self.speed.draw(g);
|
||||
}
|
||||
}
|
||||
|
||||
impl ABTestMode {
|
||||
fn step(&mut self, dt: Duration, ui: &mut UI, ctx: &EventCtx) {
|
||||
ui.primary.sim.step(&ui.primary.map, dt);
|
||||
{
|
||||
@ -228,50 +209,6 @@ impl ABTestMode {
|
||||
ui.recalculate_current_selection(ctx, &ui.primary.sim, &ShowEverything::new(), false);
|
||||
}
|
||||
|
||||
pub fn draw(state: &GameState, g: &mut GfxCtx) {
|
||||
match state.mode {
|
||||
Mode::ABTest(ref mode) => match mode.state {
|
||||
State::Setup(ref setup) => {
|
||||
state.ui.draw(
|
||||
g,
|
||||
DrawOptions::new(),
|
||||
&state.ui.primary.sim,
|
||||
&ShowEverything::new(),
|
||||
);
|
||||
setup.draw(g);
|
||||
}
|
||||
State::Scoreboard(ref s) => {
|
||||
state.ui.draw(
|
||||
g,
|
||||
DrawOptions::new(),
|
||||
&state.ui.primary.sim,
|
||||
&ShowEverything::new(),
|
||||
);
|
||||
s.draw(g);
|
||||
}
|
||||
State::Playing => {
|
||||
state.ui.draw(
|
||||
g,
|
||||
mode.common.draw_options(&state.ui),
|
||||
&state.ui.primary.sim,
|
||||
&ShowEverything::new(),
|
||||
);
|
||||
mode.common.draw(g, &state.ui);
|
||||
|
||||
if let Some(ref diff) = mode.diff_trip {
|
||||
diff.draw(g, &state.ui);
|
||||
}
|
||||
if let Some(ref diff) = mode.diff_all {
|
||||
diff.draw(g, &state.ui);
|
||||
}
|
||||
mode.menu.draw(g);
|
||||
mode.speed.draw(g);
|
||||
}
|
||||
},
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn savestate(&mut self, primary: &mut PerMapUI) {
|
||||
// Temporarily move everything into this structure.
|
||||
let blank_map = Map::blank();
|
||||
|
@ -1,16 +1,18 @@
|
||||
use crate::state::{State, Transition};
|
||||
use crate::ui::PerMapUI;
|
||||
use crate::ui::UI;
|
||||
use ezgui::{
|
||||
hotkey, EventCtx, GfxCtx, HorizontalAlignment, Key, ModalMenu, Text, VerticalAlignment, Wizard,
|
||||
WrappedWizard,
|
||||
hotkey, EventCtx, EventLoopMode, GfxCtx, HorizontalAlignment, Key, ModalMenu, Text,
|
||||
VerticalAlignment, Wizard, WrappedWizard,
|
||||
};
|
||||
use geom::Duration;
|
||||
use itertools::Itertools;
|
||||
use sim::{FinishedTrips, TripID, TripMode};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
pub enum Scoreboard {
|
||||
Summary(ModalMenu, Text),
|
||||
BrowseTrips(CompareTrips, Wizard),
|
||||
pub struct Scoreboard {
|
||||
menu: ModalMenu,
|
||||
summary: Text,
|
||||
}
|
||||
|
||||
impl Scoreboard {
|
||||
@ -76,52 +78,55 @@ impl Scoreboard {
|
||||
}
|
||||
}
|
||||
|
||||
Scoreboard::Summary(menu, summary)
|
||||
Scoreboard { menu, summary }
|
||||
}
|
||||
}
|
||||
|
||||
impl State for Scoreboard {
|
||||
fn event(&mut self, ctx: &mut EventCtx, _: &mut UI) -> (Transition, EventLoopMode) {
|
||||
self.menu.handle_event(ctx, None);
|
||||
if self.menu.action("quit") {
|
||||
return (Transition::Pop, EventLoopMode::InputOnly);
|
||||
}
|
||||
if self.menu.action("browse trips") {
|
||||
/*self = Scoreboard::BrowseTrips(
|
||||
CompareTrips::new(
|
||||
primary.sim.get_finished_trips(),
|
||||
secondary.sim.get_finished_trips(),
|
||||
),
|
||||
Wizard::new(),
|
||||
);*/
|
||||
}
|
||||
(Transition::Keep, EventLoopMode::InputOnly)
|
||||
}
|
||||
|
||||
// Returns true if done and we should go back to main A/B test mode.
|
||||
pub fn event(&mut self, ctx: &mut EventCtx, primary: &PerMapUI, secondary: &PerMapUI) -> bool {
|
||||
match self {
|
||||
Scoreboard::Summary(ref mut menu, _) => {
|
||||
menu.handle_event(ctx, None);
|
||||
if menu.action("quit") {
|
||||
return true;
|
||||
}
|
||||
if menu.action("browse trips") {
|
||||
*self = Scoreboard::BrowseTrips(
|
||||
CompareTrips::new(
|
||||
primary.sim.get_finished_trips(),
|
||||
secondary.sim.get_finished_trips(),
|
||||
),
|
||||
Wizard::new(),
|
||||
);
|
||||
}
|
||||
}
|
||||
Scoreboard::BrowseTrips(ref trips, ref mut wizard) => {
|
||||
if pick_trip(trips, &mut wizard.wrap(ctx)).is_some() {
|
||||
// TODO show more details...
|
||||
*self = Scoreboard::new(ctx, primary, secondary);
|
||||
} else if wizard.aborted() {
|
||||
*self = Scoreboard::new(ctx, primary, secondary);
|
||||
}
|
||||
}
|
||||
fn draw(&self, g: &mut GfxCtx, _: &UI) {
|
||||
g.draw_blocking_text(
|
||||
&self.summary,
|
||||
(HorizontalAlignment::Center, VerticalAlignment::Center),
|
||||
);
|
||||
self.menu.draw(g);
|
||||
}
|
||||
}
|
||||
|
||||
struct BrowseTrips {
|
||||
trips: CompareTrips,
|
||||
wizard: Wizard,
|
||||
}
|
||||
|
||||
impl State for BrowseTrips {
|
||||
fn event(&mut self, ctx: &mut EventCtx, _: &mut UI) -> (Transition, EventLoopMode) {
|
||||
if pick_trip(&self.trips, &mut self.wizard.wrap(ctx)).is_some() {
|
||||
// TODO show more details...
|
||||
return (Transition::Pop, EventLoopMode::InputOnly);
|
||||
} else if self.wizard.aborted() {
|
||||
return (Transition::Pop, EventLoopMode::InputOnly);
|
||||
}
|
||||
false
|
||||
(Transition::Keep, EventLoopMode::InputOnly)
|
||||
}
|
||||
|
||||
pub fn draw(&self, g: &mut GfxCtx) {
|
||||
match self {
|
||||
Scoreboard::Summary(ref menu, ref txt) => {
|
||||
g.draw_blocking_text(
|
||||
txt,
|
||||
(HorizontalAlignment::Center, VerticalAlignment::Center),
|
||||
);
|
||||
menu.draw(g);
|
||||
}
|
||||
Scoreboard::BrowseTrips(_, ref wizard) => {
|
||||
wizard.draw(g);
|
||||
}
|
||||
}
|
||||
fn draw(&self, g: &mut GfxCtx, _: &UI) {
|
||||
self.wizard.draw(g);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,100 +1,114 @@
|
||||
use crate::abtest::{ABTestMode, ABTestSavestate, State};
|
||||
use crate::abtest::{ABTestMode, ABTestSavestate};
|
||||
use crate::edit::apply_map_edits;
|
||||
use crate::game::{GameState, Mode};
|
||||
use crate::render::DrawMap;
|
||||
use crate::state::{State, Transition};
|
||||
use crate::ui::{Flags, PerMapUI, UI};
|
||||
use ezgui::{hotkey, EventCtx, GfxCtx, Key, LogScroller, ModalMenu, Wizard, WrappedWizard};
|
||||
use ezgui::{
|
||||
hotkey, EventCtx, EventLoopMode, GfxCtx, Key, LogScroller, ModalMenu, Wizard, WrappedWizard,
|
||||
};
|
||||
use geom::Duration;
|
||||
use map_model::{Map, MapEdits};
|
||||
use sim::{ABTest, Scenario, SimFlags};
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub enum ABTestSetup {
|
||||
Pick(Wizard),
|
||||
Manage(ModalMenu, ABTest, LogScroller),
|
||||
LoadSavestate(ABTest, Wizard),
|
||||
pub struct PickABTest {
|
||||
wizard: Wizard,
|
||||
}
|
||||
|
||||
impl ABTestSetup {
|
||||
pub fn event(state: &mut GameState, ctx: &mut EventCtx) {
|
||||
match state.mode {
|
||||
Mode::ABTest(ref mut mode) => match mode.state {
|
||||
State::Setup(ref mut setup) => match setup {
|
||||
ABTestSetup::Pick(ref mut wizard) => {
|
||||
if let Some(ab_test) = pick_ab_test(&state.ui.primary.map, wizard.wrap(ctx))
|
||||
{
|
||||
let scroller =
|
||||
LogScroller::new(ab_test.test_name.clone(), ab_test.describe());
|
||||
*setup = ABTestSetup::Manage(
|
||||
ModalMenu::new(
|
||||
&format!("A/B Test Editor for {}", ab_test.test_name),
|
||||
vec![
|
||||
(hotkey(Key::Escape), "quit"),
|
||||
(hotkey(Key::R), "run A/B test"),
|
||||
(hotkey(Key::L), "load savestate"),
|
||||
],
|
||||
ctx,
|
||||
),
|
||||
ab_test,
|
||||
scroller,
|
||||
);
|
||||
} else if wizard.aborted() {
|
||||
state.mode = Mode::SplashScreen(Wizard::new(), None);
|
||||
}
|
||||
}
|
||||
ABTestSetup::LoadSavestate(ref test, ref mut wizard) => {
|
||||
if let Some(ss) = pick_savestate(test, &mut wizard.wrap(ctx)) {
|
||||
state.mode = launch_savestate(test, ss, &mut state.ui, ctx);
|
||||
} else if wizard.aborted() {
|
||||
// TODO Here's where we need to push and pop states.
|
||||
let scroller =
|
||||
LogScroller::new(test.test_name.clone(), test.describe());
|
||||
*setup = ABTestSetup::Manage(
|
||||
ModalMenu::new(
|
||||
&format!("A/B Test Editor for {}", test.test_name),
|
||||
vec![
|
||||
(hotkey(Key::Escape), "quit"),
|
||||
(hotkey(Key::R), "run A/B test"),
|
||||
(hotkey(Key::L), "load savestate"),
|
||||
],
|
||||
ctx,
|
||||
),
|
||||
test.clone(),
|
||||
scroller,
|
||||
);
|
||||
}
|
||||
}
|
||||
ABTestSetup::Manage(ref mut menu, test, ref mut scroller) => {
|
||||
ctx.canvas.handle_event(ctx.input);
|
||||
menu.handle_event(ctx, None);
|
||||
if scroller.event(ctx.input) {
|
||||
state.mode = Mode::SplashScreen(Wizard::new(), None);
|
||||
} else if menu.action("run A/B test") {
|
||||
state.mode = launch_test(test, &mut state.ui, ctx);
|
||||
} else if menu.action("load savestate") {
|
||||
*setup = ABTestSetup::LoadSavestate(test.clone(), Wizard::new());
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => unreachable!(),
|
||||
},
|
||||
_ => unreachable!(),
|
||||
impl PickABTest {
|
||||
pub fn new() -> PickABTest {
|
||||
PickABTest {
|
||||
wizard: Wizard::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw(&self, g: &mut GfxCtx) {
|
||||
match self {
|
||||
ABTestSetup::Pick(wizard) => {
|
||||
wizard.draw(g);
|
||||
}
|
||||
ABTestSetup::LoadSavestate(_, wizard) => {
|
||||
wizard.draw(g);
|
||||
}
|
||||
ABTestSetup::Manage(ref menu, _, scroller) => {
|
||||
scroller.draw(g);
|
||||
menu.draw(g);
|
||||
}
|
||||
impl State for PickABTest {
|
||||
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> (Transition, EventLoopMode) {
|
||||
if let Some(ab_test) = pick_ab_test(&ui.primary.map, self.wizard.wrap(ctx)) {
|
||||
let scroller = LogScroller::new(ab_test.test_name.clone(), ab_test.describe());
|
||||
return (
|
||||
Transition::Replace(Box::new(ABTestSetup {
|
||||
menu: ModalMenu::new(
|
||||
&format!("A/B Test Editor for {}", ab_test.test_name),
|
||||
vec![
|
||||
(hotkey(Key::Escape), "quit"),
|
||||
(hotkey(Key::R), "run A/B test"),
|
||||
(hotkey(Key::L), "load savestate"),
|
||||
],
|
||||
ctx,
|
||||
),
|
||||
ab_test,
|
||||
scroller,
|
||||
})),
|
||||
EventLoopMode::InputOnly,
|
||||
);
|
||||
} else if self.wizard.aborted() {
|
||||
return (Transition::Pop, EventLoopMode::InputOnly);
|
||||
}
|
||||
(Transition::Keep, EventLoopMode::InputOnly)
|
||||
}
|
||||
|
||||
fn draw(&self, g: &mut GfxCtx, ui: &UI) {
|
||||
self.wizard.draw(g);
|
||||
}
|
||||
}
|
||||
|
||||
struct ABTestSetup {
|
||||
menu: ModalMenu,
|
||||
ab_test: ABTest,
|
||||
scroller: LogScroller,
|
||||
}
|
||||
|
||||
impl State for ABTestSetup {
|
||||
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> (Transition, EventLoopMode) {
|
||||
ctx.canvas.handle_event(ctx.input);
|
||||
self.menu.handle_event(ctx, None);
|
||||
if self.scroller.event(ctx.input) {
|
||||
return (Transition::Pop, EventLoopMode::InputOnly);
|
||||
} else if self.menu.action("run A/B test") {
|
||||
return (
|
||||
Transition::Replace(Box::new(launch_test(&self.ab_test, ui, ctx))),
|
||||
EventLoopMode::InputOnly,
|
||||
);
|
||||
} else if self.menu.action("load savestate") {
|
||||
return (
|
||||
Transition::Push(Box::new(LoadSavestate {
|
||||
ab_test: self.ab_test.clone(),
|
||||
wizard: Wizard::new(),
|
||||
})),
|
||||
EventLoopMode::InputOnly,
|
||||
);
|
||||
}
|
||||
(Transition::Keep, EventLoopMode::InputOnly)
|
||||
}
|
||||
|
||||
fn draw(&self, g: &mut GfxCtx, ui: &UI) {
|
||||
self.scroller.draw(g);
|
||||
self.menu.draw(g);
|
||||
}
|
||||
}
|
||||
|
||||
struct LoadSavestate {
|
||||
ab_test: ABTest,
|
||||
wizard: Wizard,
|
||||
}
|
||||
|
||||
impl State for LoadSavestate {
|
||||
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> (Transition, EventLoopMode) {
|
||||
if let Some(ss) = pick_savestate(&self.ab_test, &mut self.wizard.wrap(ctx)) {
|
||||
return (
|
||||
Transition::Replace(Box::new(launch_savestate(&self.ab_test, ss, ui, ctx))),
|
||||
EventLoopMode::InputOnly,
|
||||
);
|
||||
} else if self.wizard.aborted() {
|
||||
return (Transition::Pop, EventLoopMode::InputOnly);
|
||||
}
|
||||
(Transition::Keep, EventLoopMode::InputOnly)
|
||||
}
|
||||
|
||||
fn draw(&self, g: &mut GfxCtx, _: &UI) {
|
||||
self.wizard.draw(g);
|
||||
}
|
||||
}
|
||||
|
||||
@ -119,7 +133,7 @@ fn pick_ab_test(map: &Map, mut wizard: WrappedWizard) -> Option<ABTest> {
|
||||
}
|
||||
}
|
||||
|
||||
fn launch_test(test: &ABTest, ui: &mut UI, ctx: &mut EventCtx) -> Mode {
|
||||
fn launch_test(test: &ABTest, ui: &mut UI, ctx: &mut EventCtx) -> ABTestMode {
|
||||
let secondary = ctx.loading_screen(
|
||||
&format!("Launching A/B test {}", test.test_name),
|
||||
|ctx, mut timer| {
|
||||
@ -188,13 +202,10 @@ fn launch_test(test: &ABTest, ui: &mut UI, ctx: &mut EventCtx) -> Mode {
|
||||
},
|
||||
);
|
||||
|
||||
let mut mode = ABTestMode::new(ctx, ui, &test.test_name);
|
||||
mode.state = State::Playing;
|
||||
mode.secondary = Some(secondary);
|
||||
Mode::ABTest(mode)
|
||||
ABTestMode::new(ctx, ui, &test.test_name, secondary)
|
||||
}
|
||||
|
||||
fn launch_savestate(test: &ABTest, ss_path: String, ui: &mut UI, ctx: &mut EventCtx) -> Mode {
|
||||
fn launch_savestate(test: &ABTest, ss_path: String, ui: &mut UI, ctx: &mut EventCtx) -> ABTestMode {
|
||||
ctx.loading_screen(
|
||||
&format!("Launch A/B test from savestate {}", ss_path),
|
||||
|ctx, mut timer| {
|
||||
@ -213,9 +224,7 @@ fn launch_savestate(test: &ABTest, ss_path: String, ui: &mut UI, ctx: &mut Event
|
||||
timer.stop("setup primary");
|
||||
|
||||
timer.start("setup secondary");
|
||||
let mut mode = ABTestMode::new(ctx, ui, &test.test_name);
|
||||
mode.state = State::Playing;
|
||||
mode.secondary = Some(PerMapUI {
|
||||
let secondary = PerMapUI {
|
||||
draw_map: DrawMap::new(
|
||||
&ss.secondary_map,
|
||||
&ui.primary.current_flags,
|
||||
@ -228,9 +237,10 @@ fn launch_savestate(test: &ABTest, ss_path: String, ui: &mut UI, ctx: &mut Event
|
||||
current_selection: None,
|
||||
// TODO Hack... can we just remove these?
|
||||
current_flags: ui.primary.current_flags.clone(),
|
||||
});
|
||||
};
|
||||
timer.stop("setup secondary");
|
||||
Mode::ABTest(mode)
|
||||
|
||||
ABTestMode::new(ctx, ui, &test.test_name, secondary)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
//use crate::abtest::ABTestMode;
|
||||
use crate::abtest::setup::PickABTest;
|
||||
use crate::debug::DebugMode;
|
||||
use crate::edit::EditMode;
|
||||
//use crate::mission::MissionEditMode;
|
||||
@ -280,10 +280,8 @@ fn splash_screen(
|
||||
x if x == edit => Some(Transition::Push(Box::new(EditMode::new(ctx, ui)))),
|
||||
//x if x == tutorial => break Some(Mode::Tutorial(TutorialMode::new(ctx, ui))),
|
||||
x if x == debug => Some(Transition::Push(Box::new(DebugMode::new(ctx, ui)))),
|
||||
/*x if x == mission => break Some(Mode::Mission(MissionEditMode::new(ctx, ui))),
|
||||
x if x == abtest => {
|
||||
break Some(Mode::ABTest(ABTestMode::new(ctx, ui, "unnamed a/b test")))
|
||||
}*/
|
||||
//x if x == mission => break Some(Mode::Mission(MissionEditMode::new(ctx, ui))),
|
||||
x if x == abtest => Some(Transition::Push(Box::new(PickABTest::new()))),
|
||||
x if x == about => {
|
||||
if wizard.acknowledge(
|
||||
"About A/B Street",
|
||||
|
@ -1,4 +1,4 @@
|
||||
//mod abtest;
|
||||
mod abtest;
|
||||
mod common;
|
||||
mod debug;
|
||||
mod edit;
|
||||
|
Loading…
Reference in New Issue
Block a user