Handle disposal when deserializing save states in libretro builds

This commit is contained in:
刘皓 2025-05-28 15:32:43 -04:00
parent 1f5d90822c
commit 6f472fb732
No known key found for this signature in database
GPG key ID: 7901753DB465B711
22 changed files with 250 additions and 129 deletions

View file

@ -237,7 +237,7 @@ binding_base::object::~object() {
if (typenum > typenum_table_size) {
std::abort();
}
typenum_table[typenum - 1].destructor(inner.ptr);
typenum_table[typenum - 1].destroy(inner.ptr);
}
}
@ -292,7 +292,7 @@ void binding_base::destroy_object(wasm_objkey_t key) {
if (object.typenum == 0 || object.typenum > typenum_table_size) {
std::abort();
}
typenum_table[object.typenum - 1].destructor(object.inner.ptr);
typenum_table[object.typenum - 1].destroy(object.inner.ptr);
object.typenum = 0;
object.inner.next = next_free_objkey;
next_free_objkey = key;

View file

@ -199,10 +199,14 @@ namespace mkxp_sandbox {
}
struct typenum_table_entry {
void *(*constructor)();
void (*destructor)(void *self);
void *(*construct)();
void (*destroy)(void *self);
void (*destroy_without_signal)(void *self);
void (*dispose_without_signal)(void *self);
bool (*disposed)(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);
void (*deserialize_end)(void *self);
};
extern const struct typenum_table_entry typenum_table[];

View file

@ -21,14 +21,15 @@
#include "binding-util.h"
#include "sharedstate.h"
#include <boost/type_traits/is_detected.hpp>
using namespace mkxp_sandbox;
template <typename T> static typename std::enable_if<std::is_constructible<T>::value, void *>::type constructor() {
template <typename T> static typename std::enable_if<std::is_constructible<T>::value, void *>::type construct() {
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() {
template <typename T> static typename std::enable_if<!std::is_constructible<T>::value && std::is_constructible<T, Exception &>::value, void *>::type construct() {
Exception e;
T *obj = new T(e);
if (e.is_ok()) {
@ -39,12 +40,40 @@ template <typename T> static typename std::enable_if<!std::is_constructible<T>::
}
}
template <typename T> static void destructor(void *self) {
template <typename T> static void destroy(void *self) {
if (self != nullptr) {
delete (T *)self;
}
}
template <typename T> static typename std::enable_if<std::is_base_of<Disposable, T>::value>::type destroy_without_signal(void *self) {
if (self != nullptr) {
((T *)self)->wasDisposed.disconnect_all();
delete (T *)self;
}
}
template <typename T> static typename std::enable_if<!std::is_base_of<Disposable, T>::value>::type destroy_without_signal(void *self) {
destroy<T>(self);
}
template <typename T> static typename std::enable_if<std::is_base_of<Disposable, T>::value>::type dispose_without_signal(void *self) {
if (self != nullptr) {
((T *)self)->wasDisposed.disconnect_all();
((T *)self)->dispose();
}
}
template <typename T> static typename std::enable_if<!std::is_base_of<Disposable, T>::value>::type dispose_without_signal(void *self) {}
template <typename T> static typename std::enable_if<std::is_base_of<Disposable, T>::value, bool>::type disposed(void *self) {
return self == nullptr || ((T *)self)->isDisposed();
}
template <typename T> static typename std::enable_if<!std::is_base_of<Disposable, T>::value, bool>::type disposed(void *self) {
return self == nullptr;
}
template <typename T> static bool serialize(const void *self, void *&data, wasm_size_t &max_size) {
return ((const T *)self)->sandbox_serialize(data, max_size);
}
@ -53,7 +82,15 @@ template <typename T> static bool deserialize(void *self, const void *&data, was
return ((T *)self)->sandbox_deserialize(data, max_size);
}
#define _SANDBOX_DEF_TYPENUM_TABLE_ENTRY(_r, _data, T) {constructor<T>, destructor<T>, serialize<T>, deserialize<T>},
template <typename T> using deserialize_end_declaration = decltype(std::declval<T *>()->sandbox_deserialize_end());
template <typename T> static typename std::enable_if<boost::is_detected<deserialize_end_declaration, T>::value>::type deserialize_end(void *self) {
((T *)self)->sandbox_deserialize_end();
}
template <typename T> static typename std::enable_if<!boost::is_detected<deserialize_end_declaration, T>::value>::type deserialize_end(void *self) {}
#define _SANDBOX_DEF_TYPENUM_TABLE_ENTRY(_r, _data, T) {construct<T>, destroy<T>, destroy_without_signal<T>, dispose_without_signal<T>, disposed<T>, serialize<T>, deserialize<T>, deserialize_end<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

@ -84,11 +84,11 @@ bool sandbox_object_deser_info::set_ptr(void *ptr, wasm_size_t typenum) {
return true;
}
void *sandbox_object_deser_info::get_ptr() {
void *sandbox_object_deser_info::get_ptr() const {
return exists ? ptr : nullptr;
}
wasm_size_t sandbox_object_deser_info::get_typenum() {
wasm_size_t sandbox_object_deser_info::get_typenum() const {
return typenum;
}

View file

@ -58,8 +58,8 @@ namespace mkxp_sandbox {
return true;
}
bool set_ptr(void *ptr, wasm_size_t typenum);
void *get_ptr();
wasm_size_t get_typenum();
void *get_ptr() const;
wasm_size_t get_typenum() const;
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.
@ -76,8 +76,8 @@ namespace mkxp_sandbox {
extern std::unordered_map<wasm_size_t, struct sandbox_object_deser_info> objects_deser;
extern std::unordered_map<wasm_size_t, struct sandbox_object_deser_info> extra_objects_deser;
template <typename T> using sandbox_serialize_member_declaration = decltype(std::declval<const T &>().sandbox_serialize(std::declval<void *&>(), std::declval<wasm_size_t &>()));
template <typename T> using sandbox_deserialize_member_declaration = decltype(std::declval<T &>().sandbox_deserialize(std::declval<const void *&>(), std::declval<wasm_size_t &>()));
template <typename T> using sandbox_serialize_member_declaration = decltype(std::declval<const T *>()->sandbox_serialize(std::declval<void *&>(), std::declval<wasm_size_t &>()));
template <typename T> using sandbox_deserialize_member_declaration = decltype(std::declval<T *>()->sandbox_deserialize(std::declval<const void *&>(), std::declval<wasm_size_t &>()));
template <typename T> typename std::enable_if<std::is_same<T, bool>::value, bool>::type sandbox_serialize(T value, void *&data, wasm_size_t &max_size);
template <typename T> typename std::enable_if<std::is_enum<T>::value, bool>::type sandbox_serialize(T value, void *&data, wasm_size_t &max_size);
@ -228,7 +228,7 @@ namespace mkxp_sandbox {
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());
typenum_table[info.get_typenum() - 1].destroy(info.get_ptr());
}
}

View file

@ -1669,7 +1669,11 @@ extern "C" RETRO_API bool retro_serialize(void *data, size_t len) {
num_free_objects = 0;
}
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;
bool disposed = typenum_table[object.typenum - 1].disposed(object.inner.ptr);
if (!sandbox_serialize(disposed, data, max_size)) SER_OBJECTS_END_FAIL;
if (!disposed) {
if (!typenum_table[object.typenum - 1].serialize(object.inner.ptr, data, max_size)) SER_OBJECTS_END_FAIL;
}
}
}
if (num_free_objects > 0) {
@ -1835,31 +1839,50 @@ extern "C" RETRO_API bool retro_unserialize(const void *data, size_t len) {
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;
// Destroy objects that currently exist but don't exist in the save state
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);
typenum_table[object.typenum - 1].destroy_without_signal(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;
bool should_be_disposed;
if (!sandbox_deserialize(should_be_disposed, data, max_size)) return false;
// Destroy and recreate objects that don't match the type in the save state, or are currently disposed but not disposed in the save state
auto &object = sb()->objects[object_key - 1];
if (object.typenum > 0 && object.typenum != typenum) {
typenum_table[object.typenum - 1].destructor(object.inner.ptr);
bool currently_disposed = object.typenum == 0 || typenum_table[object.typenum - 1].disposed(object.inner.ptr);
bool should_create = object.typenum != typenum || (currently_disposed && !should_be_disposed);
bool should_destroy = should_create && object.typenum > 0;
if (should_destroy) {
typenum_table[object.typenum - 1].destroy_without_signal(object.inner.ptr);
}
if (object.typenum != typenum) {
if (should_create) {
object.typenum = typenum;
object.inner.ptr = typenum_table[typenum - 1].constructor();
object.inner.ptr = typenum_table[typenum - 1].construct();
if (object.inner.ptr == nullptr) DESER_OBJECTS_END_FAIL;
}
if (!typenum_table[typenum - 1].deserialize(object.inner.ptr, data, max_size)) DESER_OBJECTS_END_FAIL;
// Deserialize the object
if (!should_be_disposed) {
if (!typenum_table[typenum - 1].deserialize(object.inner.ptr, data, max_size)) DESER_OBJECTS_END_FAIL;
} else if (!currently_disposed) {
typenum_table[typenum - 1].dispose_without_signal(object.inner.ptr);
}
// Add it to the pointer map so that other objects that reference this one will be able to see it
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));
@ -1878,24 +1901,40 @@ extern "C" RETRO_API bool retro_unserialize(const void *data, size_t len) {
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();
// Create a new object
void *ptr = typenum_table[typenum - 1].construct();
if (ptr == nullptr) DESER_OBJECTS_END_FAIL;
// Deserialize into the newly created object
if (!typenum_table[typenum - 1].deserialize(ptr, data, max_size)) {
typenum_table[typenum - 1].destructor(ptr);
typenum_table[typenum - 1].destroy(ptr);
DESER_OBJECTS_END_FAIL;
}
// Add it to the pointer map so that other objects that reference this one will be able to see it
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);
typenum_table[typenum - 1].destroy(ptr);
DESER_OBJECTS_END_FAIL;
}
}
++extra_object_key;
}
for (const auto &object : sb()->objects) {
if (object.typenum > 0 && !typenum_table[object.typenum - 1].disposed(object.inner.ptr)) {
typenum_table[object.typenum - 1].deserialize_end(object.inner.ptr);
}
}
for (const auto &pair : extra_objects_deser) {
if (pair.second.get_typenum() > 0 && !typenum_table[pair.second.get_typenum() - 1].disposed(pair.second.get_ptr())) {
typenum_table[pair.second.get_typenum() - 1].deserialize_end(pair.second.get_ptr());
}
}
DESER_OBJECTS_END;
return true;
}

View file

@ -3392,9 +3392,6 @@ void Bitmap::loresDisposal()
#ifdef MKXPZ_RETRO
bool Bitmap::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const
{
if (isDisposed()) return mkxp_sandbox::sandbox_serialize(false, data, max_size);
if (!mkxp_sandbox::sandbox_serialize(true, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->path, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize((int32_t)width(), data, max_size)) return false;
@ -3422,16 +3419,6 @@ bool Bitmap::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size)
bool Bitmap::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->path, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize((int32_t &)p->gl.width, data, max_size)) return false;
@ -3460,4 +3447,15 @@ bool Bitmap::sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &m
return true;
}
void Bitmap::sandbox_deserialize_end()
{
if (isDisposed()) return;
if (p->selfLores != nullptr) {
loresDispCon = p->selfLores->wasDisposed.connect(&Bitmap::loresDisposal, this);
if (p->selfLores->isDisposed()) {
p->selfLores->wasDisposed();
}
}
}
#endif // MKXPZ_RETRO

View file

@ -199,6 +199,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);
void sandbox_deserialize_end();
#endif // MKXPZ_RETRO
private:

