From 6f472fb73271b1cf1385f77a0b3a75a149d1681b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E7=9A=93?= Date: Wed, 28 May 2025 15:32:43 -0400 Subject: [PATCH] Handle disposal when deserializing save states in libretro builds --- binding-sandbox/binding-base.cpp | 4 +- binding-sandbox/binding-base.h | 8 +++- binding-sandbox/binding-util.cpp | 45 +++++++++++++++++-- binding-sandbox/sandbox-serial-util.cpp | 4 +- binding-sandbox/sandbox-serial-util.h | 10 ++--- src/core.cpp | 59 ++++++++++++++++++++----- src/display/bitmap.cpp | 24 +++++----- src/display/bitmap.h | 1 + src/display/plane.cpp | 26 +++++------ src/display/plane.h | 1 + src/display/sprite.cpp | 26 +++++------ src/display/sprite.h | 1 + src/display/tilemap.cpp | 42 ++++++++++++------ src/display/tilemap.h | 1 + src/display/tilemapvx.cpp | 32 ++++++++------ src/display/tilemapvx.h | 1 + src/display/viewport.cpp | 23 +++++----- src/display/viewport.h | 1 + src/display/window.cpp | 34 ++++++++------ src/display/window.h | 1 + src/display/windowvx.cpp | 34 ++++++++------ src/display/windowvx.h | 1 + 22 files changed, 250 insertions(+), 129 deletions(-) diff --git a/binding-sandbox/binding-base.cpp b/binding-sandbox/binding-base.cpp index ab81fad8..61864cbc 100644 --- a/binding-sandbox/binding-base.cpp +++ b/binding-sandbox/binding-base.cpp @@ -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; diff --git a/binding-sandbox/binding-base.h b/binding-sandbox/binding-base.h index ca4694b2..fb988e5b 100644 --- a/binding-sandbox/binding-base.h +++ b/binding-sandbox/binding-base.h @@ -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[]; diff --git a/binding-sandbox/binding-util.cpp b/binding-sandbox/binding-util.cpp index 48b074a6..798808a1 100644 --- a/binding-sandbox/binding-util.cpp +++ b/binding-sandbox/binding-util.cpp @@ -21,14 +21,15 @@ #include "binding-util.h" #include "sharedstate.h" +#include using namespace mkxp_sandbox; -template static typename std::enable_if::value, void *>::type constructor() { +template static typename std::enable_if::value, void *>::type construct() { return new T; } -template static typename std::enable_if::value && std::is_constructible::value, void *>::type constructor() { +template static typename std::enable_if::value && std::is_constructible::value, void *>::type construct() { Exception e; T *obj = new T(e); if (e.is_ok()) { @@ -39,12 +40,40 @@ template static typename std::enable_if:: } } -template static void destructor(void *self) { +template static void destroy(void *self) { if (self != nullptr) { delete (T *)self; } } +template static typename std::enable_if::value>::type destroy_without_signal(void *self) { + if (self != nullptr) { + ((T *)self)->wasDisposed.disconnect_all(); + delete (T *)self; + } +} + +template static typename std::enable_if::value>::type destroy_without_signal(void *self) { + destroy(self); +} + +template static typename std::enable_if::value>::type dispose_without_signal(void *self) { + if (self != nullptr) { + ((T *)self)->wasDisposed.disconnect_all(); + ((T *)self)->dispose(); + } +} + +template static typename std::enable_if::value>::type dispose_without_signal(void *self) {} + +template static typename std::enable_if::value, bool>::type disposed(void *self) { + return self == nullptr || ((T *)self)->isDisposed(); +} + +template static typename std::enable_if::value, bool>::type disposed(void *self) { + return self == nullptr; +} + template 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 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, destructor, serialize, deserialize}, +template using deserialize_end_declaration = decltype(std::declval()->sandbox_deserialize_end()); + +template static typename std::enable_if::value>::type deserialize_end(void *self) { + ((T *)self)->sandbox_deserialize_end(); +} + +template static typename std::enable_if::value>::type deserialize_end(void *self) {} + +#define _SANDBOX_DEF_TYPENUM_TABLE_ENTRY(_r, _data, T) {construct, destroy, destroy_without_signal, dispose_without_signal, disposed, serialize, deserialize, deserialize_end}, 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; diff --git a/binding-sandbox/sandbox-serial-util.cpp b/binding-sandbox/sandbox-serial-util.cpp index 91494354..e93be563 100644 --- a/binding-sandbox/sandbox-serial-util.cpp +++ b/binding-sandbox/sandbox-serial-util.cpp @@ -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; } diff --git a/binding-sandbox/sandbox-serial-util.h b/binding-sandbox/sandbox-serial-util.h index 8afe2fe5..4b34c2b6 100644 --- a/binding-sandbox/sandbox-serial-util.h +++ b/binding-sandbox/sandbox-serial-util.h @@ -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` of pointers that are waiting to point to the object. @@ -76,8 +76,8 @@ namespace mkxp_sandbox { extern std::unordered_map objects_deser; extern std::unordered_map extra_objects_deser; - template using sandbox_serialize_member_declaration = decltype(std::declval().sandbox_serialize(std::declval(), std::declval())); - template using sandbox_deserialize_member_declaration = decltype(std::declval().sandbox_deserialize(std::declval(), std::declval())); + template using sandbox_serialize_member_declaration = decltype(std::declval()->sandbox_serialize(std::declval(), std::declval())); + template using sandbox_deserialize_member_declaration = decltype(std::declval()->sandbox_deserialize(std::declval(), std::declval())); template typename std::enable_if::value, bool>::type sandbox_serialize(T value, void *&data, wasm_size_t &max_size); template typename std::enable_if::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()); } } diff --git a/src/core.cpp b/src/core.cpp index 705bc946..0b87f56a 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -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::value && typenum != get_typenum::value && typenum != get_typenum::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; } diff --git a/src/display/bitmap.cpp b/src/display/bitmap.cpp index 87e18a48..4c509228 100644 --- a/src/display/bitmap.cpp +++ b/src/display/bitmap.cpp @@ -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 diff --git a/src/display/bitmap.h b/src/display/bitmap.h index 146b4148..f8de9987 100644 --- a/src/display/bitmap.h +++ b/src/display/bitmap.h @@ -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: diff --git a/src/display/plane.cpp b/src/display/plane.cpp index 12c9ca1e..058b507b 100644 --- a/src/display/plane.cpp +++ b/src/display/plane.cpp @@ -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 diff --git a/src/display/plane.h b/src/display/plane.h index 89d33db7..676af1d4 100644 --- a/src/display/plane.h +++ b/src/display/plane.h @@ -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: diff --git a/src/display/sprite.cpp b/src/display/sprite.cpp index 3b1c2f84..54b87933 100644 --- a/src/display/sprite.cpp +++ b/src/display/sprite.cpp @@ -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 diff --git a/src/display/sprite.h b/src/display/sprite.h index ca2f931e..00c5d19d 100644 --- a/src/display/sprite.h +++ b/src/display/sprite.h @@ -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: diff --git a/src/display/tilemap.cpp b/src/display/tilemap.cpp index 8e0fa149..1458109c 100644 --- a/src/display/tilemap.cpp +++ b/src/display/tilemap.cpp @@ -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 diff --git a/src/display/tilemap.h b/src/display/tilemap.h index a5d0f112..2fe93f02 100644 --- a/src/display/tilemap.h +++ b/src/display/tilemap.h @@ -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: diff --git a/src/display/tilemapvx.cpp b/src/display/tilemapvx.cpp index 469f40d8..0fb959e2 100644 --- a/src/display/tilemapvx.cpp +++ b/src/display/tilemapvx.cpp @@ -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 diff --git a/src/display/tilemapvx.h b/src/display/tilemapvx.h index 1069577b..96e2b07d 100644 --- a/src/display/tilemapvx.h +++ b/src/display/tilemapvx.h @@ -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: diff --git a/src/display/viewport.cpp b/src/display/viewport.cpp index dd9d7a56..92b528a8 100644 --- a/src/display/viewport.cpp +++ b/src/display/viewport.cpp @@ -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 diff --git a/src/display/viewport.h b/src/display/viewport.h index 3320a831..71bef7fc 100644 --- a/src/display/viewport.h +++ b/src/display/viewport.h @@ -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: diff --git a/src/display/window.cpp b/src/display/window.cpp index ccf883d8..3f3f9301 100644 --- a/src/display/window.cpp +++ b/src/display/window.cpp @@ -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 diff --git a/src/display/window.h b/src/display/window.h index 9f71d634..ca10b841 100644 --- a/src/display/window.h +++ b/src/display/window.h @@ -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: diff --git a/src/display/windowvx.cpp b/src/display/windowvx.cpp index f9e9886b..49a86753 100644 --- a/src/display/windowvx.cpp +++ b/src/display/windowvx.cpp @@ -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 diff --git a/src/display/windowvx.h b/src/display/windowvx.h index d83f97b9..9971c297 100644 --- a/src/display/windowvx.h +++ b/src/display/windowvx.h @@ -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: