summaryrefslogtreecommitdiff
path: root/src/scene.rs
blob: 28a4e6a9aa4d4a38293bef3f3010b49bb51592ed (plain)
use rustc_hash::FxHashSet;
use serde::{Deserialize, Serialize};

use crate::{
	file::FileManager,
	script::{ScriptContext, ScriptManager, WasmRunner},
};

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Scene {
	pub name: Box<str>,
	pub preload_scenes: Box<[usize]>,
	pub scripts: ResourceRequirements,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct ResourceRequirements {
	pub required: Box<[usize]>,
	pub preload: Box<[usize]>,
}

pub fn scene_id_by_name(scenes: &[Scene], name: &str) -> Option<usize> {
	for (i, scene) in scenes.iter().enumerate() {
		if &*scene.name == name {
			return Some(i);
		}
	}

	None
}

pub fn preload_scene(
	scenes: &[Scene],
	scripts: &mut ScriptManager,
	files: &mut FileManager,
	wasm_runner: &WasmRunner,
	id: usize,
) {
	let scene = &scenes[id];
	for script in &scene.scripts.required {
		scripts.preload_script(*script, files, wasm_runner);
	}
}

pub fn is_scene_loaded(
	scenes: &[Scene],
	scripts: &mut ScriptManager,
	files: &mut FileManager,
	id: usize,
) -> bool {
	let scene = &scenes[id];
	scene
		.scripts
		.required
		.iter()
		.cloned()
		.all(|script_id| scripts.is_script_loaded(script_id, files))
}

pub fn switch_scenes(
	scenes: &[Scene],
	scripts: &mut ScriptManager,
	context: &mut ScriptContext<'_>,
	files: &mut FileManager,
	wasm_runner: &WasmRunner,
	new: usize,
) {
	let active_scripts = scripts
		.active_scripts
		.iter()
		.cloned()
		.collect::<Box<[usize]>>();
	for script_id in &active_scripts {
		scripts.deactivate_script(*script_id, context, wasm_runner, files);
	}

	let mut needed_scripts = FxHashSet::default();
	let scene = &scenes[new];
	for script_id in &scene.scripts.required {
		needed_scripts.insert(*script_id);
		scripts.activate_script(*script_id, context, wasm_runner, files);
	}
	for script_id in &scene.scripts.preload {
		needed_scripts.insert(*script_id);
		scripts.preload_script(*script_id, files, wasm_runner);
	}
	for scene_to_preload in &scene.preload_scenes {
		let scene_to_preload = &scenes[*scene_to_preload];
		for script_id in &scene_to_preload.scripts.required {
			needed_scripts.insert(*script_id);
			scripts.preload_script(*script_id, files, wasm_runner);
		}
	}

	let active_scripts: FxHashSet<usize> = active_scripts.iter().cloned().collect();
	let unneeded_scripts = active_scripts.difference(&needed_scripts);
	for script_id in unneeded_scripts {
		scripts.unload_script(*script_id, files);
	}
}