From ce479e09ff65216f4b0c65494c3d8b25fdbfb06d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Lu=C3=ADs=20Vaz=20Silva?= Date: Sun, 17 Mar 2024 17:47:53 -0300 Subject: [PATCH] Fix A_ChangeModel serialization I overlooked this part on my first A_ChangeModel fix --- src/common/engine/serializer.cpp | 15 +++++++++ src/common/engine/serializer.h | 12 ++++++++ src/common/models/model.cpp | 5 ++- src/common/models/model.h | 5 ++- src/g_game.cpp | 8 ----- src/p_saveg.cpp | 3 +- src/playsim/actor.h | 26 +++++++++++----- src/playsim/p_actionfunctions.cpp | 51 ------------------------------- src/playsim/p_mobj.cpp | 44 ++++++++++++++++++++++++-- src/r_data/models.cpp | 2 +- 10 files changed, 95 insertions(+), 76 deletions(-) diff --git a/src/common/engine/serializer.cpp b/src/common/engine/serializer.cpp index 261aa464cbd..dcf93084287 100644 --- a/src/common/engine/serializer.cpp +++ b/src/common/engine/serializer.cpp @@ -294,6 +294,21 @@ bool FSerializer::BeginObject(const char *name) // //========================================================================== +bool FSerializer::HasKey(const char* name) +{ + if (isReading()) + { + return r->FindKey(name) != nullptr; + } + return false; +} + +//========================================================================== +// +// +// +//========================================================================== + bool FSerializer::HasObject(const char* name) { if (isReading()) diff --git a/src/common/engine/serializer.h b/src/common/engine/serializer.h index 29677237b5e..ae25853d948 100644 --- a/src/common/engine/serializer.h +++ b/src/common/engine/serializer.h @@ -91,6 +91,7 @@ class FSerializer void ReadObjects(bool hubtravel); bool BeginObject(const char *name); void EndObject(); + bool HasKey(const char* name); bool HasObject(const char* name); bool BeginArray(const char *name); void EndArray(); @@ -245,6 +246,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FSoundID &sid, FSoundI FSerializer &Serialize(FSerializer &arc, const char *key, FString &sid, FString *def); FSerializer &Serialize(FSerializer &arc, const char *key, NumericValue &sid, NumericValue *def); FSerializer &Serialize(FSerializer &arc, const char *key, struct ModelOverride &mo, struct ModelOverride *def); +FSerializer &Serialize(FSerializer &arc, const char *key, struct AnimModelOverride &mo, struct AnimModelOverride *def); FSerializer &Serialize(FSerializer &arc, const char *key, struct AnimOverride &ao, struct AnimOverride *def); FSerializer& Serialize(FSerializer& arc, const char* key, FTranslationID& value, FTranslationID* defval); @@ -259,6 +261,16 @@ FSerializer &Serialize(FSerializer &arc, const char *key, T *&value, T **) return arc; } +template +FSerializer &Serialize(FSerializer &arc, const char *key, std::pair &value, std::pair *def) +{ + arc.BeginObject(key); + Serialize(arc, "first", value.first, def ? &def->first : nullptr); + Serialize(arc, "second", value.second, def ? &def->second : nullptr); + arc.EndObject(); + return arc; +} + template FSerializer &Serialize(FSerializer &arc, const char *key, TArray &value, TArray *def) { diff --git a/src/common/models/model.cpp b/src/common/models/model.cpp index a8ee8958f8c..0f160341588 100644 --- a/src/common/models/model.cpp +++ b/src/common/models/model.cpp @@ -43,8 +43,6 @@ #include "texturemanager.h" #include "modelrenderer.h" - -TArray savedModelFiles; TDeletingArray Models; TArray SpriteModelFrames; TMap BaseSpriteModelFrames; @@ -160,7 +158,7 @@ unsigned FindModel(const char * path, const char * modelfile, bool silent) for(unsigned i = 0; i< Models.Size(); i++) { - if (!Models[i]->mFileName.CompareNoCase(fullname)) return i; + if (Models[i]->mFileName.CompareNoCase(fullname) == 0) return i; } auto len = fileSystem.FileLength(lump); @@ -236,6 +234,7 @@ unsigned FindModel(const char * path, const char * modelfile, bool silent) } // The vertex buffer cannot be initialized here because this gets called before OpenGL is initialized model->mFileName = fullname; + model->mFilePath = {path, modelfile}; return Models.Push(model); } diff --git a/src/common/models/model.h b/src/common/models/model.h index f5bbf43db0e..7d5746e3317 100644 --- a/src/common/models/model.h +++ b/src/common/models/model.h @@ -18,7 +18,7 @@ struct FSpriteModelFrame; FTextureID LoadSkin(const char* path, const char* fn); void FlushModels(); -extern TArray savedModelFiles; + extern TDeletingArray Models; extern TArray SpriteModelFrames; extern TMap BaseSpriteModelFrames; @@ -76,6 +76,7 @@ enum EFrameError class FModel { public: + FModel(); virtual ~FModel(); @@ -100,7 +101,9 @@ class FModel void DestroyVertexBuffer(); bool hasSurfaces = false; + FString mFileName; + std::pair mFilePath; FSpriteModelFrame *baseFrame; private: diff --git a/src/g_game.cpp b/src/g_game.cpp index 1b81ae6b064..752b8f930fe 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -2148,14 +2148,6 @@ void G_DoLoadGame () BackupSaveName = savename; - //Push any added models from A_ChangeModel - for (auto& smf : savedModelFiles) - { - FString modelFilePath = smf.Left(smf.LastIndexOf("/")+1); - FString modelFileName = smf.Right(smf.Len() - smf.Left(smf.LastIndexOf("/") + 1).Len()); - FindModel(modelFilePath.GetChars(), modelFileName.GetChars()); - } - // At this point, the GC threshold is likely a lot higher than the // amount of memory in use, so bring it down now by starting a // collection. diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index 865810cdc75..de4f7c1c1e7 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -1013,8 +1013,7 @@ void FLevelLocals::Serialize(FSerializer &arc, bool hubload) ("scrolls", Scrolls) ("automap", automap) ("interpolator", interpolator) - ("frozenstate", frozenstate) - ("savedModelFiles", savedModelFiles); + ("frozenstate", frozenstate); // Hub transitions must keep the current total time diff --git a/src/playsim/actor.h b/src/playsim/actor.h index 59ad5606056..c9465dbbf7b 100644 --- a/src/playsim/actor.h +++ b/src/playsim/actor.h @@ -719,6 +719,16 @@ struct ModelOverride TArray surfaceSkinIDs; }; +struct AnimModelOverride +{ + int id; + + AnimModelOverride() = default; + + AnimModelOverride(int i) : id(i) {} + operator int() { return id; } +}; + enum EModelDataFlags { MODELDATA_HADMODEL = 1 << 0, @@ -729,14 +739,14 @@ class DActorModelData : public DObject { DECLARE_CLASS(DActorModelData, DObject); public: - PClass * modelDef; - TArray models; - TArray skinIDs; - TArray animationIDs; - TArray modelFrameGenerators; - int flags; - int overrideFlagsSet; - int overrideFlagsClear; + PClass * modelDef; + TArray models; + TArray skinIDs; + TArray animationIDs; + TArray modelFrameGenerators; + int flags; + int overrideFlagsSet; + int overrideFlagsClear; AnimOverride curAnim; AnimOverride prevAnim; // used for interpolation when switching anims diff --git a/src/playsim/p_actionfunctions.cpp b/src/playsim/p_actionfunctions.cpp index 410ac6a534d..8ab0a021366 100644 --- a/src/playsim/p_actionfunctions.cpp +++ b/src/playsim/p_actionfunctions.cpp @@ -5438,57 +5438,6 @@ void ChangeModelNative( } } - //[SM] - We need to serialize file paths and model names so that they are pushed on loading save files. Likewise, let's not include models that were already parsed when initialized. - if (queryModel >= 0) - { - FString fullName; - fullName.Format("%s%s", modelpath.GetChars(), model.GetChars()); - bool found = false; - - for (auto &m : savedModelFiles) - { - if(m.CompareNoCase(fullName) == 0) - { - found = true; - break; - } - } - if(!found) for (auto &m : Models) - { - if (m->mFileName.CompareNoCase(fullName) == 0) - { - found = true; - break; - } - } - if(!found) savedModelFiles.Push(fullName); - } - //Same for animations - if (queryAnimation >= 0) - { - FString fullName; - fullName.Format("%s%s", animationpath.GetChars(), animation.GetChars()); - bool found = false; - - for (auto &m : savedModelFiles) - { - if(m.CompareNoCase(fullName) == 0) - { - found = true; - break; - } - } - if(!found) for (auto &m : Models) - { - if (m->mFileName.CompareNoCase(fullName) == 0) - { - found = true; - break; - } - } - if(!found) savedModelFiles.Push(fullName); - } - CleanupModelData(mobj); return; diff --git a/src/playsim/p_mobj.cpp b/src/playsim/p_mobj.cpp index ff98fb4da46..eda2a46e1e9 100644 --- a/src/playsim/p_mobj.cpp +++ b/src/playsim/p_mobj.cpp @@ -101,6 +101,7 @@ #include "fragglescript/t_fs.h" #include "shadowinlines.h" #include "d_net.h" +#include "model.h" // MACROS ------------------------------------------------------------------ @@ -1387,18 +1388,57 @@ bool AActor::Massacre () // //---------------------------------------------------------------------------- +void SerializeModelID(FSerializer &arc, const char *key, int &id) +{ // TODO: make it a proper serializable type (FModelID) instead of an int + if(arc.isWriting()) + { + if(id >= 0) + { + arc(key, Models[id]->mFilePath); + } + } + else + { + if(arc.HasKey(key)) + { + std::pair modelFile; + arc(key, modelFile); + + id = FindModel(modelFile.first.GetChars(), modelFile.second.GetChars(), true); + } + else + { + id = -1; + } + } +} + FSerializer &Serialize(FSerializer &arc, const char *key, ModelOverride &mo, ModelOverride *def) { arc.BeginObject(key); - arc("modelID", mo.modelID); + SerializeModelID(arc, "model", mo.modelID); arc("surfaceSkinIDs", mo.surfaceSkinIDs); arc.EndObject(); return arc; } +FSerializer &Serialize(FSerializer &arc, const char *key, AnimModelOverride &amo, AnimModelOverride *def) +{ + int ok = arc.BeginObject(key); + if(arc.isReading() && !ok) + { + amo.id = -1; + } + else if(ok) + { + SerializeModelID(arc, "model", amo.id); + arc.EndObject(); + } + return arc; +} + FSerializer &Serialize(FSerializer &arc, const char *key, struct AnimOverride &ao, struct AnimOverride *def) { - //TODO arc.BeginObject(key); arc("firstFrame", ao.firstFrame); arc("lastFrame", ao.lastFrame); diff --git a/src/r_data/models.cpp b/src/r_data/models.cpp index 09010c19548..d2436fc6789 100644 --- a/src/r_data/models.cpp +++ b/src/r_data/models.cpp @@ -506,7 +506,7 @@ void RenderFrameModels(FModelRenderer *renderer, FLevelLocals *Level, const FSpr skinid = smf->skinIDs[i]; } - if (modelid >= 0) + if (modelid >= 0 && modelid < Models.size()) { FModel * mdl = Models[modelid]; auto tex = skinid.isValid() ? TexMan.GetGameTexture(skinid, true) : nullptr;