View file

@ -353,9 +353,6 @@ void Plane::releaseResources()
#ifdef MKXPZ_RETRO
bool Plane::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const
{
if (isDisposed()) return mkxp_sandbox::sandbox_serialize(false, data, max_size);
if (!mkxp_sandbox::sandbox_serialize(true, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->opacity, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->blendType, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize((int32_t)p->ox, data, max_size)) return false;
@ -375,16 +372,6 @@ bool Plane::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size)
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;
@ -401,4 +388,17 @@ bool Plane::sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &ma
return true;
}
void Plane::sandbox_deserialize_end()
{
sandbox_deserialize_end_viewport_element();
if (isDisposed()) return;
if (p->bitmap != nullptr) {
p->bitmapDispCon = p->bitmap->wasDisposed.connect(&PlanePrivate::bitmapDisposal, p);
if (p->bitmap->isDisposed()) {
p->bitmap->wasDisposed();
}
}
}
#endif // MKXPZ_RETRO

View file

@ -56,6 +56,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);
void sandbox_deserialize_end();
#endif // MKXPZ_RETRO
private:

View file

@ -859,9 +859,6 @@ void Sprite::releaseResources()
#ifdef MKXPZ_RETRO
bool Sprite::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const
{
if (isDisposed()) return mkxp_sandbox::sandbox_serialize(false, data, max_size);
if (!mkxp_sandbox::sandbox_serialize(true, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->quad, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->trans, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->mirrored, data, max_size)) return false;
@ -899,16 +896,6 @@ bool Sprite::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size)
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;
@ -943,4 +930,17 @@ bool Sprite::sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &m
return true;
}
void Sprite::sandbox_deserialize_end()
{
sandbox_deserialize_end_viewport_element();
if (isDisposed()) return;
if (p->bitmap != nullptr) {
p->bitmapDispCon = p->bitmap->wasDisposed.connect(&SpritePrivate::bitmapDisposal, p);
if (p->bitmap->isDisposed()) {
p->bitmap->wasDisposed();
}
}
}
#endif // MKXPZ_RETRO

