|
use std::fs::read_dir; |
|
use std::io; |
|
use std::path::*; |
|
use std::ffi::OsStr; |
|
use std::env::current_exe; |
|
|
|
use shared_library::*; |
|
|
|
use shared::GameData; |
|
|
|
shared_library!(ModData, |
|
pub fn load(), |
|
pub fn update(data : &GameData, delta_time : i32), |
|
); |
|
|
|
/// Wrapper around the loaded mods, to make calling the unsafe mod functions |
|
/// a bit easier. This shouldn't actually be considered safe but it's for |
|
/// internal use only so I'm not gonna worry about it right now |
|
pub struct GameMod { |
|
data : ModData |
|
} |
|
|
|
impl GameMod { |
|
/// Loads the mod |
|
pub fn load(&self) { |
|
unsafe { (self.data.load)() } |
|
} |
|
|
|
// Runs the update |
|
pub fn update(&self, data : &GameData, delta_time : i32) { |
|
unsafe { (self.data.update)(data, delta_time) } |
|
} |
|
} |
|
|
|
/// Finds and loads installed mods |
|
/// |
|
/// Mods are built DLL files installed in a `mods/` directory next to the |
|
/// game's main executable. |
|
/// |
|
/// Note: When running the game in debug mode, it will look for DLL files in |
|
/// the same directory as the executable instead, so you can just `cargo run` |
|
/// in the workspace directory and the game will start with mods. |
|
pub fn load() -> Result<Vec<GameMod>, io::Error> { |
|
let dir = get_mod_dir(); |
|
println!("Looking for mods in {:?}", dir); |
|
|
|
let mut mods = Vec::new(); |
|
|
|
// Try to find all mods in the directory |
|
for file in read_dir(dir)? { |
|
let file = file?; |
|
|
|
// Files ending in .dll are native mods |
|
if file.path().extension().unwrap_or(OsStr::new("")) == "dll" { |
|
let game_mod = ModData::open(&file.path()); |
|
|
|
if let Err(e) = game_mod { |
|
println!("Could not load mod {}", file.file_name().to_str().unwrap()); |
|
println!("{:?}", e); |
|
continue; |
|
} |
|
|
|
mods.push(GameMod { data: game_mod.unwrap() }); |
|
} |
|
} |
|
|
|
// Load (initialise) the mods |
|
println!("Loading {} mods...", mods.len()); |
|
for m in &mods { |
|
m.load(); |
|
} |
|
|
|
return Ok(mods); |
|
} |
|
|
|
#[cfg(debug_assertions)] |
|
fn get_mod_dir() -> PathBuf { |
|
let mut path = current_exe().expect("Could not access working directory"); |
|
path.pop(); |
|
return path; |
|
} |
|
|
|
#[cfg(not(debug_assertions))] |
|
fn get_mod_dir() -> PathBuf { |
|
let mut path = current_exe().expect("Could not access working directory"); |
|
path.pop(); |
|
path.push("mods"); |
|
return path; |
|
} |