Compare commits

...

6 commits

Author SHA1 Message Date
Stephen Seo 1cb833b987 save/load: Impl. save/load for wasm
Kind of messy, could use some cleanup
2024-02-15 19:11:56 +09:00
Stephen Seo a2597a1c5c save/load: prevent crash on failure to save/load
TODO:
    Impl. save/load for wasm target.
2024-02-15 16:08:44 +09:00
Stephen Seo ed72c751a9 save/loading: Impl. save on native target
TODO:
    save/loading for wasm build.
2024-02-15 16:04:07 +09:00
Stephen Seo e18f3acada save/restore: Impl. tests for de/serialize
Added impl. of Default trait for Planet.

Added some derive traits (Debug and PartialEq) to some structs so that
they can be checked in the unit tests.

TODO:
    Actual saving/loading behavior.
2024-02-15 15:11:59 +09:00
Stephen Seo 63730b90bd save/restore: Impl. de/serialize for SaveData
TODO:
    Unit tests for de/serialize.
    Actual saving/loading behavior.
2024-02-15 14:22:52 +09:00
Stephen Seo 74a9980ca1 save/restore: WIP implementation
Currently working on implementing serialize/deserialize for structs for
use in saving/restoring.
2024-02-14 19:07:17 +09:00
6 changed files with 1942 additions and 91 deletions

View file

