1use std::collections::HashMap;
5use std::time::Instant;
6
7use crate::assets::Assets;
8use crate::audio::AudioOut;
9use crate::angle::Angle;
10use crate::gfx::Gfx;
11use crate::host::{Game, Host, LoadOptions, Stop};
12use crate::net::Net;
13use crate::storage::Storage;
14
15pub struct Session {
16 pub name: String,
18 pub wasm: Vec<u8>,
20 pub assets: Assets,
21 pub params: HashMap<String, String>,
22 pub allow_net: bool,
23 pub allow_hosts: Vec<String>,
25 pub fetch: crate::fetch::FetchMode,
27 pub app_id: Option<String>,
29 pub storage: Storage,
30 pub load: LoadOptions,
31 pub gl_lib: Option<std::path::PathBuf>,
33 pub gl_software: bool,
35 pub gl_stats: bool,
37 pub watch_assets: Vec<crate::assets::AssetWatch>,
40}
41
42impl Session {
43 pub fn uses_gl(&self) -> bool {
45 crate::host::imports_module(&self.wasm, "gasm:gl", self.load.allow_precompiled)
46 }
47
48 pub fn open_gl(&self, window: Option<crate::angle::NativeWindow>, size: (u32, u32)) -> Result<Angle, String> {
50 let dir = crate::angle::find(self.gl_lib.as_deref())?;
51 let open = |software| match window {
52 Some(w) => Angle::window(&dir, w, software),
53 None => Angle::offscreen(&dir, size.0, size.1, software),
54 };
55 match open(self.gl_software) {
56 Err(e) if !self.gl_software => {
58 eprintln!("[gasm] gl: {e}; trying SwiftShader (software)");
59 open(true)
60 }
61 r => r,
62 }
63 }
64
65 pub fn compile_in_background(&self) -> std::thread::JoinHandle<Result<wasmtime::Module, Stop>> {
71 let (wasm, allow) = (self.wasm.clone(), self.load.allow_precompiled);
72 std::thread::spawn(move || Game::compile(&wasm, allow))
73 }
74
75 pub fn start(self, audio: Option<Box<dyn AudioOut>>, gfx: Gfx, gl: Option<Angle>, reproducible: bool, hashing: bool) -> Result<Game, Stop> {
76 self.start_with(None, audio, gfx, gl, reproducible, hashing)
77 }
78
79 pub fn start_compiled(self, module: wasmtime::Module, audio: Option<Box<dyn AudioOut>>, gfx: Gfx, gl: Option<Angle>) -> Result<Game, Stop> {
81 self.start_with(Some(module), audio, gfx, gl, false, false)
82 }
83
84 fn start_with(self, module: Option<wasmtime::Module>, audio: Option<Box<dyn AudioOut>>, gfx: Gfx, gl: Option<Angle>, reproducible: bool, hashing: bool) -> Result<Game, Stop> {
85 let policy = crate::net::NetPolicy::new(self.allow_net, self.allow_hosts);
86 let mut host = Host::new(self.assets, self.params, audio, gfx, Net::with_policy(policy.clone()), self.storage);
87 host.fetch = crate::fetch::Fetch::new(policy, self.fetch);
88 host.fetch.set_app_id(self.app_id.as_deref());
89 if self.gl_stats {
90 host.gl.stats = Some(Default::default());
91 }
92 if let Some(a) = gl {
93 eprintln!("[gasm] gl: {}", a.renderer);
94 host.gl.attach(a);
95 }
96 if reproducible {
97 host.set_reproducible();
98 }
99 host.hashing = hashing;
100 let t0 = Instant::now();
101 let module = match module {
102 Some(m) => m,
103 None => Game::compile(&self.wasm, self.load.allow_precompiled)?,
104 };
105 let mut game = Game::load_module(module, host, self.load)?;
106 for w in self.watch_assets {
107 game.add_watch(w);
108 }
109 eprintln!("[gasm] loaded {} in {:.0} ms", self.name, t0.elapsed().as_secs_f64() * 1000.0);
110 Ok(game)
111 }
112}