Update tilemap dirty flags during libretro save state deserialization

This commit is contained in:
刘皓 2025-05-29 14:57:02 -04:00
parent 7980cd440a
commit 28b81ca95d
No known key found for this signature in database
GPG key ID: 7901753DB465B711
13 changed files with 174 additions and 23 deletions

View file

@ -105,6 +105,10 @@ return __VA_ARGS__; \
#define OUTLINE_SIZE 1
#ifdef MKXPZ_RETRO
static uint64_t next_id = 1;
#endif // MKXPZ_RETRO
/* Normalize (= ensure width and
* height are positive) */
static IntRect normalizedRect(const IntRect &rect)
@ -609,6 +613,9 @@ struct BitmapOpenHandler : FileSystem::OpenHandler
};
Bitmap::Bitmap(Exception &exception, const char *filename)
#ifdef MKXPZ_RETRO
: id(next_id++)
#endif // MKXPZ_RETRO
{
std::string hiresPrefix = "Hires/";
std::string filenameStd = filename;
@ -792,6 +799,9 @@ Bitmap::Bitmap(Exception &exception, const char *filename)
}
Bitmap::Bitmap(Exception &exception, int width, int height, bool isHires)
#ifdef MKXPZ_RETRO
: id(next_id++)
#endif // MKXPZ_RETRO
{
if (width <= 0 || height <= 0) {
exception = Exception(Exception::RGSSError, "failed to create bitmap");
@ -835,6 +845,9 @@ Bitmap::Bitmap(Exception &exception, int width, int height, bool isHires)
}
Bitmap::Bitmap(Exception &exception, void *pixeldata, int width, int height)
#ifdef MKXPZ_RETRO
: id(next_id++)
#endif // MKXPZ_RETRO
{
#ifdef MKXPZ_RETRO
SDL_Surface *surface = new SDL_Surface;
@ -900,6 +913,9 @@ Bitmap::Bitmap(Exception &exception, void *pixeldata, int width, int height)
// frame is -2 for "any and all", -1 for "current", anything else for a specific frame
Bitmap::Bitmap(Exception &exception, const Bitmap &other, int frame)
#ifdef MKXPZ_RETRO
: id(next_id++)
#endif // MKXPZ_RETRO
{
GUARD(other.guardDisposed(exception));
GUARD(other.ensureNonMega(exception));
@ -964,6 +980,9 @@ Bitmap::Bitmap(Exception &exception, const Bitmap &other, int frame)
}
Bitmap::Bitmap(Exception &exception, TEXFBO &other)
#ifdef MKXPZ_RETRO
: id(next_id++)
#endif // MKXPZ_RETRO
{
Bitmap *hiresBitmap = nullptr;
@ -1006,6 +1025,9 @@ Bitmap::Bitmap(Exception &exception, TEXFBO &other)
}
Bitmap::Bitmap(Exception &exception, SDL_Surface *imgSurf, SDL_Surface *imgSurfHires, bool forceMega)
#ifdef MKXPZ_RETRO
: id(next_id++)
#endif // MKXPZ_RETRO
{
Bitmap *hiresBitmap = nullptr;
@ -3419,13 +3441,38 @@ 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)
{
if (!mkxp_sandbox::sandbox_deserialize(p->path, data, max_size)) return false;
{
std::string old_path = p->path;
if (!mkxp_sandbox::sandbox_deserialize(p->path, data, max_size)) return false;
if (p->path != old_path) {
deserModified = true;
}
}
if (!mkxp_sandbox::sandbox_deserialize((int32_t &)p->gl.width, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize((int32_t &)p->gl.height, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->animation.enabled, data, max_size)) return false;
{
int32_t old_width = p->animation.enabled ? p->animation.width : p->gl.width;
if (!mkxp_sandbox::sandbox_deserialize((int32_t &)p->gl.width, data, max_size)) return false;
if (p->gl.width != old_width) {
deserModified = true;
}
}
{
int32_t old_height = p->animation.enabled ? p->animation.height : p->gl.height;
if (!mkxp_sandbox::sandbox_deserialize((int32_t &)p->gl.height, data, max_size)) return false;
if (p->gl.height != old_height) {
deserModified = true;
}
}
{
bool old_enabled = p->animation.enabled;
if (!mkxp_sandbox::sandbox_deserialize(p->animation.enabled, data, max_size)) return false;
if (p->animation.enabled != old_enabled) {
deserModified = true;
}
}
if (p->animation.enabled) {
uint32_t old_frame = p->animation.currentFrameI();
p->animation.width = p->gl.width;
p->animation.height = p->gl.height;
if (!mkxp_sandbox::sandbox_deserialize(p->animation.fps, data, max_size)) return false;
@ -3435,6 +3482,9 @@ bool Bitmap::sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &m
if (!mkxp_sandbox::sandbox_deserialize((int32_t &)p->animation.lastFrame, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->animation.playTime, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->animation.startTime, data, max_size)) return false;
if (p->animation.currentFrameI() != old_frame) {
deserModified = true;
}
}
if (!mkxp_sandbox::sandbox_deserialize(p->font, data, max_size)) return false;

View file

@ -192,6 +192,7 @@ public:
sigslot::signal<> modified;
#ifdef MKXPZ_RETRO
const uint64_t id; // Globally unique nonzero ID for this bitmap, for change detection during save state deserialization
bool deserModified;
#endif // MKXPZ_RETRO

View file

@ -49,6 +49,16 @@ public:
/* Origin of contents */
Vec2i orig;
bool operator==(const Geometry &other) const
{
return rect == other.rect && orig == other.orig;
}
bool operator!=(const Geometry &other) const
{
return !(*this == other);
}
Vec2i offset() const
{
return rect.pos() - orig;

View file

@ -965,7 +965,7 @@ void Sprite::sandbox_deserialize_end()
if (isDisposed()) return;
if (p->srcRect != nullptr) {
p->srcRectCon = p->srcRect->valueChanged.connect(&SpritePrivate::onSrcRectChange, p);
if (!(*p->srcRect == p->deserSavedSrcRect)) {
if (*p->srcRect != p->deserSavedSrcRect) {
p->onSrcRectChange();
}
}

View file

@ -329,9 +329,21 @@ struct TilemapPrivate
/* Change watches */
sigslot::connection tilesetCon;
#ifdef MKXPZ_RETRO
uint64_t deserSavedTilesetId;
#endif // MKXPZ_RETRO
sigslot::connection autotilesCon[autotileCount];
#ifdef MKXPZ_RETRO
uint64_t deserSavedAutotileIds[autotileCount];
#endif // MKXPZ_RETRO
sigslot::connection mapDataCon;
#ifdef MKXPZ_RETRO
uint64_t deserSavedMapDataId;
#endif // MKXPZ_RETRO
sigslot::connection prioritiesCon;
#ifdef MKXPZ_RETRO
uint64_t deserSavedPrioritiesId;
#endif // MKXPZ_RETRO
/* Dispose watches */
sigslot::connection autotilesDispCon[autotileCount];
@ -1488,7 +1500,6 @@ bool Tilemap::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size
for (size_t i = 0; i < autotileCount; ++i)
if (!mkxp_sandbox::sandbox_serialize((int32_t)p->atlas.nATFrames[i], data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->viewpPos, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->groundVert, data, max_size)) return false;
for (size_t i = 0; i < zlayersMax; ++i)
if (!mkxp_sandbox::sandbox_serialize(p->zlayerVert[i], data, max_size)) return false;
@ -1528,7 +1539,16 @@ 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)
{
if (!mkxp_sandbox::sandbox_deserialize(p->visible, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->origin, data, max_size)) return false;
{
Vec2i old_origin = p->origin;
if (!mkxp_sandbox::sandbox_deserialize(p->origin, data, max_size)) return false;
if (p->origin != old_origin) {
p->mapViewportDirty = true;
}
if (p->origin.y != old_origin.y) {
p->zOrderDirty = true;
}
}
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;
@ -1540,7 +1560,6 @@ bool Tilemap::sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &
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;
@ -1566,7 +1585,13 @@ bool Tilemap::sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &
if (!mkxp_sandbox::sandbox_deserialize(value, data, max_size)) return false;
p->elem.activeLayers = value;
}
if (!mkxp_sandbox::sandbox_deserialize(p->elem.sceneGeo, data, max_size)) return false;
{
Scene::Geometry old_geo = p->elem.sceneGeo;
if (!mkxp_sandbox::sandbox_deserialize(p->elem.sceneGeo, data, max_size)) return false;
if (p->elem.sceneGeo != old_geo) {
p->mapViewportDirty = true;
}
}
if (!mkxp_sandbox::sandbox_deserialize(p->opacity, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->blendType, data, max_size)) return false;
@ -1602,13 +1627,18 @@ void Tilemap::sandbox_deserialize_begin()
p->tilesetDispCon.disconnect();
p->tilesetCon.disconnect();
p->deserSavedTilesetId = p->tileset == nullptr ? 0 : p->tileset->id;
for (size_t i = 0; i < autotileCount; ++i)
for (size_t i = 0; i < autotileCount; ++i) {
p->autotilesCon[i].disconnect();
p->deserSavedAutotileIds[i] = p->autotiles[i] == nullptr ? 0 : p->autotiles[i]->id;
}
p->mapDataCon.disconnect();
p->deserSavedMapDataId = p->mapData == nullptr ? 0 : p->mapData->id;
p->prioritiesCon.disconnect();
p->deserSavedPrioritiesId = p->priorities == nullptr ? 0 : p->priorities->id;
}
void Tilemap::sandbox_deserialize_end()
@ -1651,7 +1681,7 @@ void Tilemap::sandbox_deserialize_end()
if (isDisposed()) return;
if (p->autotiles[i] != nullptr) {
p->autotilesCon[i] = p->autotiles[i]->modified.connect(&TilemapPrivate::invalidateAtlasContents, p);
if (p->autotiles[i]->deserModified) {
if (p->autotiles[i]->deserModified || p->autotiles[i]->id != p->deserSavedAutotileIds[i]) {
p->invalidateAtlasContents();
}
}
@ -1660,7 +1690,7 @@ void Tilemap::sandbox_deserialize_end()
if (isDisposed()) return;
if (p->mapData != nullptr) {
p->mapDataCon = p->mapData->modified.connect(&TilemapPrivate::invalidateBuffers, p);
if (p->mapData->deserModified) {
if (p->mapData->deserModified || p->mapData->id != p->deserSavedMapDataId) {
p->invalidateBuffers();
}
}
@ -1668,9 +1698,14 @@ void Tilemap::sandbox_deserialize_end()
if (isDisposed()) return;
if (p->priorities != nullptr) {
p->prioritiesCon = p->priorities->modified.connect(&TilemapPrivate::invalidateBuffers, p);
if (p->priorities->deserModified) {
if (p->priorities->deserModified || p->priorities->id != p->deserSavedPrioritiesId) {
p->invalidateBuffers();
}
}
if (isDisposed()) return;
if (p->tileset->deserModified) {
p->invalidateAtlasSize();
}
}
#endif // MKXPZ_RETRO

View file

@ -99,10 +99,19 @@ struct TilemapVXPrivate : public ViewportElement, TileAtlasVX::Reader
bool mapViewportDirty;
sigslot::connection mapDataCon;
#ifdef MKXPZ_RETRO
uint64_t deserSavedMapDataId;
#endif // MKXPZ_RETRO
sigslot::connection flagsCon;
#ifdef MKXPZ_RETRO
uint64_t deserSavedFlagsId;
#endif // MKXPZ_RETRO
sigslot::connection prepareCon;
sigslot::connection bmChangedCons[BM_COUNT];
#ifdef MKXPZ_RETRO
uint64_t deserSavedBitmapIds[BM_COUNT];
#endif // MKXPZ_RETRO
sigslot::connection bmDisposedCons[BM_COUNT];
struct AboveLayer : public ViewportElement
@ -635,6 +644,7 @@ bool TilemapVX::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_si
{
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->sceneGeo, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->groundVert, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->aboveVert, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize((mkxp_sandbox::wasm_size_t)p->allocQuads, data, max_size)) return false;
@ -657,8 +667,21 @@ 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)
{
if (!mkxp_sandbox::sandbox_deserialize(p->origin, data, max_size)) return false;
{
Vec2i old_origin = p->origin;
if (!mkxp_sandbox::sandbox_deserialize(p->origin, data, max_size)) return false;
if (p->origin != old_origin) {
p->mapViewportDirty = true;
}
}
if (!mkxp_sandbox::sandbox_deserialize(p->dispPos, data, max_size)) return false;
{
Scene::Geometry old_geo = p->sceneGeo;
if (!mkxp_sandbox::sandbox_deserialize(p->sceneGeo, data, max_size)) return false;
if (p->sceneGeo != old_geo) {
p->mapViewportDirty = true;
}
}
if (!mkxp_sandbox::sandbox_deserialize(p->groundVert, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_deserialize(p->aboveVert, data, max_size)) return false;
{
@ -705,11 +728,14 @@ void TilemapVX::sandbox_deserialize_begin()
for (size_t i = 0; i < BM_COUNT; ++i) {
p->bmChangedCons[i].disconnect();
p->deserSavedBitmapIds[i] = p->bitmaps[i] == nullptr ? 0 : p->bitmaps[i]->id;
}
p->mapDataCon.disconnect();
p->deserSavedMapDataId = p->mapData == nullptr ? 0 : p->mapData->id;
p->flagsCon.disconnect();
p->deserSavedFlagsId = p->flags == nullptr ? 0 : p->flags->id;
}
void TilemapVX::sandbox_deserialize_end()
@ -734,7 +760,7 @@ void TilemapVX::sandbox_deserialize_end()
if (isDisposed()) return;
if (p->bitmaps[i] != nullptr) {
p->bmChangedCons[i] = p->bitmaps[i]->modified.connect(&TilemapVXPrivate::invalidateAtlas, p);
if (p->bitmaps[i]->deserModified) {
if (p->bitmaps[i]->deserModified || p->bitmaps[i]->id != p->deserSavedBitmapIds[i]) {
p->invalidateAtlas();
}
}
@ -743,7 +769,7 @@ void TilemapVX::sandbox_deserialize_end()
if (isDisposed()) return;
if (p->mapData != nullptr) {
p->mapDataCon = p->mapData->modified.connect(&TilemapVXPrivate::invalidateBuffers, p);
if (p->mapData->deserModified) {
if (p->mapData->deserModified || p->mapData->id != p->deserSavedMapDataId) {
p->invalidateBuffers();
}
}
@ -751,7 +777,7 @@ void TilemapVX::sandbox_deserialize_end()
if (isDisposed()) return;
if (p->flags != nullptr) {
p->flagsCon = p->flags->modified.connect(&TilemapVXPrivate::invalidateBuffers, p);
if (p->flags->deserModified) {
if (p->flags->deserModified || p->flags->id != p->deserSavedFlagsId) {
p->invalidateBuffers();
}
}

View file

@ -274,7 +274,7 @@ void Viewport::sandbox_deserialize_end()
if (isDisposed()) return;
if (p->rect != nullptr) {
p->rectCon = p->rect->valueChanged.connect(&ViewportPrivate::onRectChange, p);
if (!(*p->rect == p->deserSavedRect)) {
if (*p->rect != p->deserSavedRect) {
p->onRectChange();
}
}

View file

@ -1053,7 +1053,7 @@ void Window::sandbox_deserialize_end()
if (isDisposed()) return;
if (p->cursorRect != nullptr) {
p->cursorRectCon = p->cursorRect->valueChanged.connect(&WindowPrivate::markControlVertDirty, p);
if (!(*p->cursorRect == p->deserSavedCursorRect)) {
if (*p->cursorRect != p->deserSavedCursorRect) {
p->markControlVertDirty();
}
}

View file

@ -1284,7 +1284,7 @@ void WindowVX::sandbox_deserialize_end()
if (isDisposed()) return;
if (p->cursorRect != nullptr) {
p->cursorRectCon = p->cursorRect->valueChanged.connect(&WindowVXPrivate::invalidateCursorVert, p);
if (!(*p->cursorRect == p->deserSavedCursorRect)) {
if (*p->cursorRect != p->deserSavedCursorRect) {
p->invalidateCursorVert();
}
}
@ -1292,7 +1292,7 @@ void WindowVX::sandbox_deserialize_end()
if (isDisposed()) return;
if (p->tone != nullptr) {
p->toneCon = p->tone->valueChanged.connect(&WindowVXPrivate::invalidateBaseTex, p);
if (!(*p->tone == p->deserSavedTone)) {
if (*p->tone != p->deserSavedTone) {
p->invalidateBaseTex();
}
}

View file

@ -76,6 +76,11 @@ bool Color::operator==(const Color &o) const
alpha == o.alpha;
}
bool Color::operator!=(const Color &o) const
{
return !(*this == o);
}
const Color &Color::operator=(const Color &o)
{
red = o.red;
@ -222,6 +227,11 @@ bool Tone::operator==(const Tone &o) const
gray == o.gray;
}
bool Tone::operator!=(const Tone &o) const
{
return !(*this == o);
}
void Tone::set(double red, double green, double blue, double gray)
{
this->red = red;
@ -362,6 +372,11 @@ bool Rect::operator==(const Rect &o) const
height == o.height;
}
bool Rect::operator!=(const Rect &o) const
{
return !(*this == o);
}
void Rect::operator=(const IntRect &rect)
{
x = rect.x;

View file

@ -65,6 +65,7 @@ struct Color : public Serializable
void set(double red, double green, double blue, double alpha);
bool operator==(const Color &o) const;
bool operator!=(const Color &o) const;
void setRed(double value);
void setGreen(double value);
@ -119,6 +120,7 @@ struct Tone : public Serializable
virtual ~Tone() {}
bool operator==(const Tone &o) const;
bool operator!=(const Tone &o) const;
void set(double red, double green, double blue, double gray);
const Tone &operator=(const Tone &o);
@ -180,6 +182,7 @@ struct Rect : public Serializable
Rect(const IntRect &r);
bool operator==(const Rect &o) const;
bool operator!=(const Rect &o) const;
void operator=(const IntRect &rect);
void set(int x, int y, int w, int h);
const Rect &operator=(const Rect &o);

View file

@ -30,16 +30,26 @@
#ifdef MKXPZ_RETRO
# include "sandbox-serial-util.h"
static uint64_t next_id = 1;
#endif // MKXPZ_RETRO
/* Init normally */
Table::Table(int x, int y /*= 1*/, int z /*= 1*/)
: xs(x), ys(y), zs(z),
:
#ifdef MKXPZ_RETRO
id(next_id++),
#endif // MKXPZ_RETRO
xs(x), ys(y), zs(z),
data(x*y*z)
{}
Table::Table(const Table &other)
: xs(other.xs), ys(other.ys), zs(other.zs),
:
#ifdef MKXPZ_RETRO
id(next_id++),
#endif // MKXPZ_RETRO
xs(other.xs), ys(other.ys), zs(other.zs),
data(other.data)
{}

View file

@ -69,6 +69,7 @@ public:
sigslot::signal<> modified;
#ifdef MKXPZ_RETRO
const uint64_t id; // Globally unique nonzero ID for this table, for change detection during save state deserialization
bool deserModified;
bool sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const;