@ -14,6 +14,12 @@ pub struct Color {
pub a: u8,
}
impl Default for Color {
fn default() -> Self {
Self::WHITE
}
}
impl Color {
pub const WHITE: Self = Self {
r: 255,
@ -39,6 +45,32 @@ impl Color {
pub fn from_rgba(r: u8, g: u8, b: u8, a: u8) -> Self {
Self { r, g, b, a }
}
pub fn deserialize(data: &[u8], offset: usize) -> Result<(Color, usize), ()> {
if data.len() < offset + 4 {
Err(())
} else {
let mut color = Color::WHITE;
color.r = data[offset];
color.g = data[offset + 1];
color.b = data[offset + 2];
color.a = data[offset + 3];
Ok((color, 4))
}
}
pub fn serialize(&self) -> Vec<u8> {
let mut bytes = Vec::new();
bytes.push(self.r);
bytes.push(self.g);
bytes.push(self.b);
bytes.push(self.a);
bytes
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
@ -58,6 +90,61 @@ impl Rectangle {
self.x += v.x;
self.y += v.y;
}
pub fn deserialize(data: &[u8], offset: usize) -> Result<(Rectangle, usize), ()> {
if data.len() < offset + std::mem::size_of::<f32>() * 4 {
return Err(());
}
let mut idx: usize = 0;
let mut rect = Rectangle::new(0.0, 0.0, 0.0, 0.0);
rect.x = f32::from_be_bytes(
data[(offset + idx)..(offset + idx + std::mem::size_of::<f32>())]
.try_into()
.map_err(|_| ())?,
);
idx += std::mem::size_of::<f32>();
rect.y = f32::from_be_bytes(
data[(offset + idx)..(offset + idx + std::mem::size_of::<f32>())]
.try_into()
.map_err(|_| ())?,
);
idx += std::mem::size_of::<f32>();
rect.w = f32::from_be_bytes(
data[(offset + idx)..(offset + idx + std::mem::size_of::<f32>())]
.try_into()
.map_err(|_| ())?,
);
idx += std::mem::size_of::<f32>();
rect.h = f32::from_be_bytes(
data[(offset + idx)..(offset + idx + std::mem::size_of::<f32>())]
.try_into()
.map_err(|_| ())?,
);
idx += std::mem::size_of::<f32>();
Ok((rect, idx))
}
pub fn serialize(&self) -> Vec<u8> {
let mut bytes = Vec::new();
for byte in self.x.to_be_bytes() {
bytes.push(byte);
}
for byte in self.y.to_be_bytes() {
bytes.push(byte);
}
for byte in self.w.to_be_bytes() {
bytes.push(byte);
}
for byte in self.h.to_be_bytes() {
bytes.push(byte);
}
bytes
}
}
impl Default for Rectangle {
@ -78,6 +165,16 @@ pub struct Circle {
pub r: f32,
}
impl Default for Circle {
fn default() -> Self {
Self {
x: 0.0,
y: 0.0,
r: 1.0,
}
}
}
impl Circle {
pub fn new(x: f32, y: f32, r: f32) -> Self {
Self { x, y, r }
@ -87,6 +184,54 @@ impl Circle {
self.x += v.x;
self.y += v.y;
}
pub fn deserialize(data: &[u8], offset: usize) -> Result<(Circle, usize), ()> {
if data.len() < 12 + offset {
return Err(());
}
let mut idx: usize = 0;
let mut circle = Circle::new(0.0, 0.0, 1.0);
circle.x = f32::from_be_bytes(
data[(offset + idx)..(offset + idx + std::mem::size_of::<f32>())]
.try_into()
.map_err(|_| ())?,
);
idx += std::mem::size_of::<f32>();
circle.y = f32::from_be_bytes(
data[(offset + idx)..(offset + idx + std::mem::size_of::<f32>())]
.try_into()
.map_err(|_| ())?,
);
idx += std::mem::size_of::<f32>();
circle.r = f32::from_be_bytes(
data[(offset + idx)..(offset + idx + std::mem::size_of::<f32>())]
.try_into()
.map_err(|_| ())?,
);
idx += std::mem::size_of::<f32>();
Ok((circle, idx))
}
pub fn serialize(&self) -> Vec<u8> {
let mut bytes = Vec::new();
for byte in self.x.to_be_bytes() {
bytes.push(byte);
}
for byte in self.y.to_be_bytes() {
bytes.push(byte);
}
for byte in self.r.to_be_bytes() {
bytes.push(byte);
}
bytes
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
@ -95,6 +240,12 @@ pub struct Vector {
pub y: f32,
}
impl Default for Vector {
fn default() -> Self {
Self { x: 1.0, y: 1.0 }
}
}
impl Add<Vector> for Vector {
type Output = Vector;
@ -146,6 +297,43 @@ impl Vector {
pub fn new(x: f32, y: f32) -> Self {
Self { x, y }
}
pub fn deserialize(data: &[u8], offset: usize) -> Result<(Vector, usize), ()> {
let mut idx: usize = 0;
let mut vector = Vector::new(0.0, 0.0);
if data.len() < offset + idx + std::mem::size_of::<f32>() {
return Err(());
}
vector.x = f32::from_be_bytes(
data[(offset + idx)..(offset + idx + std::mem::size_of::<f32>())]
.try_into()
.map_err(|_| ())?,
);
idx += std::mem::size_of::<f32>();
vector.y = f32::from_be_bytes(
data[(offset + idx)..(offset + idx + std::mem::size_of::<f32>())]
.try_into()
.map_err(|_| ())?,
);
idx += std::mem::size_of::<f32>();
Ok((vector, idx))
}
pub fn serialize(&self) -> Vec<u8> {
let mut bytes = Vec::new();
for byte in self.x.to_be_bytes() {
bytes.push(byte);
}
for byte in self.y.to_be_bytes() {
bytes.push(byte);
}
bytes
}
}
impl From<(f32, f32)> for Vector {
@ -348,3 +536,48 @@ impl Window {
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_de_serialize_color() {
let color = Color::from_rgba(1, 2, 3, 4);
let bytes = color.serialize();
let (des_color, size) =
Color::deserialize(&bytes, 0).expect("Should be able to deserialize Color!");
assert_eq!(color, des_color);
assert_eq!(bytes.len(), size);
}
#[test]
fn test_de_serialize_rectangle() {
let rect = Rectangle::new(1.0, 2.0, 3.0, 4.0);
let bytes = rect.serialize();
let (des_rect, size) =
Rectangle::deserialize(&bytes, 0).expect("Should be able to deserialize Rectangle!");
assert_eq!(rect, des_rect);
assert_eq!(bytes.len(), size);
}
#[test]
fn test_de_serialize_circle() {
let circle = Circle::new(1.0, 2.0, 3.0);
let bytes = circle.serialize();
let (des_circle, size) =
Circle::deserialize(&bytes, 0).expect("Should be able to deserialize Circle!");
assert_eq!(circle, des_circle);
assert_eq!(bytes.len(), size);
}
#[test]
fn test_de_serialize_vector() {
let vect = Vector::new(1.0, 2.0);
let bytes = vect.serialize();
let (des_vect, size) =
Vector::deserialize(&bytes, 0).expect("Should be able to deserialize Vector!");
assert_eq!(vect, des_vect);
assert_eq!(bytes.len(), size);
}
}

View file

@ -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;

File diff suppressed because it is too large Load diff

61
src/wasm_helpers.rs Normal file
View 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)
}

View file

@ -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

View file

@ -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);
}