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 faux_quicksilver;
|
||||||
mod original_impl;
|
mod original_impl;
|
||||||
mod shaders;
|
mod shaders;
|
||||||
|
mod wasm_helpers;
|
||||||
|
|
||||||
use agnostic_interface::raylib_impl::RaylibGame;
|
use agnostic_interface::raylib_impl::RaylibGame;
|
||||||
use faux_quicksilver::Window;
|
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::agnostic_interface::CameraInterface;
|
||||||
use crate::faux_quicksilver::{Circle, Color, Rectangle, Transform, Vector, Window};
|
use crate::faux_quicksilver::{Circle, Color, Rectangle, Transform, Vector, Window};
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
|
use std::os::raw::{c_int, c_void};
|
||||||
|
use std::sync::mpsc::{Receiver, TryRecvError};
|
||||||
|
|
||||||
const WIDTH_F: f32 = 800.0;
|
const WIDTH_F: f32 = 800.0;
|
||||||
const HEIGHT_F: f32 = 600.0;
|
const HEIGHT_F: f32 = 600.0;
|
||||||
|
@ -1899,6 +1901,8 @@ pub struct GameState {
|
||||||
camera: Box<dyn CameraInterface>,
|
camera: Box<dyn CameraInterface>,
|
||||||
move_to: Vector,
|
move_to: Vector,
|
||||||
save_load_notification: Option<SaveLoadNotification>,
|
save_load_notification: Option<SaveLoadNotification>,
|
||||||
|
#[cfg(target_family = "wasm")]
|
||||||
|
load_recv: Option<Receiver<Vec<u8>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GameState {
|
impl GameState {
|
||||||
|
@ -2028,6 +2032,8 @@ impl GameState {
|
||||||
camera,
|
camera,
|
||||||
move_to: Vector::new(400.0, 300.0),
|
move_to: Vector::new(400.0, 300.0),
|
||||||
save_load_notification: None,
|
save_load_notification: None,
|
||||||
|
#[cfg(target_family = "wasm")]
|
||||||
|
load_recv: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2498,7 +2504,6 @@ impl GameState {
|
||||||
match sl {
|
match sl {
|
||||||
SaveLoadNotification::Save { text, timer } => {
|
SaveLoadNotification::Save { text, timer } => {
|
||||||
*timer -= dt;
|
*timer -= dt;
|
||||||
println!("save, timer is {}", timer);
|
|
||||||
if *timer <= 0.0 {
|
if *timer <= 0.0 {
|
||||||
self.save_load_notification = None;
|
self.save_load_notification = None;
|
||||||
} else if text.is_none() {
|
} else if text.is_none() {
|
||||||
|
@ -2520,6 +2525,57 @@ impl GameState {
|
||||||
fish.update(dt);
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2703,11 +2759,34 @@ impl GameState {
|
||||||
|
|
||||||
#[cfg(target_family = "wasm")]
|
#[cfg(target_family = "wasm")]
|
||||||
pub fn save(&mut self) -> IOResult<()> {
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_family = "wasm")]
|
#[cfg(target_family = "wasm")]
|
||||||
pub fn load(&mut self) -> IOResult<()> {
|
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(())
|
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_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
|
#endif
|
||||||
|
|
|
@ -5,6 +5,40 @@
|
||||||
|
|
||||||
#include <stdio.h>
|
#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) {
|
void main_loop(void *ud) {
|
||||||
ld45_iterate(ud);
|
ld45_iterate(ud);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue