save/load: Impl. save/load for wasm
Kind of messy, could use some cleanup
This commit is contained in:
parent
a2597a1c5c
commit
1cb833b987
5 changed files with 180 additions and 1 deletions
|
@ -2,6 +2,7 @@ pub mod agnostic_interface;
|
|||
mod faux_quicksilver;
|
||||
mod original_impl;
|
||||
mod shaders;
|
||||
mod wasm_helpers;
|
||||
|
||||
use agnostic_interface::raylib_impl::RaylibGame;
|
||||
use faux_quicksilver::Window;
|
||||
|
|
|
@ -3,6 +3,8 @@ use std::{fs::File, io::Result as IOResult, path::PathBuf, str::FromStr};
|
|||
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;
|
||||
|
@ -1899,6 +1901,8 @@ pub struct GameState {
|
|||
camera: Box<dyn CameraInterface>,
|
||||
move_to: Vector,
|
||||
save_load_notification: Option<SaveLoadNotification>,
|
||||
#[cfg(target_family = "wasm")]
|
||||
load_recv: Option<Receiver<Vec<u8>>>,
|
||||
}
|
||||
|
||||
impl GameState {
|
||||
|
@ -2028,6 +2032,8 @@ impl GameState {
|
|||
camera,
|
||||
move_to: Vector::new(400.0, 300.0),
|
||||
save_load_notification: None,
|
||||
#[cfg(target_family = "wasm")]
|
||||
load_recv: None,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -2498,7 +2504,6 @@ impl GameState {
|
|||
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() {
|
||||
|
@ -2520,6 +2525,57 @@ impl GameState {
|
|||
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(())
|
||||
}
|
||||
|
||||
|
@ -2703,11 +2759,34 @@ impl GameState {
|
|||
|
||||
#[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(())
|
||||
}
|
||||
}
|
||||
|
|
61
src/wasm_helpers.rs
Normal file
61
src/wasm_helpers.rs
Normal file
|
@ -0,0 +1,61 @@
|
|||
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)
|
||||
}
|
|
@ -5,4 +5,8 @@ extern void *ld45_initialize();
|
|||
|
||||
extern void ld45_iterate(void *context);
|
||||
|
||||
extern void ld45_save_async(void *data, int length);
|
||||
extern void ld45_load_async(void *usr);
|
||||
extern void ld45_load_rust_handler(void *usr, void *data, int len);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -5,6 +5,40 @@
|
|||
|
||||
#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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue