use crate::client::*;
use crate::gfx;
use crate::os;
use crate::reloader;
use std::process::ExitStatus;
use std::process::Command;
use std::io::{self, Write};
pub struct PluginReloadResponder {
pub name: String,
pub path: String,
pub output_filepath: String,
pub files: Vec<String>
}
pub trait Plugin<D: gfx::Device, A: os::App> {
fn create() -> Self where Self: Sized;
fn setup(&mut self, client: Client<D, A>) -> Client<D, A>;
fn update(&mut self, client: Client<D, A>) -> Client<D, A>;
fn ui(&mut self, client: Client<D, A>) -> Client<D, A>;
fn unload(&mut self, client: Client<D, A>) -> Client<D, A>;
}
pub fn build_all() {
let path = super::get_data_path("..");
let output = if super::get_config_name() == "release" {
Command::new("cargo")
.current_dir(path)
.arg("build")
.arg("--release")
.output()
.expect("hotline::hot_lib:: hot lib failed to build!")
}
else {
Command::new("cargo")
.current_dir(path)
.arg("build")
.output()
.expect("hotline::hot_lib:: hot lib failed to build!")
};
if !output.stdout.is_empty() {
println!("{}", String::from_utf8(output.stdout).unwrap());
}
if !output.stderr.is_empty() {
println!("{}", String::from_utf8(output.stderr).unwrap());
}
}
impl reloader::ReloadResponder for PluginReloadResponder {
fn add_file(&mut self, path: &str) {
self.files.push(path.to_string());
}
fn get_files(&self) -> Vec<String> {
let src_path = self.path.to_string() + "/" + &self.name.to_string() + "/src";
let src_files = super::get_files_recursive(&src_path, Vec::new());
let mut result = self.files.to_vec();
result.extend(src_files);
result
}
fn get_last_mtime(&self) -> std::time::SystemTime {
let meta = std::fs::metadata(&self.output_filepath);
if meta.is_ok() {
std::fs::metadata(&self.output_filepath).unwrap().modified().unwrap()
}
else {
std::time::SystemTime::now()
}
}
fn build(&mut self) -> ExitStatus {
let output = if super::get_config_name() == "release" {
Command::new("cargo")
.current_dir(&self.path)
.arg("build")
.arg("--release")
.arg("-p")
.arg(&self.name)
.output()
.expect("hotline::hot_lib:: hot lib failed to build!")
}
else {
Command::new("cargo")
.current_dir(&self.path)
.arg("build")
.arg("-p")
.arg(&self.name)
.output()
.expect("hotline::hot_lib:: hot lib failed to build!")
};
let mut stdout = io::stdout().lock();
if !output.stdout.is_empty() {
stdout.write_all(&output.stdout).unwrap();
}
if !output.stderr.is_empty() {
stdout.write_all(&output.stderr).unwrap();
}
output.status
}
}
#[macro_export]
macro_rules! hotline_plugin {
($input:ident) => {
#[no_mangle]
pub fn create() -> *mut core::ffi::c_void {
let plugin = $input::create();
let ptr = Box::into_raw(Box::new(plugin));
ptr.cast()
}
#[no_mangle]
pub fn update(mut client: client::Client<gfx_platform::Device, os_platform::App>, ptr: *mut core::ffi::c_void) -> client::Client<gfx_platform::Device, os_platform::App> {
unsafe {
let plugin = ptr.cast::<$input>();
let plugin = plugin.as_mut().unwrap();
plugin.update(client)
}
}
#[no_mangle]
pub fn setup(mut client: client::Client<gfx_platform::Device, os_platform::App>, ptr: *mut core::ffi::c_void) -> client::Client<gfx_platform::Device, os_platform::App> {
unsafe {
let plugin = ptr.cast::<$input>();
let plugin = plugin.as_mut().unwrap();
plugin.setup(client)
}
}
#[no_mangle]
pub fn unload(mut client: client::Client<gfx_platform::Device, os_platform::App>, ptr: *mut core::ffi::c_void) -> client::Client<gfx_platform::Device, os_platform::App> {
unsafe {
let plugin = ptr.cast::<$input>();
let plugin = plugin.as_mut().unwrap();
plugin.unload(client)
}
}
#[no_mangle]
pub fn ui(mut client: client::Client<gfx_platform::Device, os_platform::App>, ptr: *mut core::ffi::c_void, imgui_ctx: *mut core::ffi::c_void) -> client::Client<gfx_platform::Device, os_platform::App> {
unsafe {
let plugin = ptr.cast::<$input>();
let plugin = plugin.as_mut().unwrap();
client.imgui.set_current_context(imgui_ctx);
plugin.ui(client)
}
}
}
}
pub type PluginInstance = *mut core::ffi::c_void;