Continue implementing save state deserialization in libretro builds

This commit is contained in:
刘皓 2025-05-27 16:59:41 -04:00
parent 290ce15875
commit 8ca753d85d
No known key found for this signature in database
GPG key ID: 7901753DB465B711
36 changed files with 758 additions and 148 deletions

View file

@ -220,6 +220,8 @@ void binding_base::strncpy(wasm_ptr_t dst_address, const char *src, wasm_size_t
sandbox_strncpy(instance(), dst_address, src, max_size);
}
binding_base::object::object() : inner {.next = 0}, typenum(0) {}
binding_base::object::object(wasm_size_t typenum, void *ptr) : inner {.ptr = ptr}, typenum(typenum) {}
binding_base::object::object(struct object &&object) noexcept : inner(std::exchange(object.inner, (union binding_base::object::inner){.next = 0})), typenum(std::exchange(object.typenum, 0)) {}
@ -239,10 +241,6 @@ binding_base::object::~object() {
}
}
const std::vector<struct binding_base::object> &binding_base::get_objects() const noexcept {
return objects;
}
wasm_objkey_t binding_base::create_object(wasm_size_t typenum, void *ptr) {
if (ptr == nullptr || typenum == 0 || typenum > typenum_table_size) {
std::abort();

View file

@ -199,8 +199,10 @@ namespace mkxp_sandbox {
}
struct typenum_table_entry {
void *(*constructor)();
void (*destructor)(void *self);
bool (*serialize)(const void *self, void *&data, wasm_size_t &max_size);
bool (*deserialize)(void *self, const void *&data, wasm_size_t &max_size);
};
extern const struct typenum_table_entry typenum_table[];
@ -270,6 +272,7 @@ namespace mkxp_sandbox {
// Otherwise, this is a number corresponding to the type of the object.
wasm_size_t typenum;
object();
object(wasm_size_t typenum, void *ptr);
object(const struct object &object) = delete;
object(struct object &&object) noexcept;
@ -278,12 +281,14 @@ namespace mkxp_sandbox {
~object();
};
std::shared_ptr<struct w2c_ruby> _instance;
public:
std::vector<struct object> objects;
wasm_objkey_t next_free_objkey;
private:
std::shared_ptr<struct w2c_ruby> _instance;
wasm_ptr_t stack_ptr;
public:
wasm_objkey_t next_free_objkey;
std::unordered_map<key_t, struct fiber, boost::hash<key_t>> fibers;
binding_base(std::shared_ptr<struct w2c_ruby> m);
@ -335,9 +340,6 @@ namespace mkxp_sandbox {
return sandbox_arycpy(instance(), dst_address, src, num_elements);
}
// Returns a reference to all currently existing objects.
const std::vector<struct object> &get_objects() const noexcept;
// Creates a new object and returns its key.
wasm_objkey_t create_object(wasm_size_t typenum, void *ptr);

View file

@ -24,9 +24,33 @@
using namespace mkxp_sandbox;
template <typename T> static typename std::enable_if<std::is_constructible<T>::value, void *>::type constructor() {
static_assert(!(std::is_same<T, Tilemap::Autotiles>::value || std::is_same<T, TilemapVX::BitmapArray>::value), "this type should not have a public constructor");
return new T;
}
template <typename T> static typename std::enable_if<!std::is_constructible<T>::value && std::is_constructible<T, Exception &>::value, void *>::type constructor() {
static_assert(!(std::is_same<T, Tilemap::Autotiles>::value || std::is_same<T, TilemapVX::BitmapArray>::value), "this type should not have a public constructor");
Exception e;
T *obj = new T(e);
if (e.is_ok()) {
return obj;
} else {
delete obj;
return nullptr;
}
}
template <typename T> static typename std::enable_if<!std::is_constructible<T>::value && !std::is_constructible<T, Exception &>::value, void *>::type constructor() {
static_assert((std::is_same<T, Tilemap::Autotiles>::value || std::is_same<T, TilemapVX::BitmapArray>::value), "this type should have a public constructor");
return nullptr;
}
template <typename T> static typename std::enable_if<std::is_destructible<T>::value>::type destructor(void *self) {
static_assert(!(std::is_same<T, Tilemap::Autotiles>::value || std::is_same<T, TilemapVX::BitmapArray>::value), "this type should not have a public destructor");
delete (T *)self;
if (self != nullptr) {
delete (T *)self;
}
}
template <typename T> static typename std::enable_if<!std::is_destructible<T>::value>::type destructor(void *self) {
@ -37,7 +61,11 @@ template <typename T> static bool serialize(const void *self, void *&data, wasm_
return ((const T *)self)->sandbox_serialize(data, max_size);
}
#define _SANDBOX_DEF_TYPENUM_TABLE_ENTRY(_r, _data, T) {.destructor = destructor<T>, .serialize = serialize<T>},
template <typename T> static bool deserialize(void *self, const void *&data, wasm_size_t &max_size) {
return ((T *)self)->sandbox_deserialize(data, max_size);
}
#define _SANDBOX_DEF_TYPENUM_TABLE_ENTRY(_r, _data, T) {.constructor = constructor<T>, .destructor = destructor<T>, .serialize = serialize<T>, .deserialize = deserialize<T>},
extern const struct typenum_table_entry mkxp_sandbox::typenum_table[SANDBOX_NUM_TYPENUMS] = {BOOST_PP_SEQ_FOR_EACH(_SANDBOX_DEF_TYPENUM_TABLE_ENTRY, _, SANDBOX_TYPENUM_TYPES)};
extern const wasm_size_t mkxp_sandbox::typenum_table_size = SANDBOX_NUM_TYPENUMS;

View file

@ -44,7 +44,7 @@ std::vector<std::tuple<const void *, wasm_size_t>> mkxp_sandbox::extra_objects;
std::unordered_map<wasm_size_t, struct sandbox_object_deser_info> mkxp_sandbox::objects_deser;
std::unordered_map<wasm_size_t, struct sandbox_object_deser_info> mkxp_sandbox::extra_objects_deser;
sandbox_object_deser_info::sandbox_object_deser_info() : ptr(new std::vector<void **>), typenum(0), ref_count(0), exists(false) {}
sandbox_object_deser_info::sandbox_object_deser_info(void *ptr, wasm_size_t typenum) : ptr(ptr), typenum(typenum), ref_count(0), exists(true) {}
sandbox_object_deser_info::sandbox_object_deser_info(struct sandbox_object_deser_info &&info) noexcept : ptr(std::exchange(info.ptr, nullptr)), typenum(info.typenum), ref_count(std::exchange(info.ref_count, 1)), exists(std::exchange(info.exists, true)) {}
@ -66,6 +66,32 @@ wasm_size_t sandbox_object_deser_info::get_ref_count() const noexcept {
return ref_count;
}
bool sandbox_object_deser_info::set_ptr(void *ptr, wasm_size_t typenum) {
if (this->typenum != typenum) {
return false;
}
if (exists && ptr != this->ptr) {
return false;
}
if (!exists) {
for (void **ref : *(std::vector<void **> *)this->ptr) {
*ref = ptr;
}
delete (std::vector<void **> *)this->ptr;
exists = true;
this->ptr = ptr;
}
return true;
}
void *sandbox_object_deser_info::get_ptr() {
return exists ? ptr : nullptr;
}
wasm_size_t sandbox_object_deser_info::get_typenum() {
return typenum;
}
template <> bool mkxp_sandbox::sandbox_serialize(bool value, void *&data, wasm_size_t &max_size) {
RESERVE(sizeof(uint8_t));
*(uint8_t *)data = value;
@ -221,7 +247,8 @@ template <> bool mkxp_sandbox::sandbox_deserialize(double &value, const void *&d
}
template <> bool mkxp_sandbox::sandbox_serialize(const char *value, void *&data, wasm_size_t &max_size) {
wasm_size_t size = std::strlen(value) + 1;
wasm_size_t size = std::strlen(value);
if (!sandbox_serialize(size, data, max_size)) return false;
RESERVE(size);
std::memcpy(data, value, size);
ADVANCE(size);
@ -229,7 +256,8 @@ template <> bool mkxp_sandbox::sandbox_serialize(const char *value, void *&data,
}
template <> bool mkxp_sandbox::sandbox_serialize(const std::string &value, void *&data, wasm_size_t &max_size) {
wasm_size_t size = value.length() + 1;
wasm_size_t size = value.length();
if (!sandbox_serialize(size, data, max_size)) return false;
RESERVE(size);
std::memcpy(data, value.c_str(), size);
ADVANCE(size);
@ -239,12 +267,12 @@ template <> bool mkxp_sandbox::sandbox_serialize(const std::string &value, void
template <> bool mkxp_sandbox::sandbox_deserialize(std::string &value, const void *&data, wasm_size_t &max_size) {
wasm_size_t size;
if (!sandbox_deserialize(size, data, max_size)) return false;
if (size == 0 || ((const char *)data)[size - 1] != 0) return false;
RESERVE(size);
value.resize(size - 1);
value.clear();
value.resize(size);
char *str = &value[0];
std::memcpy(str, data, size - 1);
if (std::strlen(str) != size - 1) {
std::memcpy(str, data, size);
if (std::strlen(str) != size) {
value.clear();
return false;
}

View file

@ -32,8 +32,8 @@
namespace mkxp_sandbox {
struct sandbox_object_deser_info {
sandbox_object_deser_info();
template <typename T> sandbox_object_deser_info(T *ptr) : ptr(ptr), typenum(get_typenum<T>::value), ref_count(0), exists(true) {}
template <typename T> sandbox_object_deser_info(T *&ref) : ptr(new std::vector<void **>({(void **)&ref})), typenum(mkxp_sandbox::get_typenum<T>::value), ref_count(1), exists(false) {}
sandbox_object_deser_info(void *ptr, wasm_size_t typenum);
sandbox_object_deser_info(const struct sandbox_object_deser_info &) = delete;
sandbox_object_deser_info(struct sandbox_object_deser_info &&) noexcept;
struct sandbox_object_deser_info &operator=(const struct sandbox_object_deser_info &) = delete;
@ -41,37 +41,25 @@ namespace mkxp_sandbox {
~sandbox_object_deser_info();
wasm_size_t get_ref_count() const noexcept;
template <typename T> bool add_ref(T *&ref) {
if (typenum == 0) {
typenum = get_typenum<T>::value;
} else if (typenum != get_typenum<T>::value) {
if (typenum != mkxp_sandbox::get_typenum<T>::value) {
return false;
}
if (ref_count > 0 && (std::is_same<T, Color>::value || std::is_same<T, Tone>::value || std::is_same<T, Rect>::value || std::is_same<T, Tilemap::Autotiles>::value || std::is_same<T, TilemapVX::BitmapArray>::value)) {
// Don't allow types that are copied by value (Color, Tone and Rect) or autotiles/bitmap arrays to be referenced more than once
return false;
}
if (exists) {
ref = (T *)ptr;
} else {
ref = nullptr;
((std::vector<void **> *)ptr)->push_back((void **)&ref);
}
++ref_count;
return true;
}
template <typename T> bool set_ptr(T *ptr) {
if (typenum == 0) {
typenum = get_typenum<T>::value;
} else if (typenum != get_typenum<T>::value) {
return false;
}
if (exists && ptr != this->ptr) {
return false;
}
if (!exists) {
for (void **ref : *(std::vector<void **> *)this->ptr) {
*(T **)ref = ptr;
}
delete (std::vector<void **> *)this->ptr;
exists = true;
this->ptr = ptr;
}
}
bool set_ptr(void *ptr, wasm_size_t typenum);
void *get_ptr();
wasm_size_t get_typenum();
private:
// If `exists` is true, this is a pointer to the object. Otherwise, this is a `std::vector<void **>` of pointers that are waiting to point to the object.
@ -138,7 +126,7 @@ namespace mkxp_sandbox {
extra_objects.clear();
wasm_objkey_t key = 0;
for (const auto &object : sb()->get_objects()) {
for (const auto &object : sb()->objects) {
++key;
if (object.typenum == get_typenum<T>::value) {
map.emplace((T *)object.inner.ptr, (struct info){.key = key, .is_extra = false});
@ -221,7 +209,8 @@ namespace mkxp_sandbox {
auto &deser_map = type != 0 ? extra_objects_deser : objects_deser;
const auto it = deser_map.find(key);
if (it == deser_map.end()) {
return deser_map.emplace(key, sandbox_object_deser_info()).first->second.add_ref(ref);
deser_map.emplace(key, sandbox_object_deser_info(ref));
return true;
} else {
return it->second.add_ref(ref);
}
@ -234,6 +223,15 @@ namespace mkxp_sandbox {
is_deserializing = false;
objects_deser.clear();
// Delete extra objects with no references so we don't leak them
for (auto &pair : extra_objects_deser) {
struct sandbox_object_deser_info &info = pair.second;
if (info.get_ref_count() == 0 && info.get_ptr() != nullptr) {
typenum_table[info.get_typenum() - 1].destructor(info.get_ptr());
}
}
extra_objects_deser.clear();
}
};
@ -268,9 +266,6 @@ namespace mkxp_sandbox {
if (!sandbox_deserialize(value.back(), data, max_size)) return false;
--size;
}
for (T &item : value) {
if (!sandbox_deserialize(item, data, max_size)) return false;
}
return true;
}

View file

@ -129,6 +129,10 @@ bool sandbox::sandbox_serialize_fdtable(void *&data, wasm_size_t &max_size) cons
return wasi->sandbox_serialize(data, max_size);
}
bool sandbox::sandbox_deserialize_fdtable(const void *&data, wasm_size_t &max_size) {
return wasi->sandbox_deserialize(data, max_size);
}
Movie *sandbox::get_movie_from_main_thread() {
return movie.load(std::memory_order_relaxed); // No need for synchronization because we always set the movie from the main thread
}

View file

@ -64,6 +64,7 @@ namespace mkxp_sandbox {
sandbox();
~sandbox();
bool sandbox_serialize_fdtable(void *&data, wasm_size_t &max_size) const;
bool sandbox_deserialize_fdtable(const void *&data, wasm_size_t &max_size);
Movie *get_movie_from_main_thread();
Movie *get_movie_from_audio_thread();
void set_movie(Movie *new_movie);

View file

@ -20,6 +20,7 @@
*/
#include <algorithm>
#include <cstdint>
#include <cstring>
#include <random>
#include <sstream>
@ -41,8 +42,8 @@ struct fs_dir *wasi_file_entry::dir_handle() const noexcept {
return (struct fs_dir *)handle;
}
struct FileSystem::File *wasi_file_entry::file_handle() const noexcept {
return (struct FileSystem::File *)handle;
struct fs_file *wasi_file_entry::file_handle() const noexcept {
return (struct fs_file *)handle;
}
wasi_t::w2c_wasi__snapshot__preview1(std::shared_ptr<struct w2c_ruby> ruby) : ruby(ruby) {
@ -50,15 +51,15 @@ wasi_t::w2c_wasi__snapshot__preview1(std::shared_ptr<struct w2c_ruby> ruby) : ru
fdtable.push_back({.type = wasi_fd_type::STDIN});
fdtable.push_back({.type = wasi_fd_type::STDOUT});
fdtable.push_back({.type = wasi_fd_type::STDERR});
fdtable.push_back({.type = wasi_fd_type::FS, .handle = new fs_dir {.root = nullptr, .path = std::string("/Game"), .writable = true}});
fdtable.push_back({.type = wasi_fd_type::FS, .handle = new fs_dir {.root = nullptr, .path = std::string("/Save"), .writable = true}});
fdtable.push_back({.type = wasi_fd_type::FS, .handle = new fs_dir {.root = nullptr, .path = std::string("/System"), .writable = false}});
fdtable.push_back({.type = wasi_fd_type::FS, .handle = new fs_dir {.root = nullptr, .path = std::string("/Dist"), .writable = false}});
fdtable.push_back({.type = wasi_fd_type::FS, .handle = new fs_dir {.path = std::string("/Game"), .writable = true}});
fdtable.push_back({.type = wasi_fd_type::FS, .handle = new fs_dir {.path = std::string("/Save"), .writable = true}});
fdtable.push_back({.type = wasi_fd_type::FS, .handle = new fs_dir {.path = std::string("/System"), .writable = false}});
fdtable.push_back({.type = wasi_fd_type::FS, .handle = new fs_dir {.path = std::string("/Dist"), .writable = false}});
}
wasi_t::~w2c_wasi__snapshot__preview1() {
// Close all of the open WASI file descriptors
for (size_t i = fdtable.size(); i > 0;) {
for (uint32_t i = fdtable.size(); i > 0;) {
deallocate_file_descriptor(--i);
}
}
@ -76,12 +77,17 @@ struct fs_enumerate_data {
uint32_t wasi_t::allocate_file_descriptor(enum wasi_fd_type type, void *handle) {
if (vacant_fds.empty()) {
if (fdtable.size() >= UINT32_MAX) {
MKXPZ_THROW(std::bad_alloc());
}
uint32_t fd = fdtable.size();
fdtable.push_back({.type = type, .handle = handle});
return fd;
} else {
uint32_t fd = vacant_fds.back();
vacant_fds.pop_back();
fdtable[fd].type = type;
fdtable[fd].handle = handle;
return fd;
}
}
@ -97,16 +103,12 @@ void wasi_t::deallocate_file_descriptor(uint32_t fd) {
delete fdtable[fd].file_handle();
break;
default:
break;
return;
}
}
if (!fdtable.empty() && fd == fdtable.size() - 1) {
fdtable.pop_back();
} else {
fdtable[fd] = {.type = wasi_fd_type::VACANT, .handle = nullptr};
vacant_fds.push_back(fd);
}
fdtable[fd] = {.type = wasi_fd_type::VACANT, .handle = nullptr};
vacant_fds.push_back(fd);
}
void *wasi_t::ptr(wasm_ptr_t address) const noexcept {
@ -130,9 +132,9 @@ const char *wasi_t::str(wasm_ptr_t address) const noexcept {
}
bool wasi_t::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const {
if (!::sandbox_serialize((wasm_size_t)fdtable.size(), data, max_size)) return false;
if (!::sandbox_serialize((uint32_t)fdtable.size(), data, max_size)) return false;
wasm_size_t num_free_handles = 0;
uint32_t num_free_handles = 0;
for (const struct wasi_file_entry &entry : fdtable) {
if (entry.type == wasi_fd_type::FSDIR) {
@ -142,8 +144,8 @@ bool wasi_t::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size)
num_free_handles = 0;
}
if (!::sandbox_serialize((uint8_t)1, data, max_size)) return false;
if (!::sandbox_serialize(entry.dir_handle()->root, data, max_size)) return false;
if (!::sandbox_serialize(entry.dir_handle()->path, data, max_size)) return false;
if (!::sandbox_serialize(entry.dir_handle()->root->path, data, max_size)) return false;
} else if (entry.type == wasi_fd_type::FSFILE) {
if (num_free_handles > 0) {
if (!::sandbox_serialize((uint8_t)0, data, max_size)) return false;
@ -151,7 +153,8 @@ bool wasi_t::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size)
num_free_handles = 0;
}
if (!::sandbox_serialize((uint8_t)2, data, max_size)) return false;
if (!::sandbox_serialize(entry.file_handle()->path(), data, max_size)) return false;
if (!::sandbox_serialize(entry.file_handle()->root, data, max_size)) return false;
if (!::sandbox_serialize(entry.file_handle()->file.path(), data, max_size)) return false;
} else {
++num_free_handles;
}
@ -165,6 +168,79 @@ bool wasi_t::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size)
return true;
}
bool wasi_t::sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size) {
uint32_t size;
if (!::sandbox_deserialize(size, data, max_size)) return false;
for (uint32_t i = fdtable.size(); i > size;) {
deallocate_file_descriptor(--i);
}
vacant_fds.clear();
fdtable.resize(size, {.type = wasi_fd_type::VACANT});
uint32_t i = 0;
while (i < size) {
uint8_t type;
if (!::sandbox_deserialize(type, data, max_size)) return false;
if (type == 0) {
uint32_t num_free_handles;
if (!::sandbox_deserialize(num_free_handles, data, max_size)) return false;
if (i + num_free_handles > size || i + num_free_handles < i) return false;
for (uint32_t j = i; j < i + num_free_handles; ++j) {
deallocate_file_descriptor(j);
vacant_fds.clear();
}
i += num_free_handles;
} else {
if (fdtable[i].type != wasi_fd_type::VACANT && fdtable[i].type != wasi_fd_type::FSDIR && fdtable[i].type != wasi_fd_type::FSFILE) {
return false;
}
if (type == 1) {
if (fdtable[i].type != wasi_fd_type::VACANT && fdtable[i].type != wasi_fd_type::FSDIR) {
deallocate_file_descriptor(i);
vacant_fds.clear();
}
uint32_t root;
if (!::sandbox_deserialize(root, data, max_size)) return false;
if (root >= fdtable.size() || fdtable[root].type != wasi_fd_type::FS) return false;
std::string path;
if (!::sandbox_deserialize(path, data, max_size)) return false;
path = mkxp_retro::fs->normalize(path.c_str(), false, true);
fdtable[i] = {.type = wasi_fd_type::FSDIR, .handle = new fs_dir {.path = path, .root = root, .writable = fdtable[root].dir_handle()->writable}};
} else if (type == 2) {
if (fdtable[i].type != wasi_fd_type::VACANT && fdtable[i].type != wasi_fd_type::FSFILE) {
deallocate_file_descriptor(i);
vacant_fds.clear();
}
uint32_t root;
if (!::sandbox_deserialize(root, data, max_size)) return false;
if (root >= fdtable.size() || fdtable[root].type != wasi_fd_type::FS) return false;
std::string path;
if (!::sandbox_deserialize(path, data, max_size)) return false;
path = mkxp_retro::fs->normalize(path.c_str(), false, true);
struct fs_file *handle = new fs_file {.file {*mkxp_retro::fs, path.c_str(), fdtable[root].dir_handle()->writable ? fdtable[root].dir_handle()->path.c_str() : nullptr, false}, .root = root};
if (!handle->file.is_open() || (fdtable[root].dir_handle()->writable && !handle->file.is_write_open())) {
delete handle;
return false;
}
fdtable[i] = {.type = wasi_fd_type::FSFILE, .handle = handle};
} else {
return false;
}
++i;
}
}
for (uint32_t j = 0; i < fdtable.size(); ++j) {
if (fdtable[j].type == wasi_fd_type::VACANT) {
vacant_fds.push_back(j);
}
}
return true;
}
extern "C" uint32_t w2c_wasi__snapshot__preview1_args_get(wasi_t *wasi, wasm_ptr_t argv, wasm_ptr_t argv_buf) {
return WASI_ESUCCESS;
}
@ -212,6 +288,7 @@ extern "C" uint32_t w2c_wasi__snapshot__preview1_fd_close(wasi_t *wasi, uint32_t
case wasi_fd_type::STDOUT:
case wasi_fd_type::STDERR:
case wasi_fd_type::FS:
return WASI_EINVAL;
case wasi_fd_type::FSDIR:
case wasi_fd_type::FSFILE:
@ -324,7 +401,7 @@ extern "C" uint32_t w2c_wasi__snapshot__preview1_fd_filestat_get(wasi_t *wasi, u
case wasi_fd_type::FSFILE:
{
PHYSFS_Stat stat;
if (!PHYSFS_stat(wasi->fdtable[fd].file_handle()->path(), &stat)) {
if (!PHYSFS_stat(wasi->fdtable[fd].file_handle()->file.path(), &stat)) {
return WASI_ENOENT;
}
if (stat.filetype != PHYSFS_FILETYPE_REGULAR) {
@ -448,7 +525,7 @@ extern "C" uint32_t w2c_wasi__snapshot__preview1_fd_read(wasi_t *wasi, uint32_t
#ifdef MKXPZ_BIG_ENDIAN
ptr -= length;
#endif // MKXPZ_BIG_ENDIAN
PHYSFS_sint64 n = PHYSFS_readBytes(wasi->fdtable[fd].file_handle()->get(), ptr, length);
PHYSFS_sint64 n = PHYSFS_readBytes(wasi->fdtable[fd].file_handle()->file.get(), ptr, length);
#ifdef MKXPZ_BIG_ENDIAN
std::reverse(ptr, ptr + length);
#endif // MKXPZ_BIG_ENDIAN
@ -597,12 +674,8 @@ extern "C" uint32_t w2c_wasi__snapshot__preview1_fd_renumber(wasi_t *wasi, uint3
} else {
wasi->fdtable[to] = wasi->fdtable[fd];
}
if (!wasi->fdtable.empty() && fd == wasi->fdtable.size() - 1) {
wasi->fdtable.pop_back();
} else {
wasi->fdtable[fd] = {.type = wasi_fd_type::VACANT, .handle = nullptr};
wasi->vacant_fds.push_back(fd);
}
wasi->fdtable[fd] = {.type = wasi_fd_type::VACANT, .handle = nullptr};
wasi->vacant_fds.push_back(fd);
return WASI_ESUCCESS;
}
@ -634,7 +707,7 @@ extern "C" uint32_t w2c_wasi__snapshot__preview1_fd_tell(wasi_t *wasi, uint32_t
return WASI_EINVAL;
case wasi_fd_type::FSFILE:
wasi->ref<uint64_t>(result) = PHYSFS_tell(wasi->fdtable[fd].file_handle()->get());
wasi->ref<uint64_t>(result) = PHYSFS_tell(wasi->fdtable[fd].file_handle()->file.get());
return WASI_ESUCCESS;
}
@ -681,7 +754,7 @@ extern "C" uint32_t w2c_wasi__snapshot__preview1_fd_write(wasi_t *wasi, uint32_t
case wasi_fd_type::FSFILE:
{
if (!wasi->fdtable[fd].file_handle()->is_write_open()) {
if (!wasi->fdtable[fd].file_handle()->file.is_write_open()) {
return WASI_EROFS;
}
uint32_t size = 0;
@ -692,7 +765,7 @@ extern "C" uint32_t w2c_wasi__snapshot__preview1_fd_write(wasi_t *wasi, uint32_t
ptr -= length;
std::reverse(ptr, ptr + length);
#endif // MKXPZ_BIG_ENDIAN
PHYSFS_sint64 n = PHYSFS_writeBytes(wasi->fdtable[fd].file_handle()->get_write(), ptr, length);
PHYSFS_sint64 n = PHYSFS_writeBytes(wasi->fdtable[fd].file_handle()->file.get_write(), ptr, length);
#ifdef MKXPZ_BIG_ENDIAN
std::reverse(ptr, ptr + length);
#endif // MKXPZ_BIG_ENDIAN
@ -777,6 +850,10 @@ extern "C" uint32_t w2c_wasi__snapshot__preview1_path_open(wasi_t *wasi, uint32_
return WASI_EBADF;
}
if (wasi->fdtable.size() >= UINT32_MAX && wasi->vacant_fds.empty()) {
return WASI_EMFILE;
}
switch (wasi->fdtable[fd].type) {
case wasi_fd_type::VACANT:
return WASI_EBADF;
@ -833,26 +910,27 @@ extern "C" uint32_t w2c_wasi__snapshot__preview1_path_open(wasi_t *wasi, uint32_
return WASI_EROFS;
}
uint32_t root = wasi->fdtable[fd].type == wasi_fd_type::FS ? fd : wasi->fdtable[fd].dir_handle()->root;
if (exists && stat.filetype == PHYSFS_FILETYPE_DIRECTORY) {
struct fs_dir *root = wasi->fdtable[fd].dir_handle()->root != nullptr ? wasi->fdtable[fd].dir_handle()->root : wasi->fdtable[fd].dir_handle();
struct fs_dir *handle = new fs_dir {.root = root, .path = new_path, .writable = writable};
struct fs_dir *handle = new fs_dir {.path = new_path, .root = root, .writable = writable};
wasi->ref<uint32_t>(result) = wasi->allocate_file_descriptor(wasi_fd_type::FSDIR, handle);
} else {
const char *write_path_prefix;
if (writable) {
struct fs_dir *root = wasi->fdtable[fd].dir_handle()->root != nullptr ? wasi->fdtable[fd].dir_handle()->root : wasi->fdtable[fd].dir_handle();
write_path_prefix = root->path.c_str();
uint32_t root = wasi->fdtable[fd].type == wasi_fd_type::FS ? fd : wasi->fdtable[fd].dir_handle()->root;
write_path_prefix = wasi->fdtable[root].dir_handle()->path.c_str();
} else {
write_path_prefix = nullptr;
}
struct FileSystem::File *handle = new FileSystem::File(*mkxp_retro::fs, new_path.c_str(), write_path_prefix, truncate, exists);
struct fs_file *handle = new fs_file {.file {*mkxp_retro::fs, new_path.c_str(), write_path_prefix, truncate, exists}, .root = root};
// Check for errors opening the read handle and/or write handle
if (!handle->is_open() || (needs_write && writable && !handle->is_write_open())) {
PHYSFS_ErrorCode error = handle->get_read_error();
if (error == handle->get_read_error()) {
error = handle->get_write_error();
if (!handle->file.is_open() || (needs_write && writable && !handle->file.is_write_open())) {
PHYSFS_ErrorCode error = handle->file.get_read_error();
if (error == handle->file.get_read_error()) {
error = handle->file.get_write_error();
}
delete handle;
switch (error) {
@ -922,8 +1000,8 @@ extern "C" uint32_t w2c_wasi__snapshot__preview1_path_remove_directory(wasi_t *w
return WASI_ENOTDIR;
}
struct fs_dir *root = wasi->fdtable[fd].dir_handle()->root != nullptr ? wasi->fdtable[fd].dir_handle()->root : wasi->fdtable[fd].dir_handle();
if (!PHYSFS_delete(new_path.c_str() + root->path.length())) {
uint32_t root = wasi->fdtable[fd].type == wasi_fd_type::FS ? fd : wasi->fdtable[fd].dir_handle()->root;
if (!PHYSFS_delete(new_path.c_str() + wasi->fdtable[root].dir_handle()->path.length())) {
switch (PHYSFS_getLastErrorCode()) {
case PHYSFS_ERR_DIR_NOT_EMPTY:
return WASI_ENOTEMPTY;
@ -996,8 +1074,8 @@ extern "C" uint32_t w2c_wasi__snapshot__preview1_path_unlink_file(wasi_t *wasi,
return WASI_EIO;
}
struct fs_dir *root = wasi->fdtable[fd].dir_handle()->root != nullptr ? wasi->fdtable[fd].dir_handle()->root : wasi->fdtable[fd].dir_handle();
if (!PHYSFS_delete(new_path.c_str() + root->path.length())) {
uint32_t root = wasi->fdtable[fd].type == wasi_fd_type::FS ? fd : wasi->fdtable[fd].dir_handle()->root;
if (!PHYSFS_delete(new_path.c_str() + wasi->fdtable[root].dir_handle()->path.length())) {
switch (PHYSFS_getLastErrorCode()) {
case PHYSFS_ERR_READ_ONLY:
case PHYSFS_ERR_NO_WRITE_DIR:

View file

@ -160,18 +160,23 @@
typedef std::pair<u32, std::string> path_cache_entry_t;
struct fs_dir {
struct fs_dir *root; // Null if this is a preopened directory handle, otherwise a pointer to the handle of the preopened directory that contains this directory.
std::string path; // Path of the directory.
uint32_t root; // Undefined if this is a preopened directory, otherwise the file descriptor of the preopened directory that contains this directory.
bool writable; // If true, writes made to this directory handle will be routed into the save directory. Otherwise, writes are disallowed.
};
struct fs_file {
struct FileSystem::File file;
uint32_t root; // The file descriptor of the preopened directory that contains this file.
};
enum wasi_fd_type {
STDIN, // This file descriptor is standard input. The `handle` field is null.
STDOUT, // This file descriptor is standard output. The `handle` field is null.
STDERR, // This file descriptor is standard error. The `handle` field is null.
FS, // This file descriptor is a preopened directory handled by PhysFS. The `handle` field is a `struct fs_dir *`.
FSDIR, // This file descriptor is a directory handled by PhysFS. The `handle` field is a `struct fs_dir *`.
FSFILE, // This file descriptor is a file handled by PhysFS. The `handle` field is a `struct FileSystem::File *`.
FSFILE, // This file descriptor is a file handled by PhysFS. The `handle` field is a `struct fs_file *`.
VACANT, // Indicates this is a vacant file descriptor that doesn't correspond to a file. The `handle` field is null.
};
@ -182,7 +187,7 @@ struct wasi_file_entry {
void *handle;
struct fs_dir *dir_handle() const noexcept;
struct FileSystem::File *file_handle() const noexcept;
struct fs_file *file_handle() const noexcept;
};
typedef struct w2c_wasi__snapshot__preview1 {
@ -232,6 +237,8 @@ typedef struct w2c_wasi__snapshot__preview1 {
}
bool sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const;
bool sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size);
} wasi_t;
#endif /* MKXPZ_SANDBOX_WASI_H */

View file

@ -32,6 +32,7 @@
#include <alext.h>
#include <fluidsynth.h>
#include "binding-util.h"
#include "mkxp-polyfill.h" // std::mutex, std::strtoul
#include "git-hash.h"
@ -1567,11 +1568,18 @@ extern "C" RETRO_API size_t retro_serialize_size() {
max_size -= (bytes); \
} while (0)
#define OBJECTS_BEGIN_DETAIL(_r, _data, T) sandbox_ptr_map<T>::sandbox_serialize_begin();
#define OBJECTS_BEGIN do { BOOST_PP_SEQ_FOR_EACH(OBJECTS_BEGIN_DETAIL, _, SANDBOX_TYPENUM_TYPES) } while (0)
#define OBJECTS_END_DETAIL(_r, _data, T) sandbox_ptr_map<T>::sandbox_serialize_end();
#define OBJECTS_END do { BOOST_PP_SEQ_FOR_EACH(OBJECTS_END_DETAIL, _, SANDBOX_TYPENUM_TYPES) } while (0)
#define OBJECTS_END_FAIL do { OBJECTS_END; return false; } while (0)
#define SER_OBJECTS_BEGIN_DETAIL(_r, _data, T) sandbox_ptr_map<T>::sandbox_serialize_begin();
#define SER_OBJECTS_BEGIN do { BOOST_PP_SEQ_FOR_EACH(SER_OBJECTS_BEGIN_DETAIL, _, SANDBOX_TYPENUM_TYPES) } while (0)
#define SER_OBJECTS_END_DETAIL(_r, _data, T) sandbox_ptr_map<T>::sandbox_serialize_end();
#define SER_OBJECTS_END do { BOOST_PP_SEQ_FOR_EACH(SER_OBJECTS_END_DETAIL, _, SANDBOX_TYPENUM_TYPES) } while (0)
#define SER_OBJECTS_END_FAIL do { SER_OBJECTS_END; return false; } while (0)
#define DESER_FAIL do { deinit_sandbox(); return false; } while (0)
#define DESER_OBJECTS_BEGIN_DETAIL(_r, _data, T) sandbox_ptr_map<T>::sandbox_deserialize_begin();
#define DESER_OBJECTS_BEGIN do { BOOST_PP_SEQ_FOR_EACH(DESER_OBJECTS_BEGIN_DETAIL, _, SANDBOX_TYPENUM_TYPES) } while (0)
#define DESER_OBJECTS_END_DETAIL(_r, _data, T) sandbox_ptr_map<T>::sandbox_deserialize_end();
#define DESER_OBJECTS_END do { BOOST_PP_SEQ_FOR_EACH(DESER_OBJECTS_END_DETAIL, _, SANDBOX_TYPENUM_TYPES) } while (0)
#define DESER_OBJECTS_END_FAIL do { DESER_OBJECTS_END; sb()->objects.clear(); sb()->next_free_objkey = 0; DESER_FAIL; } while (0)
extern "C" RETRO_API bool retro_serialize(void *data, size_t len) {
wasm_size_t max_size = len;
@ -1646,49 +1654,48 @@ extern "C" RETRO_API bool retro_serialize(void *data, size_t len) {
if (!sb().sandbox_serialize_fdtable(data, max_size)) return false;
// Write the number of objects, then each object
OBJECTS_BEGIN;
if (!sandbox_serialize((wasm_size_t)sb()->get_objects().size(), data, max_size)) OBJECTS_END_FAIL;
SER_OBJECTS_BEGIN;
if (!sandbox_serialize((wasm_size_t)sb()->objects.size(), data, max_size)) SER_OBJECTS_END_FAIL;
wasm_size_t num_free_objects = 0;
for (const auto &object : sb()->get_objects()) {
for (const auto &object : sb()->objects) {
if (object.typenum == 0) {
++num_free_objects;
} else if (object.typenum > SANDBOX_NUM_TYPENUMS) {
std::abort();
} else {
if (num_free_objects > 0) {
if (!sandbox_serialize((wasm_size_t)0, data, max_size)) OBJECTS_END_FAIL;
if (!sandbox_serialize(num_free_objects, data, max_size)) OBJECTS_END_FAIL;
if (!sandbox_serialize((wasm_size_t)0, data, max_size)) SER_OBJECTS_END_FAIL;
if (!sandbox_serialize(num_free_objects, data, max_size)) SER_OBJECTS_END_FAIL;
num_free_objects = 0;
}
if (!sandbox_serialize(object.typenum, data, max_size)) OBJECTS_END_FAIL;
if (!typenum_table[object.typenum - 1].serialize(object.inner.ptr, data, max_size)) OBJECTS_END_FAIL;
if (!sandbox_serialize(object.typenum, data, max_size)) SER_OBJECTS_END_FAIL;
if (!typenum_table[object.typenum - 1].serialize(object.inner.ptr, data, max_size)) SER_OBJECTS_END_FAIL;
}
}
if (num_free_objects > 0) {
if (!sandbox_serialize((wasm_size_t)0, data, max_size)) OBJECTS_END_FAIL;
if (!sandbox_serialize(num_free_objects, data, max_size)) OBJECTS_END_FAIL;
if (!sandbox_serialize((wasm_size_t)0, data, max_size)) SER_OBJECTS_END_FAIL;
if (!sandbox_serialize(num_free_objects, data, max_size)) SER_OBJECTS_END_FAIL;
num_free_objects = 0;
}
// Write the number of extra objects that were found during serialization of the normal objects, then each such object
if (max_size < sizeof(wasm_size_t)) OBJECTS_END_FAIL;
if (max_size < sizeof(wasm_size_t)) SER_OBJECTS_END_FAIL;
wasm_size_t *num_extra_objects_ptr = (wasm_size_t *)data;
ADVANCE(sizeof(wasm_size_t));
for (size_t i = 0; i < extra_objects.size(); ++i) { // More items can be added to this vector during iteration
const void *ptr = std::get<0>(extra_objects[i]);
wasm_size_t typenum = std::get<1>(extra_objects[i]);
if (typenum == 0) {
std::abort();
} else if (typenum > SANDBOX_NUM_TYPENUMS) {
if (typenum != get_typenum<Color>::value && typenum != get_typenum<Tone>::value && typenum != get_typenum<Rect>::value) {
std::fprintf(stderr, "extra object other than Color, Tone or Rect found during save state serialization with typenum %llu (there's probably a bug in the sandbox bindings)\n", (unsigned long long)typenum);
std::abort();
} else {
if (!sandbox_serialize(typenum, data, max_size)) OBJECTS_END_FAIL;
if (!typenum_table[typenum - 1].serialize(ptr, data, max_size)) OBJECTS_END_FAIL;
if (!sandbox_serialize(typenum, data, max_size)) SER_OBJECTS_END_FAIL;
if (!typenum_table[typenum - 1].serialize(ptr, data, max_size)) SER_OBJECTS_END_FAIL;
}
}
*num_extra_objects_ptr = (wasm_size_t)extra_objects.size();
OBJECTS_END;
SER_OBJECTS_END;
std::memset(data, 0, max_size);
return true;
}
@ -1727,37 +1734,37 @@ extern "C" RETRO_API bool retro_unserialize(const void *data, size_t len) {
// Read the sandbox state
{
wasm_ptr_t value;
if (!sandbox_deserialize(value, data, max_size)) return false;
if (!sandbox_deserialize(value, data, max_size)) DESER_FAIL;
sb()->set_machine_stack_pointer(value);
}
{
uint8_t value;
if (!sandbox_deserialize(value, data, max_size)) return false;
if (!sandbox_deserialize(value, data, max_size)) DESER_FAIL;
sb()->set_asyncify_state(value);
}
{
wasm_ptr_t value;
if (!sandbox_deserialize(value, data, max_size)) return false;
if (!sandbox_deserialize(value, data, max_size)) DESER_FAIL;
sb()->set_asyncify_data(value);
}
if (!sandbox_deserialize(frame_count, data, max_size)) return false;
if (!sandbox_deserialize(frame_count, data, max_size)) DESER_FAIL;
{
uint64_t value;
if (!sandbox_deserialize(value, data, max_size)) return false;
if (!sandbox_deserialize(value, data, max_size)) DESER_FAIL;
frame_time = value;
}
if (!sandbox_deserialize(frame_time_remainder, data, max_size)) return false;
if (!sandbox_deserialize(retro_run_count, data, max_size)) return false;
if (!sandbox_deserialize(sb().transitioning, data, max_size)) return false;
if (!sandbox_deserialize(frame_time_remainder, data, max_size)) DESER_FAIL;
if (!sandbox_deserialize(retro_run_count, data, max_size)) DESER_FAIL;
if (!sandbox_deserialize(sb().transitioning, data, max_size)) DESER_FAIL;
{
bool have_trans_map;
if (!sandbox_deserialize(have_trans_map, data, max_size)) return false;
if (!sandbox_deserialize(have_trans_map, data, max_size)) DESER_FAIL;
if (have_trans_map) {
if (sb().trans_map == nullptr) {
// TODO
return false;
DESER_FAIL;
}
if (!sandbox_deserialize(*sb().trans_map, data, max_size)) return false;
if (!sandbox_deserialize(*sb().trans_map, data, max_size)) DESER_FAIL;
} else {
if (sb().trans_map != nullptr) {
delete sb().trans_map;
@ -1768,14 +1775,14 @@ extern "C" RETRO_API bool retro_unserialize(const void *data, size_t len) {
{
// TODO: movie
bool have_movie;
if (!sandbox_deserialize(have_movie, data, max_size)) return false;
if (have_movie) return false;
if (!sandbox_deserialize(have_movie, data, max_size)) DESER_FAIL;
if (have_movie) DESER_FAIL;
}
{
// Read sandbox fibers
wasm_size_t num_fibers;
if (!sandbox_deserialize(num_fibers, data, max_size)) return false;
if (!sandbox_deserialize(num_fibers, data, max_size)) DESER_FAIL;
sb()->fibers.clear();
sb()->fibers.reserve(num_fibers);
@ -1783,25 +1790,25 @@ extern "C" RETRO_API bool retro_unserialize(const void *data, size_t len) {
while (num_fibers > 0) {
// Read the key of the fiber
std::tuple<wasm_size_t, wasm_size_t, wasm_size_t> key;
if (!sandbox_deserialize(std::get<0>(key), data, max_size)) return false;
if (!sandbox_deserialize(std::get<1>(key), data, max_size)) return false;
if (!sandbox_deserialize(std::get<2>(key), data, max_size)) return false;
if (!sandbox_deserialize(std::get<0>(key), data, max_size)) DESER_FAIL;
if (!sandbox_deserialize(std::get<1>(key), data, max_size)) DESER_FAIL;
if (!sandbox_deserialize(std::get<2>(key), data, max_size)) DESER_FAIL;
// Construct the fiber
auto &fiber = sb()->fibers.emplace(key, key).first->second;
// Read the stack index of the fiber
if (!sandbox_deserialize(fiber.stack_index, data, max_size)) return false;
if (!sandbox_deserialize(fiber.stack_index, data, max_size)) DESER_FAIL;
// Read sandbox frames
wasm_size_t num_frames;
if (!sandbox_deserialize(num_frames, data, max_size)) return false;
if (!sandbox_deserialize(num_frames, data, max_size)) DESER_FAIL;
fiber.deser_stack.reserve(num_frames);
while (num_frames > 0) {
wasm_ptr_t stack_pointer;
if (!sandbox_deserialize(stack_pointer, data, max_size)) return false;
if (!sandbox_deserialize(stack_pointer, data, max_size)) DESER_FAIL;
int32_t state;
if (!sandbox_deserialize(state, data, max_size)) return false;
if (!sandbox_deserialize(state, data, max_size)) DESER_FAIL;
fiber.deser_stack.emplace_back(stack_pointer, state);
--num_frames;
}
@ -1810,6 +1817,85 @@ extern "C" RETRO_API bool retro_unserialize(const void *data, size_t len) {
}
}
// Read the open WASI file descriptors
if (!sb().sandbox_deserialize_fdtable(data, max_size)) DESER_FAIL;
// Read objects
DESER_OBJECTS_BEGIN;
sb()->next_free_objkey = 0;
wasm_objkey_t object_key = 1;
wasm_size_t num_objects;
if (!sandbox_deserialize(num_objects, data, max_size)) DESER_OBJECTS_END_FAIL;
sb()->objects.resize(num_objects);
while (object_key <= num_objects) {
wasm_size_t typenum;
if (!sandbox_deserialize(typenum, data, max_size)) DESER_OBJECTS_END_FAIL;
if (typenum == 0) {
wasm_size_t num_free_objects;
if (!::sandbox_deserialize(num_free_objects, data, max_size)) DESER_OBJECTS_END_FAIL;
if (object_key - 1 + num_free_objects > num_objects || object_key + num_free_objects < object_key) DESER_OBJECTS_END_FAIL;
for (wasm_size_t i = object_key; i < object_key + num_free_objects; ++i) {
auto &object = sb()->objects[i - 1];
if (object.typenum > 0) {
if (object.typenum > SANDBOX_NUM_TYPENUMS) {
std::abort();
}
typenum_table[object.typenum - 1].destructor(object.inner.ptr);
object.typenum = 0;
}
object.inner.next = sb()->next_free_objkey;
sb()->next_free_objkey = i;
}
object_key += num_free_objects;
} else {
if (typenum > SANDBOX_NUM_TYPENUMS) DESER_OBJECTS_END_FAIL;
auto &object = sb()->objects[object_key - 1];
if (object.typenum > 0 && object.typenum != typenum) {
typenum_table[object.typenum - 1].destructor(object.inner.ptr);
}
if (object.typenum != typenum) {
object.typenum = typenum;
object.inner.ptr = typenum_table[typenum - 1].constructor();
if (object.inner.ptr == nullptr && typenum != get_typenum<Tilemap::Autotiles>::value && typenum != get_typenum<TilemapVX::BitmapArray>::value) DESER_OBJECTS_END_FAIL;
}
if (!typenum_table[typenum - 1].deserialize(object.inner.ptr, data, max_size)) DESER_OBJECTS_END_FAIL;
auto it = objects_deser.find(object_key);
if (it == objects_deser.end()) {
objects_deser.emplace(object_key, sandbox_object_deser_info(object.inner.ptr, typenum));
} else {
it->second.set_ptr(object.inner.ptr, typenum);
}
++object_key;
}
}
// Read extra objects
wasm_objkey_t extra_object_key = 1;
wasm_size_t num_extra_objects;
if (!sandbox_deserialize(num_extra_objects, data, max_size)) DESER_OBJECTS_END_FAIL;
while (extra_object_key <= num_extra_objects) {
wasm_size_t typenum;
if (!sandbox_deserialize(typenum, data, max_size)) DESER_OBJECTS_END_FAIL;
if (typenum != get_typenum<Color>::value && typenum != get_typenum<Tone>::value && typenum != get_typenum<Rect>::value) DESER_OBJECTS_END_FAIL;
void *ptr = typenum_table[typenum - 1].constructor();
if (ptr == nullptr && typenum != get_typenum<Tilemap::Autotiles>::value && typenum != get_typenum<TilemapVX::BitmapArray>::value) DESER_OBJECTS_END_FAIL;
if (!typenum_table[typenum - 1].deserialize(ptr, data, max_size)) {
typenum_table[typenum - 1].destructor(ptr);
DESER_OBJECTS_END_FAIL;
}
auto it = extra_objects_deser.find(extra_object_key);
if (it == extra_objects_deser.end()) {
extra_objects_deser.emplace(extra_object_key, sandbox_object_deser_info(ptr, typenum));
} else {
if (!it->second.set_ptr(ptr, typenum)) {
typenum_table[typenum - 1].destructor(ptr);
DESER_OBJECTS_END_FAIL;
}
}
++extra_object_key;
}
DESER_OBJECTS_END;
return true;
}

View file

@ -56,7 +56,7 @@ class Bitmap : public Disposable
public:
Bitmap(Exception &exception, const char *filename);
Bitmap(Exception &exception, int width, int height, bool isHires = false);
Bitmap(Exception &exception, int width = 1, int height = 1, bool isHires = false);
Bitmap(Exception &exception, void *pixeldata, int width, int height);
Bitmap(Exception &exception, TEXFBO &other);
Bitmap(Exception &exception, SDL_Surface *imgSurf, SDL_Surface *imgSurfHires, bool forceMega = false);

View file

@ -693,15 +693,42 @@ Font::getSdlFont(Exception &exception)
#ifdef MKXPZ_RETRO
bool Font::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const
{
if (!mkxp_sandbox::sandbox_serialize((int32_t)p->size, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->bold, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->italic, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->outline, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->shadow, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->name, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->color, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->outColor, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize((int32_t)p->size, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->name, data, max_size)) return false;
return true;
}
bool Font::sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size)
{
if (!mkxp_sandbox::sandbox_deserialize(p->bold, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->italic, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->outline, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->shadow, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->color, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->outColor, data, max_size)) return false;
// Invalidate the inner font object if either the name or size of this font is different from before
if (p->sdlFont != nullptr) {
int32_t size = p->size;
if (!mkxp_sandbox::sandbox_deserialize((int32_t &)p->size, data, max_size)) return false;
std::string name(p->name);
if (!mkxp_sandbox::sandbox_deserialize(p->name, data, max_size)) return false;
if (p->size != size || p->name != name) {
p->sdlFont = nullptr;
}
} else {
if (!mkxp_sandbox::sandbox_deserialize((int32_t &)p->size, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->name, data, max_size)) return false;
}
return true;
}
#endif // MKXPZ_RETRO

View file

@ -151,6 +151,7 @@ public:
#ifdef MKXPZ_RETRO
bool sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const;
bool sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size);
#endif // MKXPZ_RETRO
private:

View file

@ -211,10 +211,19 @@ void SceneElement::unlink()
#ifdef MKXPZ_RETRO
bool SceneElement::sandbox_serialize_scene_element(void *&data, mkxp_sandbox::wasm_size_t &max_size) const
{
if (!mkxp_sandbox::sandbox_serialize((uint64_t)creationStamp, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(creationStamp, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize((int32_t)z, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(visible, data, max_size)) return false;
return true;
}
bool SceneElement::sandbox_deserialize_scene_element(const void *&data, mkxp_sandbox::wasm_size_t &max_size)
{
if (!mkxp_sandbox::sandbox_deserialize(creationStamp, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize((int32_t &)z, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(visible, data, max_size)) return false;
return true;
}
#endif // MKXPZ_REROO

View file

@ -97,6 +97,7 @@ public:
#ifdef MKXPZ_RETRO
bool sandbox_serialize_scene_element(void *&data, mkxp_sandbox::wasm_size_t &max_size) const;
bool sandbox_deserialize_scene_element(const void *&data, mkxp_sandbox::wasm_size_t &max_size);
#endif // MKXPZ_REROO
protected:
@ -131,7 +132,7 @@ protected:
void unlink();
IntruListLink<SceneElement> link;
const unsigned int creationStamp;
uint64_t creationStamp;
int z;
bool visible;
Scene *scene;

View file

@ -372,4 +372,33 @@ bool Plane::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size)
return true;
}
bool Plane::sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size)
{
{
bool active;
if (!mkxp_sandbox::sandbox_deserialize(active, data, max_size)) return false;
if (!active) {
dispose();
return true;
}
// TODO: undispose
}
if (!mkxp_sandbox::sandbox_deserialize(p->opacity, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->blendType, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize((int32_t &)p->ox, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize((int32_t &)p->oy, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->zoomX, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->zoomY, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->sceneGeo, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->quadSourceDirty, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->qArray, data, max_size)) return false;
if (!sandbox_deserialize_viewport_element(data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->bitmap, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->color, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->tone, data, max_size)) return false;
return true;
}
#endif // MKXPZ_RETRO

View file

@ -55,6 +55,7 @@ public:
#ifdef MKXPZ_RETRO
bool sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const;
bool sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size);
#endif // MKXPZ_RETRO
private:

View file

@ -896,4 +896,51 @@ bool Sprite::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size)
return true;
}
bool Sprite::sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size)
{
{
bool active;
if (!mkxp_sandbox::sandbox_deserialize(active, data, max_size)) return false;
if (!active) {
dispose();
return true;
}
// TODO: undispose
}
if (!mkxp_sandbox::sandbox_deserialize(p->quad, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->trans, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->mirrored, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize((int32_t &)p->bushDepth, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->efBushDepth, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->bushOpacity, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->opacity, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->blendType, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->patternBlendType, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->patternTile, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->patternOpacity, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->patternScroll, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->patternZoom, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->invert, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->sceneRect, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->sceneOrig, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->isVisible, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize((int32_t &)p->wave.amp, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize((int32_t &)p->wave.length, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize((int32_t &)p->wave.speed, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->wave.phase, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->wave.qArray, data, max_size)) return false;
if (!sandbox_deserialize_viewport_element(data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->bitmap, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->pattern, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->srcRect, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->color, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->tone, data, max_size)) return false;
return true;
}
#endif // MKXPZ_RETRO

View file

@ -84,6 +84,7 @@ public:
#ifdef MKXPZ_RETRO
bool sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const;
bool sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size);
#endif // MKXPZ_RETRO
private:

View file

@ -136,6 +136,11 @@ struct FlashMap
return data;
}
Table *&getData()
{
return data;
}
void setData(Table *value)
{
if (data == value)

View file

@ -1463,6 +1463,11 @@ bool Tilemap::Autotiles::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_
return true;
}
bool Tilemap::Autotiles::sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size)
{
return true;
}
bool Tilemap::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const
{
if (isDisposed()) return mkxp_sandbox::sandbox_serialize(false, data, max_size);
@ -1515,4 +1520,64 @@ bool Tilemap::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size
return true;
}
bool Tilemap::sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size)
{
{
bool active;
if (!mkxp_sandbox::sandbox_deserialize(active, data, max_size)) return false;
if (!active) {
dispose();
return true;
}
// TODO: undispose
}
if (!mkxp_sandbox::sandbox_deserialize(p->visible, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->origin, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->dispPos, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->atlas.size, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize((int32_t &)p->atlas.efTilesetH, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->atlas.usableATs, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->atlas.animatedATs, data, max_size)) return false;
for (size_t i = 0; i < autotileCount; ++i)
if (!mkxp_sandbox::sandbox_deserialize(p->atlas.smallATs[i], data, max_size)) return false;
for (size_t i = 0; i < autotileCount; ++i)
if (!mkxp_sandbox::sandbox_deserialize((int32_t &)p->atlas.nATFrames[i], data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->viewpPos, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->groundVert, data, max_size)) return false;
for (size_t i = 0; i < zlayersMax; ++i)
if (!mkxp_sandbox::sandbox_deserialize(p->zlayerVert[i], data, max_size)) return false;
for (size_t i = 0; i < zlayersMax + 1; ++i)
if (!mkxp_sandbox::sandbox_deserialize((mkxp_sandbox::wasm_size_t &)p->zlayerBases[i], data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->tiles.animated, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->tiles.aniIdx, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->flashAlphaIdx, data, max_size)) return false;
if (!p->elem.ground->sandbox_deserialize_viewport_element(data, max_size)) return false;
for (size_t i = 0; i < zlayersMax; ++i)
if (!p->elem.zlayers[i]->sandbox_deserialize_viewport_element(data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize((mkxp_sandbox::wasm_size_t &)p->elem.activeLayers, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->elem.sceneGeo, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->opacity, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->blendType, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->viewport, data, max_size)) return false;
for (size_t i = 0; i < autotileCount; ++i)
if (!mkxp_sandbox::sandbox_deserialize(p->autotiles[i], data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->tileset, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->mapData, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->priorities, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->flashMap.getData(), data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->color, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->tone, data, max_size)) return false;
return true;
}
#endif // MKXPZ_RETRO

View file

@ -50,6 +50,7 @@ public:
#ifdef MKXPZ_RETRO
bool sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const;
bool sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size);
#endif // MKXPZ_RETRO
private:
@ -86,6 +87,7 @@ public:
#ifdef MKXPZ_RETRO
bool sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const;
bool sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size);
#endif // MKXPZ_RETRO
private:

View file

@ -621,6 +621,11 @@ bool TilemapVX::BitmapArray::sandbox_serialize(void *&data, mkxp_sandbox::wasm_s
return true;
}
bool TilemapVX::BitmapArray::sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size)
{
return true;
}
bool TilemapVX::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const
{
if (isDisposed()) return mkxp_sandbox::sandbox_serialize(false, data, max_size);
@ -645,4 +650,36 @@ bool TilemapVX::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_si
return true;
}
bool TilemapVX::sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size)
{
{
bool active;
if (!mkxp_sandbox::sandbox_deserialize(active, data, max_size)) return false;
if (!active) {
dispose();
return true;
}
// TODO: undispose
}
if (!mkxp_sandbox::sandbox_deserialize(p->origin, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->dispPos, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->groundVert, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->aboveVert, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize((mkxp_sandbox::wasm_size_t &)p->allocQuads, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize((mkxp_sandbox::wasm_size_t &)p->groundQuads, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize((mkxp_sandbox::wasm_size_t &)p->aboveQuads, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->frameIdx, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->aniOffset, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->flashAlphaIdx, data, max_size)) return false;
if (!p->above.sandbox_deserialize_viewport_element(data, max_size)) return false;
if (!p->sandbox_deserialize_viewport_element(data, max_size)) return false;
for (size_t i = 0; i < BM_COUNT; ++i)
if (!mkxp_sandbox::sandbox_deserialize(p->bitmaps[i], data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->mapData, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->flashMap.getData(), data, max_size)) return false;
return true;
}
#endif // MKXPZ_RETRO

View file

@ -46,6 +46,7 @@ public:
#ifdef MKXPZ_RETRO
bool sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const;
bool sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size);
#endif // MKXPZ_RETRO
private:
@ -74,6 +75,7 @@ public:
#ifdef MKXPZ_RETRO
bool sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const;
bool sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size);
#endif // MKXPZ_RETRO
private:

View file

@ -244,6 +244,28 @@ bool Viewport::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_siz
return true;
}
bool Viewport::sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size)
{
{
bool active;
if (!mkxp_sandbox::sandbox_deserialize(active, data, max_size)) return false;
if (!active) {
dispose();
return true;
}
// TODO: undispose
}
if (!mkxp_sandbox::sandbox_deserialize(p->screenRect, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->isOnScreen, data, max_size)) return false;
if (!sandbox_deserialize_scene_element(data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->rect, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->color, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->tone, data, max_size)) return false;
return true;
}
#endif // MXKPZ_RETRO
@ -293,4 +315,12 @@ bool ViewportElement::sandbox_serialize_viewport_element(void *&data, mkxp_sandb
return true;
}
bool ViewportElement::sandbox_deserialize_viewport_element(const void *&data, mkxp_sandbox::wasm_size_t &max_size)
{
if (!sandbox_deserialize_scene_element(data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(m_viewport, data, max_size)) return false;
return true;
}
#endif // MXKPZ_RETRO

View file

@ -53,6 +53,7 @@ public:
#ifdef MKXPZ_RETRO
bool sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const;
bool sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size);
#endif // MXKPZ_RETRO
private:
@ -85,6 +86,7 @@ public:
#ifdef MKXPZ_RETRO
bool sandbox_serialize_viewport_element(void *&data, mkxp_sandbox::wasm_size_t &max_size) const;
bool sandbox_deserialize_viewport_element(const void *&data, mkxp_sandbox::wasm_size_t &max_size);
#endif // MXKPZ_RETRO
protected:

View file

@ -982,4 +982,43 @@ bool Window::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size)
return true;
}
bool Window::sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size)
{
{
bool active;
if (!mkxp_sandbox::sandbox_deserialize(active, data, max_size)) return false;
if (!active) {
dispose();
return true;
}
// TODO: undispose
}
if (!mkxp_sandbox::sandbox_deserialize(p->bgStretch, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->active, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->pause, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->sceneOffset, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->position, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->size, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->contentsOffset, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->opacity, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->backOpacity, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->contentsOpacity, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->baseQuadArray, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->useBaseTex, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->baseTexQuad, data, max_size)) return false;
if (!p->controlsElement.sandbox_deserialize_viewport_element(data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->controlsQuadArray, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->contentsQuad, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->cursorAniAlphaIdx, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->pauseAniAlphaIdx, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->pauseAniQuadIdx, data, max_size)) return false;
if (!sandbox_deserialize_viewport_element(data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->windowskin, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->contents, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->cursorRect, data, max_size)) return false;
return true;
}
#endif // MKXPZ_RETRO

View file

@ -67,6 +67,7 @@ public:
#ifdef MKXPZ_RETRO
bool sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const;
bool sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size);
#endif // MKXPZ_RETRO
private:

View file

@ -1183,11 +1183,6 @@ bool WindowVX::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_siz
if (!mkxp_sandbox::sandbox_serialize(p->contentsOpacity, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->openness, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->ctrlVert, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->pauseVert != nullptr, data, max_size)) return false;
if (p->pauseVert != nullptr)
if (!mkxp_sandbox::sandbox_serialize(*p->pauseVert, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->contentsQuad, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->padRect, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->clipRect, data, max_size)) return false;
@ -1204,4 +1199,47 @@ bool WindowVX::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_siz
return true;
}
bool WindowVX::sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size)
{
{
bool active;
if (!mkxp_sandbox::sandbox_deserialize(active, data, max_size)) return false;
if (!active) {
dispose();
return true;
}
// TODO: undispose
}
if (!mkxp_sandbox::sandbox_deserialize(p->active, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->arrowsVisible, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->pause, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize((int32_t &)p->width, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize((int32_t &)p->height, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->geo, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->contentsOff, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize((int32_t &)p->padding, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize((int32_t &)p->paddingBottom, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->opacity, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->backOpacity, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->contentsOpacity, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->openness, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->ctrlVert, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->contentsQuad, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->padRect, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->clipRect, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->cursorVert, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->pauseAlphaIdx, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->pauseQuadIdx, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->cursorAlphaIdx, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->sceneOffset, data, max_size)) return false;
if (!sandbox_deserialize_viewport_element(data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->windowskin, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->contents, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->cursorRect, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->tone, data, max_size)) return false;
return true;
}
#endif // MKXPZ_RETRO

View file

@ -74,6 +74,7 @@ public:
#ifdef MKXPZ_RETRO
bool sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const;
bool sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size);
#endif // MKXPZ_RETRO
private:

View file

@ -191,6 +191,15 @@ bool Color::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size)
return true;
}
bool Color::sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size) {
if (!mkxp_sandbox::sandbox_deserialize(red, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(green, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(blue, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(alpha, data, max_size)) return false;
return true;
}
#endif // MKXPZ_RETRO
@ -320,6 +329,15 @@ bool Tone::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) c
return true;
}
bool Tone::sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size) {
if (!mkxp_sandbox::sandbox_deserialize(red, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(green, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(blue, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(gray, data, max_size)) return false;
return true;
}
#endif // MKXPZ_RETRO
@ -472,4 +490,13 @@ bool Rect::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) c
return true;
}
bool Rect::sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size) {
if (!mkxp_sandbox::sandbox_deserialize((int32_t &)x, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize((int32_t &)y, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize((int32_t &)width, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize((int32_t &)height, data, max_size)) return false;
return true;
}
#endif // MKXPZ_RETRO

View file

@ -94,6 +94,7 @@ struct Color : public Serializable
#ifdef MKXPZ_RETRO
bool sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const;
bool sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size);
#endif // MKXPZ_RETRO
/* Range (0.0 ~ 255.0) */
@ -150,6 +151,7 @@ struct Tone : public Serializable
#ifdef MKXPZ_RETRO
bool sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const;
bool sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size);
#endif // MKXPZ_RETRO
/* Range (-255.0 ~ 255.0) */
@ -213,6 +215,7 @@ struct Rect : public Serializable
#ifdef MKXPZ_RETRO
bool sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const;
bool sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size);
#endif // MKXPZ_RETRO
int x;

View file

@ -172,11 +172,25 @@ bool Table::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size)
if (!mkxp_sandbox::sandbox_serialize((int32_t)xs, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize((int32_t)ys, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize((int32_t)zs, data, max_size)) return false;
if (xs * ys * zs != this->data.size()) std::abort();
if ((uint32_t)xs * (uint32_t)ys * (uint32_t)zs != this->data.size()) std::abort();
if (max_size < this->data.size() * sizeof(int16_t)) return false;
memcpy(data, this->data.data(), this->data.size() * sizeof(int16_t));
data = (uint8_t *)data + this->data.size() * sizeof(int16_t);
max_size -= this->data.size() * sizeof(int16_t);
return true;
}
bool Table::sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size)
{
if (!mkxp_sandbox::sandbox_deserialize((int32_t &)xs, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize((int32_t &)ys, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize((int32_t &)zs, data, max_size)) return false;
this->data.clear();
this->data.resize((uint32_t)xs * (uint32_t)ys * (uint32_t)zs);
if (max_size < this->data.size() * sizeof(int16_t)) return false;
memcpy(this->data.data(), data, this->data.size() * sizeof(int16_t));
data = (uint8_t *)data + this->data.size() * sizeof(int16_t);
max_size -= this->data.size() * sizeof(int16_t);
return true;
}
#endif // MKXPZ_RETRO

View file

@ -35,7 +35,7 @@
class Table : public Serializable
{
public:
Table(int x, int y = 1, int z = 1);
Table(int x = 1, int y = 1, int z = 1);
/* Clone constructor */
Table(const Table &other);
virtual ~Table() {}
@ -70,6 +70,7 @@ public:
#ifdef MKXPZ_RETRO
bool sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const;
bool sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size);
#endif // MKXPZ_RETRO
private:

View file

@ -107,7 +107,7 @@ struct SharedStatePrivate
Quad gpQuad;
unsigned int stampCounter;
uint64_t stampCounter;
std::chrono::time_point<std::chrono::steady_clock> startupTime;
@ -435,7 +435,7 @@ double SharedState::runTime() {
#endif // MKXPZ_RETRO
}
unsigned int SharedState::genTimeStamp()
uint64_t SharedState::genTimeStamp()
{
return p->stampCounter++;
}

View file

@ -84,7 +84,7 @@ struct SharedState
sigslot::signal<> prepareDraw;
unsigned int genTimeStamp();
uint64_t genTimeStamp();
// Returns time since SharedState was constructed in microseconds
double runTime();