View file

@ -85,6 +85,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);
void sandbox_deserialize_end();
#endif // MKXPZ_RETRO
private:

View file

@ -1475,9 +1475,6 @@ bool Tilemap::Autotiles::sandbox_deserialize(const void *&data, mkxp_sandbox::wa
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);
if (!mkxp_sandbox::sandbox_serialize(true, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->visible, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->origin, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->dispPos, data, max_size)) return false;
@ -1530,16 +1527,6 @@ bool Tilemap::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size
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;
@ -1597,4 +1584,33 @@ bool Tilemap::sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &
return true;
}
void Tilemap::sandbox_deserialize_end()
{
if (isDisposed()) return;
p->elem.ground->sandbox_deserialize_end_viewport_element();
for (size_t i = 0; i < zlayersMax; ++i) {
if (isDisposed()) return;
p->elem.zlayers[i]->sandbox_deserialize_end_viewport_element();
}
for (size_t i = 0; i < autotileCount; ++i) {
if (isDisposed()) return;
if (p->autotiles[i] != nullptr) {
p->autotilesDispCon[i] = p->autotiles[i]->wasDisposed.connect( [i, this] { p->atlasContentsDisposal(i); } );
if (p->autotiles[i]->isDisposed()) {
p->autotiles[i]->wasDisposed();
}
}
}
if (isDisposed()) return;
if (p->tileset != nullptr) {
p->tilesetDispCon = p->tileset->wasDisposed.connect(&TilemapPrivate::tilesetDisposal, p);
if (p->tileset->isDisposed()) {
p->tileset->wasDisposed();
}
}
}
#endif // MKXPZ_RETRO

View file

@ -89,6 +89,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);
void sandbox_deserialize_end();
#endif // MKXPZ_RETRO
private:

View file

@ -633,9 +633,6 @@ bool TilemapVX::BitmapArray::sandbox_deserialize(const void *&data, mkxp_sandbox
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);
if (!mkxp_sandbox::sandbox_serialize(true, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->origin, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->dispPos, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->groundVert, data, max_size)) return false;
@ -660,16 +657,6 @@ bool TilemapVX::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_si
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;
@ -703,4 +690,23 @@ bool TilemapVX::sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t
return true;
}
void TilemapVX::sandbox_deserialize_end()
{
if (isDisposed()) return;
p->above.sandbox_deserialize_end_viewport_element();
if (isDisposed()) return;
p->sandbox_deserialize_end_viewport_element();
for (size_t i = 0; i < BM_COUNT; ++i) {
if (isDisposed()) return;
if (p->bitmaps[i] != nullptr) {
p->bmDisposedCons[i] = p->bitmaps[i]->wasDisposed.connect( [i, this] { p->atlasDisposal(i); } );
if (p->bitmaps[i]->isDisposed()) {
p->bitmaps[i]->wasDisposed();
}
}
}
}
#endif // MKXPZ_RETRO

View file

@ -77,6 +77,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);
void sandbox_deserialize_end();
#endif // MKXPZ_RETRO
private:

