Refactor libretro save state serialization to not require extra objects

This commit is contained in:
刘皓 2025-05-31 19:06:57 -04:00
parent adc9cdd96d
commit 3c244cc7ea
No known key found for this signature in database
GPG key ID: 7901753DB465B711
10 changed files with 120 additions and 157 deletions

View file

@ -107,15 +107,13 @@ template <typename T> static typename std::enable_if<!boost::is_detected<deseria
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;
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;
std::unordered_map<wasm_size_t, struct sandbox_swizzle_info> mkxp_sandbox::swizzle_map;
sandbox_object_deser_info::sandbox_object_deser_info(void *ptr, wasm_size_t typenum) : ptr(ptr), typenum(typenum), ref_count(0), exists(true) {}
sandbox_swizzle_info::sandbox_swizzle_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)) {}
sandbox_swizzle_info::sandbox_swizzle_info(struct sandbox_swizzle_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)) {}
struct sandbox_object_deser_info &sandbox_object_deser_info::operator=(struct sandbox_object_deser_info &&info) noexcept {
struct sandbox_swizzle_info &sandbox_swizzle_info::operator=(struct sandbox_swizzle_info &&info) noexcept {
ptr = std::exchange(info.ptr, nullptr);
typenum = info.typenum;
ref_count = std::exchange(info.ref_count, 1);
@ -123,17 +121,17 @@ struct sandbox_object_deser_info &sandbox_object_deser_info::operator=(struct sa
return *this;
}
sandbox_object_deser_info::~sandbox_object_deser_info() {
sandbox_swizzle_info::~sandbox_swizzle_info() {
if (!exists) {
delete (std::vector<void **> *)ptr;
}
}
wasm_size_t sandbox_object_deser_info::get_ref_count() const noexcept {
wasm_size_t sandbox_swizzle_info::get_ref_count() const noexcept {
return ref_count;
}
bool sandbox_object_deser_info::set_ptr(void *ptr, wasm_size_t typenum) {
bool sandbox_swizzle_info::set_ptr(void *ptr, wasm_size_t typenum) {
if (this->typenum != typenum) {
// Don't allow pointers of mismatching type
return false;
@ -153,15 +151,15 @@ bool sandbox_object_deser_info::set_ptr(void *ptr, wasm_size_t typenum) {
return true;
}
void *sandbox_object_deser_info::get_ptr() const {
void *sandbox_swizzle_info::get_ptr() const {
return exists ? ptr : nullptr;
}
wasm_size_t sandbox_object_deser_info::get_typenum() const {
wasm_size_t sandbox_swizzle_info::get_typenum() const {
return typenum;
}
bool sandbox_object_deser_info::get_exists() const {
bool sandbox_swizzle_info::get_exists() const {
return exists;
}

View file

@ -22,7 +22,6 @@
#ifndef MKXPZ_SANDBOX_SERIAL_UTIL_H
#define MKXPZ_SANDBOX_SERIAL_UTIL_H
#include <tuple>
#include <type_traits>
#include <unordered_map>
#include <utility>
@ -76,14 +75,14 @@ namespace mkxp_sandbox {
static constexpr wasm_size_t _get_typenum_counter_start = __COUNTER__;
BOOST_PP_SEQ_FOR_EACH(_SANDBOX_DEF_GET_TYPENUM, _, SANDBOX_TYPENUM_TYPES);
struct sandbox_object_deser_info {
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;
struct sandbox_object_deser_info &operator=(struct sandbox_object_deser_info &&) noexcept;
~sandbox_object_deser_info();
struct sandbox_swizzle_info {
template <typename T> sandbox_swizzle_info(T *&ref) : ptr(new std::vector<void **>({(void **)&ref})), typenum(mkxp_sandbox::get_typenum<T>::value), ref_count(1), exists(false) {}
sandbox_swizzle_info(void *ptr, wasm_size_t typenum);
sandbox_swizzle_info(const struct sandbox_swizzle_info &) = delete;
sandbox_swizzle_info(struct sandbox_swizzle_info &&) noexcept;
struct sandbox_swizzle_info &operator=(const struct sandbox_swizzle_info &) = delete;
struct sandbox_swizzle_info &operator=(struct sandbox_swizzle_info &&) noexcept;
~sandbox_swizzle_info();
wasm_size_t get_ref_count() const noexcept;
template <typename T> bool add_ref(T *&ref) {
if (typenum != mkxp_sandbox::get_typenum<T>::value) {
@ -118,9 +117,7 @@ namespace mkxp_sandbox {
bool exists;
};
extern std::vector<std::tuple<const void *, wasm_size_t>> extra_objects;
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;
extern std::unordered_map<wasm_size_t, struct sandbox_swizzle_info> swizzle_map;
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 &>()));
@ -144,12 +141,7 @@ namespace mkxp_sandbox {
template <typename T> struct sandbox_ptr_map {
private:
struct info {
mkxp_sandbox::wasm_objkey_t key;
bool is_extra;
};
static std::unordered_map<const T *, struct info> map;
static std::unordered_map<const T *, mkxp_sandbox::wasm_objkey_t> unswizzle_map;
static bool is_serializing;
static bool is_deserializing;
@ -166,14 +158,13 @@ namespace mkxp_sandbox {
}
is_serializing = true;
map.clear();
extra_objects.clear();
unswizzle_map.clear();
wasm_objkey_t key = 0;
for (const auto &object : sb()->objects) {
++key;
if (object.typenum == get_typenum<T>::value) {
map.emplace((T *)object.inner.ptr, (struct info){key, false});
unswizzle_map.emplace((T *)object.inner.ptr, key);
}
}
}
@ -185,22 +176,9 @@ namespace mkxp_sandbox {
std::abort();
}
if (ptr == nullptr) {
if (!mkxp_sandbox::sandbox_serialize((uint8_t)2, data, max_size)) return false;
} else {
const auto &it = map.find(ptr);
if (it != map.end()) {
if (!mkxp_sandbox::sandbox_serialize((uint8_t)(it->second.is_extra ? 1 : 0), data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(it->second.key, data, max_size)) return false;
} else {
if (!mkxp_sandbox::sandbox_serialize((uint8_t)1, data, max_size)) return false;
constexpr wasm_size_t typenum = get_typenum<T>::value;
extra_objects.emplace_back((const void *)ptr, typenum);
map.emplace(ptr, (struct info){(wasm_objkey_t)extra_objects.size(), true});
if (!mkxp_sandbox::sandbox_serialize((wasm_objkey_t)extra_objects.size(), data, max_size)) return false;
}
if (!mkxp_sandbox::sandbox_serialize(ptr != nullptr, data, max_size)) return false;
if (ptr != nullptr) {
if (!mkxp_sandbox::sandbox_serialize(unswizzle_map.at(ptr), data, max_size)) return false;
}
return true;
@ -212,8 +190,7 @@ namespace mkxp_sandbox {
}
is_serializing = false;
map.clear();
extra_objects.clear();
unswizzle_map.clear();
}
static void sandbox_deserialize_begin() {
@ -228,8 +205,7 @@ namespace mkxp_sandbox {
}
is_deserializing = true;
objects_deser.clear();
extra_objects_deser.clear();
swizzle_map.clear();
}
static bool sandbox_deserialize(T *&ref, const void *&data, wasm_size_t &max_size) {
@ -239,22 +215,19 @@ namespace mkxp_sandbox {
std::abort();
}
uint8_t type;
if (!mkxp_sandbox::sandbox_deserialize(type, data, max_size)) return false;
if (type > 2) return false;
bool is_not_null;
if (!mkxp_sandbox::sandbox_deserialize(is_not_null, data, max_size)) return false;
if (type == 2) {
if (!is_not_null) {
ref = nullptr;
// Don't allow null Color, Tone or Rect pointers (null Font pointers are allowed since they indicate `shState->defaultFont()`)
return !std::is_same<T, Color>::value && !std::is_same<T, Tone>::value && !std::is_same<T, Rect>::value;
return true;
}
wasm_objkey_t key;
if (!mkxp_sandbox::sandbox_deserialize(key, data, max_size)) return false;
auto &deser_map = type != 0 ? extra_objects_deser : objects_deser;
const auto it = deser_map.find(key);
if (it == deser_map.end()) {
deser_map.emplace(key, sandbox_object_deser_info(ref));
const auto it = swizzle_map.find(key);
if (it == swizzle_map.end()) {
swizzle_map.emplace(key, sandbox_swizzle_info(ref));
return true;
} else {
return it->second.add_ref(ref);
@ -267,21 +240,11 @@ 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].destroy(info.get_ptr());
}
}
extra_objects_deser.clear();
swizzle_map.clear();
}
};
template <typename T> std::unordered_map<const T *, struct sandbox_ptr_map<T>::info> sandbox_ptr_map<T>::map;
template <typename T> std::unordered_map<const T *, mkxp_sandbox::wasm_objkey_t> sandbox_ptr_map<T>::unswizzle_map;
template <typename T> bool sandbox_ptr_map<T>::is_serializing = false;
template <typename T> bool sandbox_ptr_map<T>::is_deserializing = false;

View file

@ -1692,24 +1692,6 @@ extern "C" RETRO_API bool retro_serialize(void *data, size_t len) {
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)) 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 != 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::fflush(stderr);
std::abort();
} else {
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();
SER_OBJECTS_END;
std::memset(data, 0, max_size);
return true;
@ -1888,8 +1870,8 @@ extern "C" RETRO_API bool retro_unserialize(const void *data, size_t len) {
object.typenum = typenum;
object.inner.ptr = typenum_table[typenum - 1].construct();
if (object.inner.ptr == nullptr) DESER_OBJECTS_END_FAIL;
typenum_table[typenum - 1].deserialize_begin(object.inner.ptr, true);
currently_disposed = false;
typenum_table[typenum - 1].deserialize_begin(object.inner.ptr, true);
}
// Deserialize the object
@ -1899,10 +1881,10 @@ extern "C" RETRO_API bool retro_unserialize(const void *data, size_t len) {
typenum_table[typenum - 1].dispose(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));
// Add it to the swizzle map so that other objects that reference this one will be able to see it
auto it = swizzle_map.find(object_key);
if (it == swizzle_map.end()) {
swizzle_map.emplace(object_key, sandbox_swizzle_info(object.inner.ptr, typenum));
} else {
it->second.set_ptr(object.inner.ptr, typenum);
}
@ -1910,46 +1892,8 @@ extern "C" RETRO_API bool retro_unserialize(const void *data, size_t len) {
}
}
// 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;
// Create a new object
void *ptr = typenum_table[typenum - 1].construct();
if (ptr == nullptr) DESER_OBJECTS_END_FAIL;
typenum_table[typenum - 1].deserialize_begin(ptr, true);
// Deserialize into the newly created object
if (!typenum_table[typenum - 1].deserialize(ptr, data, max_size)) {
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].destroy(ptr);
DESER_OBJECTS_END_FAIL;
}
}
++extra_object_key;
}
// Make sure every pointer in the save state has been swizzled
for (const auto &pair : objects_deser) {
if (!pair.second.get_exists()) {
DESER_OBJECTS_END_FAIL;
}
}
for (const auto &pair : extra_objects_deser) {
for (const auto &pair : swizzle_map) {
if (!pair.second.get_exists()) {
DESER_OBJECTS_END_FAIL;
}
@ -1960,11 +1904,6 @@ extern "C" RETRO_API bool retro_unserialize(const void *data, size_t len) {
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].deserialize_end(pair.second.get_ptr());
}
}
DESER_OBJECTS_END;
return true;
}

View file

@ -698,8 +698,9 @@ bool Font::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) c
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->color, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->outColor, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->color == &p->colorTmp ? nullptr : p->color, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->outColor == &p->outColorTmp ? nullptr : 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;
@ -713,8 +714,15 @@ bool Font::sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max
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 (p->color == nullptr) {
p->color = &p->colorTmp;
}
if (!mkxp_sandbox::sandbox_deserialize(p->outColor, data, max_size)) return false;
if (p->outColor == nullptr) {
p->outColor = &p->outColorTmp;
}
// Invalidate the inner font object if either the name or size of this font is different from before
if (p->sdlFont != nullptr) {

View file

@ -360,10 +360,12 @@ bool Plane::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size)
if (!mkxp_sandbox::sandbox_serialize(p->zoomX, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->zoomY, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->sceneGeo, data, max_size)) return false;
if (!sandbox_serialize_viewport_element(data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->bitmap, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->color, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->tone, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->color == &p->tmp.color ? nullptr : p->color, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->tone == &p->tmp.tone ? nullptr : p->tone, data, max_size)) return false;
return true;
}
@ -407,10 +409,18 @@ bool Plane::sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &ma
p->quadSourceDirty = true;
}
}
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 (p->color == nullptr) {
p->color = &p->tmp.color;
}
if (!mkxp_sandbox::sandbox_deserialize(p->tone, data, max_size)) return false;
if (p->tone == nullptr) {
p->tone = &p->tmp.tone;
}
return true;
}

View file

@ -890,9 +890,9 @@ bool Sprite::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size)
if (!mkxp_sandbox::sandbox_serialize(p->bitmap, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->pattern, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->srcRect, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->color, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->tone, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->srcRect == &p->tmp.rect ? nullptr : p->srcRect, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->color == &p->tmp.color ? nullptr : p->color, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->tone == &p->tmp.tone ? nullptr : p->tone, data, max_size)) return false;
return true;
}
@ -977,8 +977,17 @@ bool Sprite::sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &m
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 (p->srcRect == nullptr) {
p->srcRect = &p->tmp.rect;
}
if (!mkxp_sandbox::sandbox_deserialize(p->color, data, max_size)) return false;
if (p->color == nullptr) {
p->color = &p->tmp.color;
}
if (!mkxp_sandbox::sandbox_deserialize(p->tone, data, max_size)) return false;
if (p->tone == nullptr) {
p->tone = &p->tmp.tone;
}
return true;
}

