1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
use me3_framework::Framework;
use me3_game_support_fromsoft::sprj::SprjGame;

use super::{game::Ds3Bootstrap, game_support::GameSupport};
use crate::widgets::Console;

type GameBootstrapRunner = dyn FnOnce(&Framework, &mut Console) -> Option<&'static dyn SprjGame>;

pub struct Bootstrapper {
    game_bootstraps: Vec<Box<GameBootstrapRunner>>,
}

impl Bootstrapper {
    pub fn new() -> Self {
        Bootstrapper {
            game_bootstraps: vec![],
        }
    }

    pub fn with_game_support<G, Support>(mut self) -> Self
    where
        G: SprjGame + 'static,
        Support: GameSupport<G> + ?Sized,
    {
        self.game_bootstraps.push(Box::new(|framework, console| {
            Support::initialize().map(|api| {
                Support::configure_console(api, console);
                Support::configure_scripting(api, framework.get_script_host());

                api as &dyn SprjGame
            })
        }));
        self
    }

    pub fn bootstrap(
        self,
        framework: &Framework,
        console: &mut Console,
    ) -> Option<&'static dyn SprjGame> {
        self.game_bootstraps
            .into_iter()
            .find_map(|bootstrap| bootstrap(framework, console))
    }
}

/// Infer the current game that is running from the environment and bootstrap an instance of [SprjGame] for the game.
pub fn bootstrap_game(
    framework: &Framework,
    console: &mut Console,
) -> Option<&'static dyn SprjGame> {
    Bootstrapper::new()
        .with_game_support::<_, Ds3Bootstrap>()
        .bootstrap(framework, console)
}