use crate::agnostic_interface::CameraInterface;
use crate::faux_quicksilver::{Circle, Color, Rectangle, Transform, Vector, Window};
use rand::prelude::*;
+use std::os::raw::{c_int, c_void};
+use std::sync::mpsc::{Receiver, TryRecvError};
const WIDTH_F: f32 = 800.0;
const HEIGHT_F: f32 = 600.0;
camera: Box<dyn CameraInterface>,
move_to: Vector,
save_load_notification: Option<SaveLoadNotification>,
+ #[cfg(target_family = "wasm")]
+ load_recv: Option<Receiver<Vec<u8>>>,
}
impl GameState {
camera,
move_to: Vector::new(400.0, 300.0),
save_load_notification: None,
+ #[cfg(target_family = "wasm")]
+ load_recv: None,
})
}
match sl {
SaveLoadNotification::Save { text, timer } => {
*timer -= dt;
- println!("save, timer is {}", timer);
if *timer <= 0.0 {
self.save_load_notification = None;
} else if text.is_none() {
fish.update(dt);
}
+ #[cfg(target_family = "wasm")]
+ if let Some(rx) = &mut self.load_recv {
+ let recv_result = rx.try_recv();
+ if let Ok(v) = recv_result {
+ if v.is_empty() {
+ self.save_load_notification = Some(SaveLoadNotification::Load {
+ text: Some(String::from("Failed to load! (callback failure)")),
+ timer: SL_NOTIF_TIME,
+ });
+ } else {
+ let des_result = SaveData::deserialize(&v);
+ if let Ok((save_data, _)) = des_result {
+ self.planets = save_data.planets;
+ self.stars = save_data.stars;
+ self.fishes = save_data.fishes;
+ self.player = save_data.player;
+ self.joining_particles = save_data.joining_particles;
+ self.expl_conv_p_systems.clear();
+ self.move_to = Vector::new(self.player.x, self.player.y);
+ self.camera
+ .set_view_xy(
+ self.player.x - WIDTH_F / 2.0,
+ self.player.y - HEIGHT_F / 2.0,
+ )
+ .ok();
+ self.dbl_click_timeout = None;
+ self.click_time = None;
+ self.click_release_time = DOUBLE_CLICK_TIME;
+ self.state = 10;
+ self.state_dirty = true;
+ self.save_load_notification = Some(SaveLoadNotification::Load {
+ text: None,
+ timer: SL_NOTIF_TIME,
+ });
+ } else {
+ self.save_load_notification = Some(SaveLoadNotification::Load {
+ text: Some(String::from("Failed to load! (parse issue)")),
+ timer: SL_NOTIF_TIME,
+ });
+ }
+ }
+ self.load_recv = None;
+ } else if recv_result == Err(TryRecvError::Disconnected) {
+ self.save_load_notification = Some(SaveLoadNotification::Load {
+ text: Some(String::from("Failed to load! (sender disconnected)")),
+ timer: SL_NOTIF_TIME,
+ });
+ self.load_recv = None;
+ }
+ }
+
Ok(())
}
#[cfg(target_family = "wasm")]
pub fn save(&mut self) -> IOResult<()> {
+ let save_bytes = SaveData {
+ planets: self.planets.clone(),
+ stars: self.stars.clone(),
+ fishes: self.fishes.clone(),
+ player: self.player,
+ joining_particles: self.joining_particles.clone(),
+ }
+ .serialize();
+
+ crate::wasm_helpers::save_data(&save_bytes)?;
+ self.save_load_notification = Some(SaveLoadNotification::Save {
+ text: None,
+ timer: SL_NOTIF_TIME,
+ });
+
Ok(())
}
#[cfg(target_family = "wasm")]
pub fn load(&mut self) -> IOResult<()> {
+ let receiver = crate::wasm_helpers::load_data()?;
+
+ self.load_recv = Some(receiver);
+ self.save_load_notification = Some(SaveLoadNotification::Save {
+ text: Some(String::from("Loading...")),
+ timer: SL_NOTIF_TIME,
+ });
+
Ok(())
}
}
--- /dev/null
+use std::os::raw::*;
+use std::sync::mpsc::{channel, Receiver, Sender};
+
+#[cfg(not(target_family = "wasm"))]
+pub fn save_data(data: &[u8]) -> std::io::Result<()> {
+ Err(std::io::Error::other("Unimplemented for native"))
+}
+
+#[cfg(not(target_family = "wasm"))]
+pub fn load_data() -> std::io::Result<Receiver<Vec<u8>>> {
+ Err(std::io::Error::other("Unimplemented for native"))
+}
+
+#[cfg(target_family = "wasm")]
+#[no_mangle]
+pub extern "C" fn ld45_load_rust_handler(usr: *mut c_void, data: *const c_void, len: c_int) {
+ let mut sender_box: Box<Sender<Vec<u8>>> =
+ unsafe { Box::from_raw(usr as *mut Sender<Vec<u8>>) };
+
+ if data.is_null() || len == 0 {
+ (*sender_box).send(Vec::new()).ok();
+ drop(sender_box);
+ println!("callback: Failed to load data!");
+ return;
+ }
+
+ let v: Vec<u8> =
+ unsafe { std::slice::from_raw_parts(data as *const u8, len as usize).to_owned() };
+
+ (*sender_box).send(v).ok();
+ println!("callback: Loaded data!");
+
+ drop(sender_box);
+}
+
+#[cfg(target_family = "wasm")]
+extern "C" {
+ fn ld45_save_async(data: *const c_void, length: c_int);
+ fn ld45_load_async(usr: *const c_void);
+}
+
+#[cfg(target_family = "wasm")]
+pub fn save_data(data: &[u8]) -> std::io::Result<()> {
+ unsafe {
+ ld45_save_async(data as *const [u8] as *const c_void, data.len() as c_int);
+ }
+ Ok(())
+}
+
+#[cfg(target_family = "wasm")]
+pub fn load_data() -> std::io::Result<Receiver<Vec<u8>>> {
+ let (tx, rx) = channel();
+ let mut handler = Box::new(tx);
+
+ unsafe {
+ let mut ptr = Box::into_raw(handler);
+ ld45_load_async(ptr as *mut c_void);
+ }
+
+ Ok(rx)
+}
#include <stdio.h>
+void ld45_saved_result_ok(void *usr) {
+ puts("Save OK");
+}
+
+void ld45_saved_result_err(void *usr) {
+ puts("Save ERR");
+}
+
+void ld45_load_result_ok(void *usr, void *data, int len) {
+ ld45_load_rust_handler(usr, data, len);
+}
+
+void ld45_load_result_err(void *usr) {
+ ld45_load_rust_handler(usr, NULL, 0);
+}
+
+void ld45_save_async(void *data, int length) {
+ emscripten_idb_async_store("ld45_oneandall_db",
+ "savedata",
+ data,
+ length,
+ NULL,
+ ld45_saved_result_ok,
+ ld45_saved_result_err);
+}
+
+void ld45_load_async(void *usr) {
+ emscripten_idb_async_load("ld45_oneandall_db",
+ "savedata",
+ usr,
+ ld45_load_result_ok,
+ ld45_load_result_err);
+}
+
void main_loop(void *ud) {
ld45_iterate(ud);
}