View file

@ -1514,8 +1514,8 @@ bool Tilemap::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size
if (!mkxp_sandbox::sandbox_serialize(p->mapData, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->priorities, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->flashMap.getData(), data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->color, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->tone, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->color == &p->tmp.color ? nullptr : p->color, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->tone == &p->tmp.tone ? nullptr : p->tone, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(atProxy, data, max_size)) return false;
@ -1577,7 +1577,13 @@ bool Tilemap::sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &
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 (p->color == nullptr) {
p->color = &p->tmp.color;
}
if (!mkxp_sandbox::sandbox_deserialize(p->tone, data, max_size)) return false;
if (p->tone == nullptr) {
p->tone = &p->tmp.tone;
}
if (!mkxp_sandbox::sandbox_deserialize(atProxy, data, max_size)) return false;

View file

@ -253,9 +253,9 @@ bool Viewport::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_siz
if (!sandbox_serialize_scene_element(data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->rect, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->color, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->tone, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->rect == &p->tmp.rect ? nullptr : p->rect, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->color == &p->tmp.color ? nullptr : p->color, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->tone == &p->tmp.tone ? nullptr : p->tone, data, max_size)) return false;
return true;
}
@ -273,8 +273,17 @@ bool Viewport::sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t
if (!sandbox_deserialize_scene_element(data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->rect, data, max_size)) return false;
if (p->rect == nullptr) {
p->rect = &p->tmp.rect;
}
if (!mkxp_sandbox::sandbox_deserialize(p->color, data, max_size)) return false;
if (p->color == nullptr) {
p->color = &p->tmp.color;
}
if (!mkxp_sandbox::sandbox_deserialize(p->tone, data, max_size)) return false;
if (p->tone == nullptr) {
p->tone = &p->tmp.tone;
}
return true;
}

View file

@ -967,14 +967,18 @@ bool Window::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size)
if (!mkxp_sandbox::sandbox_serialize(p->opacity, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->backOpacity, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->contentsOpacity, data, max_size)) return false;
if (!p->controlsElement.sandbox_serialize_viewport_element(data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->cursorAniAlphaIdx, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->pauseAniAlphaIdx, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->pauseAniQuadIdx, data, max_size)) return false;
if (!sandbox_serialize_viewport_element(data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->windowskin, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->contents, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->cursorRect, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->cursorRect == &p->tmp.rect ? nullptr : p->cursorRect, data, max_size)) return false;
return true;
}
@ -1033,17 +1037,24 @@ bool Window::sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &m
p->contentsQuad.setColor(Vec4(1, 1, 1, p->contentsOpacity.norm));
}
}
if (!p->controlsElement.sandbox_deserialize_viewport_element(data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->cursorAniAlphaIdx, data, max_size)) return false;
p->cursorAniAlphaIdx %= cursorAniAlphaN;
if (!mkxp_sandbox::sandbox_deserialize(p->pauseAniAlphaIdx, data, max_size)) return false;
p->pauseAniAlphaIdx = std::min(p->pauseAniAlphaIdx, (uint8_t)(pauseAniAlphaN - 1));
if (!mkxp_sandbox::sandbox_deserialize(p->pauseAniQuadIdx, data, max_size)) return false;
p->pauseAniQuadIdx %= pauseAniQuadN;
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 (p->cursorRect == nullptr) {
p->cursorRect = &p->tmp.rect;
}
return true;
}

View file

@ -1191,11 +1191,13 @@ bool WindowVX::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_siz
if (!mkxp_sandbox::sandbox_serialize(p->pauseQuadIdx, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->cursorAlphaIdx, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->sceneOffset, data, max_size)) return false;
if (!sandbox_serialize_viewport_element(data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->windowskin, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->contents, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->cursorRect, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->tone, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->cursorRect == &p->tmp.rect ? nullptr : p->cursorRect, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->tone == &p->tmp.tone ? nullptr : p->tone, data, max_size)) return false;
return true;
}
@ -1287,11 +1289,19 @@ bool WindowVX::sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t
if (!mkxp_sandbox::sandbox_deserialize(p->cursorAlphaIdx, data, max_size)) return false;
p->cursorAlphaIdx %= cursorAlphaN;
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 (p->cursorRect == nullptr) {
p->cursorRect = &p->tmp.rect;
}
if (!mkxp_sandbox::sandbox_deserialize(p->tone, data, max_size)) return false;
if (p->tone == nullptr) {
p->tone = &p->tmp.tone;
}
return true;
}