View file

@ -232,9 +232,6 @@ void Viewport::releaseResources()
#ifdef MKXPZ_RETRO
bool Viewport::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const
{
if (isDisposed()) return mkxp_sandbox::sandbox_serialize(false, data, max_size);
if (!mkxp_sandbox::sandbox_serialize(true, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->screenRect, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->isOnScreen, data, max_size)) return false;
if (!sandbox_serialize_scene_element(data, max_size)) return false;
@ -247,16 +244,6 @@ bool Viewport::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_siz
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;
@ -323,4 +310,14 @@ bool ViewportElement::sandbox_deserialize_viewport_element(const void *&data, mk
return true;
}
void ViewportElement::sandbox_deserialize_end_viewport_element()
{
if (m_viewport != nullptr) {
viewportDispCon = m_viewport->wasDisposed.connect(&ViewportElement::viewportElementDisposal, this);
if (m_viewport->isDisposed()) {
m_viewport->wasDisposed();
}
}
}
#endif // MXKPZ_RETRO

View file

@ -87,6 +87,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);
void sandbox_deserialize_end_viewport_element();
#endif // MXKPZ_RETRO
protected:

View file

@ -953,9 +953,6 @@ void Window::releaseResources()
#ifdef MKXPZ_RETRO
bool Window::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const
{
if (isDisposed()) return mkxp_sandbox::sandbox_serialize(false, data, max_size);
if (!mkxp_sandbox::sandbox_serialize(true, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->bgStretch, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->active, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->pause, data, max_size)) return false;
@ -985,16 +982,6 @@ bool Window::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size)
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;
@ -1021,4 +1008,25 @@ bool Window::sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &m
return true;
}
void Window::sandbox_deserialize_end()
{
sandbox_deserialize_end_viewport_element();
if (isDisposed()) return;
if (p->windowskin != nullptr) {
p->windowskinDispCon = p->windowskin->wasDisposed.connect(&WindowPrivate::windowskinDisposal, p);
if (p->windowskin->isDisposed()) {
p->windowskin->wasDisposed();
}
}
if (isDisposed()) return;
if (p->contents != nullptr) {
p->contentsDispCon = p->contents->wasDisposed.connect(&WindowPrivate::contentsDisposal, p);
if (p->contents->isDisposed()) {
p->contents->wasDisposed();
}
}
}
#endif // MKXPZ_RETRO

View file

@ -68,6 +68,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);
void sandbox_deserialize_end();
#endif // MKXPZ_RETRO
private:

View file

@ -1166,9 +1166,6 @@ void WindowVX::releaseResources()
#ifdef MKXPZ_RETRO
bool WindowVX::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const
{
if (isDisposed()) return mkxp_sandbox::sandbox_serialize(false, data, max_size);
if (!mkxp_sandbox::sandbox_serialize(true, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->active, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->arrowsVisible, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->pause, data, max_size)) return false;
@ -1202,16 +1199,6 @@ bool WindowVX::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_siz
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;
@ -1242,4 +1229,25 @@ bool WindowVX::sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t
return true;
}
void WindowVX::sandbox_deserialize_end()
{
sandbox_deserialize_end_viewport_element();
if (isDisposed()) return;
if (p->windowskin != nullptr) {
p->windowskinDispCon = p->windowskin->wasDisposed.connect(&WindowVXPrivate::windowskinDisposal, p);
if (p->windowskin->isDisposed()) {
p->windowskin->wasDisposed();
}
}
if (isDisposed()) return;
if (p->contents != nullptr) {
p->contentsDispCon = p->contents->wasDisposed.connect(&WindowVXPrivate::contentsDisposal, p);
if (p->contents->isDisposed()) {
p->contents->wasDisposed();
}
}
}
#endif // MKXPZ_RETRO

View file

@ -75,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);
void sandbox_deserialize_end();
#endif // MKXPZ_RETRO
private: