diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 55183af61..cd08d9e1c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1124,6 +1124,7 @@ set (PCH_SOURCES po_man.cpp portal.cpp r_utility.cpp + serializer.cpp sc_man.cpp st_stuff.cpp statistics.cpp @@ -1414,6 +1415,7 @@ source_group("Games\\Strife Game" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DI source_group("Intermission" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/intermission/.+") source_group("Math" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/math/.+") source_group("Menu" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/menu/.+") +source_group("RapidJSON" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rapidjson/.+") source_group("Render Core\\Render Headers" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/r_.+\\.h$") source_group("Render Core\\Render Sources" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/r_.+\\.cpp$") source_group("Render Data\\Resource Headers" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/r_data/.+\\.h$") diff --git a/src/dobject.h b/src/dobject.h index 787a07359..7f177c8d4 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -416,6 +416,8 @@ public: template friend inline FArchive &operator<<(FArchive &arc, TObjPtr &o); template friend inline void GC::Mark(TObjPtr &obj); + template friend FSerializer &Serialize(FSerializer &arc, const char *key, TObjPtr &value, TObjPtr *); + friend class DObject; }; diff --git a/src/info.cpp b/src/info.cpp index 7198a5de4..f70124f8b 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -375,6 +375,9 @@ void PClassActor::InitializeNativeDefaults() else { memset (Defaults, 0, Size); + // Non-DECORATE properties that must be set. + ((AActor*)Defaults)->DamageMultiply = 1.; // fixme: Make this a DECORATE property. + ((AActor*)Defaults)->ConversationRoot = -1; } } diff --git a/src/json.cpp b/src/json.cpp index fe4a2d5d4..7dd969daa 100644 --- a/src/json.cpp +++ b/src/json.cpp @@ -1,353 +1,33 @@ -#define RAPIDJSON_48BITPOINTER_OPTIMIZATION 0 // disable this insanity which is bound to make the code break over time. -#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1 -#define RAPIDJSON_HAS_CXX11_RANGE_FOR 1 - -//#define PRETTY - -#include "rapidjson/rapidjson.h" -#include "rapidjson/writer.h" -#include "rapidjson/prettywriter.h" -#include "rapidjson/stringbuffer.h" -#include "rapidjson/document.h" -#include "r_defs.h" +#include "serializer.h" #include "r_local.h" -#include "p_lnspec.h" -#include "i_system.h" -#include "w_wad.h" -#include "p_terrain.h" -#include "c_dispatch.h" #include "p_setup.h" -#include "p_conversation.h" -#include "dsectoreffect.h" -#include "actor.h" -#include "r_data/r_interpolate.h" -#include "g_shared/a_sharedglobal.h" - -TArray loadsectors; -TArray loadlines; -TArray loadsides; +#include "c_dispatch.h" +#include "i_system.h" +#include "a_sharedglobal.h" //========================================================================== // // // //========================================================================== -FSerializer &Serialize(FSerializer &arc, const char *key, FName &value); - -//========================================================================== -// -// -// -//========================================================================== -typedef rapidjson::Value FJSONValue; - -struct FJSONObject +FSerializer &Serialize(FSerializer &arc, const char *key, line_t &line, line_t *def) { - rapidjson::Value *mObject; - rapidjson::Value::MemberIterator mIterator; - - FJSONObject(rapidjson::Value *v) + if (arc.BeginObject(key)) { - mObject = v; - mIterator = v->MemberEnd(); + arc("flags", line.flags, def->flags) + ("activation", line.activation, def->activation) + ("special", line.special, def->special) + ("alpha", line.alpha, def->alpha) + .Args("args", line.args, def->args, line.special) + ("portalindex", line.portalindex, def->portalindex) + // no need to store the sidedef references. Unless the map loader is changed they will not change between map loads. + //.Array("sides", line.sidedef, 2) + .EndObject(); } -}; + return arc; - - -class FSerializer -{ -#ifndef PRETTY - typedef rapidjson::Writer > Writer; -#else - typedef rapidjson::PrettyWriter > Writer; -#endif - -public: - Writer *mWriter = nullptr; - TArray mInObject; - rapidjson::StringBuffer mOutString; - TArray mDObjects; - TMap mObjectMap; - TArray mObjects; - rapidjson::Value mDocObj; // just because RapidJSON is stupid and does not allow direct access to what's in the document. - - int ArraySize() - { - if (mObjects.Last().mObject->IsArray()) - { - return mObjects.Last().mObject->Size(); - } - else - { - return 0; - } - } - - rapidjson::Value *FindKey(const char *key) - { - FJSONObject &obj = mObjects.Last(); - if (obj.mObject->IsObject()) - { - // This will continue the search from the last found key, assuming - // that key are being read in the same order in which they were written. - // As long as this is the case this will reduce time here significantly. - // Do at most as many iterations as the object has members. Otherwise the key cannot be present. - for (rapidjson::SizeType i = 0; i < obj.mObject->MemberCount(); i++) - { - if (obj.mIterator == obj.mObject->MemberEnd()) obj.mIterator = obj.mObject->MemberBegin(); - else obj.mIterator++; - if (!strcmp(key, obj.mIterator->name.GetString())) - { - return &obj.mIterator->value; - } - } - } - else if (obj.mObject->IsArray()) - { - // todo: Get element at current index and increment. - } - return nullptr; - } - -public: - - bool OpenWriter(bool pretty) - { - if (mWriter != nullptr || mObjects.Size() > 0) - { - return false; - } - mWriter = new Writer(mOutString); - return true; - } - - bool OpenReader(rapidjson::Document *doc) - { - if (mWriter != nullptr || mObjects.Size() > 0 || !doc->IsObject()) - { - return false; - } - mDocObj = doc->GetObject(); - mObjects.Push(FJSONObject(&mDocObj)); - return true; - } - - bool isReading() const - { - return mWriter == nullptr; - } - - bool isWriting() const - { - return mWriter != nullptr; - } - - void WriteKey(const char *key) - { - if (mInObject.Size() > 0 && mInObject.Last()) - { - mWriter->Key(key); - } - } - - FSerializer &BeginObject(const char *name) - { - if (isWriting()) - { - WriteKey(name); - mWriter->StartObject(); - mInObject.Push(true); - } - else - { - auto val = FindKey(name); - if (val != nullptr) - { - if (val->IsObject()) - { - mObjects.Push(FJSONObject(val)); - } - else - { - I_Error("Object expected for '%s'", name); - } - } - else - { - I_Error("'%s' not found", name); - } - } - return *this; - } - - FSerializer &EndObject() - { - if (isWriting()) - { - mWriter->EndObject(); - mInObject.Pop(); - } - else - { - mObjects.Pop(); - } - return *this; - } - - bool BeginArray(const char *name) - { - if (isWriting()) - { - WriteKey(name); - mWriter->StartArray(); - mInObject.Push(false); - } - else - { - auto val = FindKey(name); - if (val != nullptr) - { - if (val->IsArray()) - { - mObjects.Push(FJSONObject(val)); - } - else - { - I_Error("Array expected for '%s'", name); - } - } - else - { - return false; - } - } - return true; - } - - FSerializer &EndArray() - { - if (isWriting()) - { - mWriter->EndArray(); - mInObject.Pop(); - } - else - { - mObjects.Pop(); - } - return *this; - } - - - //========================================================================== - // - // Special handler for args (because ACS specials' arg0 needs special treatment.) - // - //========================================================================== - - FSerializer &Args(const char *key, int *args, int special) - { - if (isWriting()) - { - WriteKey(key); - mWriter->StartArray(); - for (int i = 0; i < 5; i++) - { - if (i == 0 && args[i] < 0 && P_IsACSSpecial(special)) - { - mWriter->String(FName(ENamedName(-args[i])).GetChars()); - } - else - { - mWriter->Int(args[i]); - } - } - mWriter->EndArray(); - } - else - { - auto val = FindKey(key); - if (val != nullptr) - { - if (val->IsArray()) - { - unsigned int cnt = MIN(val->Size(), 5); - for (unsigned int i = 0; i < cnt; i++) - { - const rapidjson::Value &aval = (*val)[i]; - if (aval.IsInt()) - { - args[i] = aval.GetInt(); - } - else if (i == 0 && aval.IsString()) - { - args[i] = -FName(aval.GetString()); - } - else - { - I_Error("Integer expected for '%s[%d]'", key, i); - } - } - } - } - else - { - I_Error("array expected for '%s'", key); - } - } - return *this; - } - - template - FSerializer &operator()(const char *key, T &obj) - { - return Serialize(*this, key, obj); - } - - template - FSerializer &operator()(const char *key, T &obj, T & def) - { - if (isWriting() && !memcmp(&obj, &def, sizeof(T))) return *this; - return Serialize(*this, key, obj); - } - - template - FSerializer &Array(const char *key, T *obj, int count) - { - if (BeginArray(key)) - { - for (int i = 0; i < count; i++) - { - Serialize(*this, nullptr, obj[i]); - } - EndArray(); - } - return *this; - } - - FSerializer &Terrain(const char *key, int &terrain) - { - FName terr = P_GetTerrainName(terrain); - Serialize(*this, key, terr); - if (isReading()) - { - terrain = P_FindTerrain(terr); - } - return *this; - } - - FSerializer &Sprite(const char *key, uint16_t &spritenum) - { - if (isWriting()) - { - WriteKey(key); - mWriter->String(sprites[spritenum].name, 4); - } - return *this; - } -}; +} //========================================================================== // @@ -355,26 +35,119 @@ public: // //========================================================================== -FSerializer &Serialize(FSerializer &arc, const char *key, bool &value) +FSerializer &Serialize(FSerializer &arc, const char *key, side_t::part &part, side_t::part *def) { - if (arc.isWriting()) + if (arc.canSkip() && def != nullptr && !memcmp(&part, def, sizeof(part))) { - arc.WriteKey(key); - arc.mWriter->Bool(value); + return arc; } - else + + if (arc.BeginObject(key)) { - auto val = arc.FindKey(key); - if (val != nullptr) + arc("xoffset", part.xOffset, def->xOffset) + ("yoffset", part.yOffset, def->yOffset) + ("xscale", part.xScale, def->xScale) + ("yscale", part.yScale, def->yScale) + ("texture", part.texture, def->texture) + ("interpolation", part.interpolation) + .EndObject(); + } + return arc; +} + +//========================================================================== +// +// +// +//========================================================================== + +FSerializer &Serialize(FSerializer &arc, const char *key, side_t &side, side_t *def) +{ + if (arc.BeginObject(key)) + { + arc.Array("textures", side.textures, def->textures, 3, true) + ("light", side.Light, def->Light) + ("flags", side.Flags, def->Flags) + //("leftside", side.LeftSide) + //("rightside", side.RightSide) + //("index", side.Index) + ("attacheddecals", side.AttachedDecals) + .EndObject(); + } + return arc; +} + +//========================================================================== +// +// +// +//========================================================================== + +FSerializer &Serialize(FSerializer &arc, const char *key, FLinkedSector &ls, FLinkedSector *def) +{ + if (arc.BeginObject(key)) + { + arc("sector", ls.Sector) + ("type", ls.Type) + .EndObject(); + } + return arc; +} + +//========================================================================== +// +// +// +//========================================================================== + +FSerializer &Serialize(FSerializer &arc, const char *key, sector_t::splane &p, sector_t::splane *def) +{ + if (arc.canSkip() && def != nullptr && !memcmp(&p, def, sizeof(p))) + { + return arc; + } + + if (arc.BeginObject(key)) + { + arc("xoffs", p.xform.xOffs, def->xform.xOffs) + ("yoffs", p.xform.yOffs, def->xform.yOffs) + ("xscale", p.xform.xScale, def->xform.xScale) + ("yscale", p.xform.yScale, def->xform.yScale) + ("angle", p.xform.Angle, def->xform.Angle) + ("baseyoffs", p.xform.baseyOffs, def->xform.baseyOffs) + ("baseangle", p.xform.baseAngle, def->xform.baseAngle) + ("flags", p.Flags, def->Flags) + ("light", p.Light, def->Light) + ("texture", p.Texture, def->Texture) + ("texz", p.TexZ, def->TexZ) + ("alpha", p.alpha, def->alpha) + .EndObject(); + } + return arc; +} + +//========================================================================== +// +// +// +//========================================================================== + +FSerializer &Serialize(FSerializer &arc, const char *key, secplane_t &p, secplane_t *def) +{ + if (arc.canSkip() && def != nullptr && !memcmp(&p, def, sizeof(p))) + { + return arc; + } + + if (arc.BeginObject(key)) + { + arc("normal", p.normal, def->normal) + ("d", p.D, def->D) + .EndObject(); + + if (arc.isReading() && p.normal.Z != 0) { - if (val->IsBool()) - { - value = val->GetBool(); - } - else - { - I_Error("boolean type expected for '%s'", key); - } + p.negiC = 1 / p.normal.Z; } } return arc; @@ -386,664 +159,62 @@ FSerializer &Serialize(FSerializer &arc, const char *key, bool &value) // //========================================================================== -FSerializer &Serialize(FSerializer &arc, const char *key, int64_t &value) +FSerializer &Serialize(FSerializer &arc, const char *key, sector_t &p, sector_t *def) { - if (arc.isWriting()) + if (arc.BeginObject(key)) { - arc.WriteKey(key); - arc.mWriter->Int64(value); - } - else - { - auto val = arc.FindKey(key); - if (val != nullptr) - { - if (val->IsInt64()) - { - value = val->GetInt64(); - } - else - { - I_Error("integer type expected for '%s'", key); - } - } - } - return arc; -} - -//========================================================================== -// -// -// -//========================================================================== - -FSerializer &Serialize(FSerializer &arc, const char *key, uint64_t &value) -{ - if (arc.isWriting()) - { - arc.WriteKey(key); - arc.mWriter->Uint64(value); - } - else - { - auto val = arc.FindKey(key); - if (val != nullptr) - { - if (val->IsUint64()) - { - value = val->GetUint64(); - } - else - { - I_Error("integer type expected for '%s'", key); - } - } + arc("floorplane", p.floorplane, def->floorplane) + ("ceilingplane", p.ceilingplane, def->ceilingplane) + ("lightlevel", p.lightlevel, def->lightlevel) + ("special", p.special, def->special) + ("soundtraversed", p.soundtraversed, def->soundtraversed) + ("seqtype", p.seqType, def->seqType) + ("seqname", p.SeqName, def->SeqName) + ("friction", p.friction, def->friction) + ("movefactor", p.movefactor, def->movefactor) + ("stairlock", p.stairlock, def->stairlock) + ("prevsec", p.prevsec, def->prevsec) + ("nextsec", p.nextsec, def->nextsec) + .Array("planes", p.planes, def->planes, 2, true) + //("heightsec", p.heightsec) + //("bottommap", p.bottommap) + //("midmap", p.midmap) + //("topmap", p.topmap) + ("damageamount", p.damageamount, def->damageamount) + ("damageinterval", p.damageinterval, def->damageinterval) + ("leakydamage", p.leakydamage, def->leakydamage) + ("damagetype", p.damagetype, def->damagetype) + ("sky", p.sky, def->sky) + ("moreflags", p.MoreFlags, def->MoreFlags) + ("flags", p.Flags, def->Flags) + .Array("portals", p.Portals, def->Portals, 2, true) + ("zonenumber", p.ZoneNumber, def->ZoneNumber) + .Array("interpolations", p.interpolations, 4, true) + ("soundtarget", p.SoundTarget) + ("secacttarget", p.SecActTarget) + ("floordata", p.floordata) + ("ceilingdata", p.ceilingdata) + ("lightingdata", p.lightingdata) + ("fakefloor_sectors", p.e->FakeFloor.Sectors) + ("midtexf_lines", p.e->Midtex.Floor.AttachedLines) + ("midtexf_sectors", p.e->Midtex.Floor.AttachedSectors) + ("midtexc_lines", p.e->Midtex.Ceiling.AttachedLines) + ("midtexc_sectors", p.e->Midtex.Ceiling.AttachedSectors) + ("linked_floor", p.e->Linked.Floor.Sectors) + ("linked_ceiling", p.e->Linked.Ceiling.Sectors) + ("colormap", p.ColorMap, def->ColorMap) + .Terrain("floorterrain", p.terrainnum[0], &def->terrainnum[0]) + .Terrain("ceilingterrain", p.terrainnum[1], &def->terrainnum[1]) + .EndObject(); } return arc; } -//========================================================================== -// -// -// -//========================================================================== - -FSerializer &Serialize(FSerializer &arc, const char *key, int32_t &value) -{ - if (arc.isWriting()) - { - arc.WriteKey(key); - arc.mWriter->Int(value); - } - else - { - auto val = arc.FindKey(key); - if (val != nullptr) - { - if (val->IsInt()) - { - value = val->GetInt(); - } - else - { - I_Error("integer type expected for '%s'", key); - } - } - } - return arc; -} - -//========================================================================== -// -// -// -//========================================================================== - -FSerializer &Serialize(FSerializer &arc, const char *key, uint32_t &value) -{ - if (arc.isWriting()) - { - arc.WriteKey(key); - arc.mWriter->Uint(value); - } - else - { - auto val = arc.FindKey(key); - if (val != nullptr) - { - if (val->IsUint()) - { - value = val->GetUint(); - } - else - { - I_Error("integer type expected for '%s'", key); - } - } - } - return arc; -} - - -//========================================================================== -// -// -// -//========================================================================== - -FSerializer &Serialize(FSerializer &arc, const char *key, int8_t &value) -{ - int32_t vv = value; - Serialize(arc, key, vv); - value = (int8_t)vv; - return arc; -} - -FSerializer &Serialize(FSerializer &arc, const char *key, uint8_t &value) -{ - uint32_t vv = value; - Serialize(arc, key, vv); - value = (uint8_t)vv; - return arc; -} - -FSerializer &Serialize(FSerializer &arc, const char *key, int16_t &value) -{ - int32_t vv = value; - Serialize(arc, key, vv); - value = (int16_t)vv; - return arc; -} - -FSerializer &Serialize(FSerializer &arc, const char *key, uint16_t &value) -{ - uint32_t vv = value; - Serialize(arc, key, vv); - value = (uint16_t)vv; - return arc; -} - -//========================================================================== -// -// -// -//========================================================================== - -FSerializer &Serialize(FSerializer &arc, const char *key, double &value) -{ - if (arc.isWriting()) - { - arc.WriteKey(key); - arc.mWriter->Double(value); - } - else - { - auto val = arc.FindKey(key); - if (val != nullptr) - { - if (val->IsDouble()) - { - value = val->GetDouble(); - } - else - { - I_Error("float type expected for '%s'", key); - } - } - } - return arc; -} - -//========================================================================== -// -// -// -//========================================================================== - -FSerializer &Serialize(FSerializer &arc, const char *key, float &value) -{ - double vv = value; - Serialize(arc, key, vv); - value = (float)vv; - return arc; -} - -//========================================================================== -// -// -// -//========================================================================== - -FSerializer &Serialize(FSerializer &arc, const char *key, side_t *&value) -{ - ptrdiff_t vv = value == nullptr? -1 : value - sides; - Serialize(arc, key, vv); - value = vv < 0 ? nullptr : sides + vv; - return arc; -} - -//========================================================================== -// -// -// -//========================================================================== - -FSerializer &Serialize(FSerializer &arc, const char *key, sector_t *&value) -{ - ptrdiff_t vv = value == nullptr ? -1 : value - sectors; - Serialize(arc, key, vv); - value = vv < 0 ? nullptr : sectors + vv; - return arc; -} - -//========================================================================== -// -// -// -//========================================================================== - -FSerializer &Serialize(FSerializer &arc, const char *key, player_t *&value) -{ - ptrdiff_t vv = value == nullptr ? -1 : value - players; - Serialize(arc, key, vv); - value = vv < 0 ? nullptr : players + vv; - return arc; -} - -//========================================================================== -// -// -// -//========================================================================== - -FSerializer &Serialize(FSerializer &arc, const char *key, line_t *&value) -{ - ptrdiff_t vv = value == nullptr ? -1 : value - lines; - Serialize(arc, key, vv); - value = vv < 0 ? nullptr : lines + vv; - return arc; -} - -//========================================================================== -// -// -// -//========================================================================== - -FSerializer &Serialize(FSerializer &arc, const char *key, FTextureID &value) -{ - if (arc.isWriting()) - { - if (!value.Exists()) - { - arc.WriteKey(key); - arc.mWriter->Null(); - return arc; - } - if (value.isNull()) - { - // save 'no texture' in a more space saving way - arc.WriteKey(key); - arc.mWriter->Int(0); - return arc; - } - FTextureID chk = value; - if (chk.GetIndex() >= TexMan.NumTextures()) chk.SetNull(); - FTexture *pic = TexMan[chk]; - const char *name; - - if (Wads.GetLinkedTexture(pic->SourceLump) == pic) - { - name = Wads.GetLumpFullName(pic->SourceLump); - } - else - { - name = pic->Name; - } - arc.WriteKey(key); - arc.mWriter->StartObject(); - arc.mWriter->Key("name"); - arc.mWriter->String(name); - arc.mWriter->Key("usetype"); - arc.mWriter->Int(pic->UseType); - arc.mWriter->EndObject(); - } - else - { - auto val = arc.FindKey(key); - if (val != nullptr) - { - if (val->IsObject()) - { - const rapidjson::Value &nameval = (*val)["name"]; - const rapidjson::Value &typeval = (*val)["type"]; - if (nameval.IsString() && typeval.IsInt()) - { - value = TexMan.GetTexture(nameval.GetString(), typeval.GetInt()); - } - else - { - I_Error("object does not represent a texture for '%s'", key); - } - } - else if (val->IsNull()) - { - value.SetInvalid(); - } - else if (val->IsInt() && val->GetInt() == 0) - { - value.SetNull(); - } - else - { - I_Error("object does not represent a texture for '%s'", key); - } - } - } - return arc; -} - -//========================================================================== -// -// -// -//========================================================================== - -FSerializer &Serialize(FSerializer &arc, const char *key, DObject *&value) -{ - if (arc.isWriting()) - { - if (value != nullptr) - { - int ndx; - int *pndx = arc.mObjectMap.CheckKey(value); - if (pndx != nullptr) ndx = *pndx; - else - { - ndx = arc.mDObjects.Push(value); - arc.mObjectMap[value] = ndx; - } - Serialize(arc, key, ndx); - } - } - else - { - auto val = arc.FindKey(key); - if (val != nullptr) - { - } - else - { - value = nullptr; - } - } - return arc; -} - -template -FSerializer &Serialize(FSerializer &arc, const char *key, T *&value) -{ - DObject *v = static_cast(value); - Serialize(arc, key, v); - value = static_cast(v); - return arc; -} - -template -FSerializer &Serialize(FSerializer &arc, const char *key, TObjPtr &value) -{ - DObject *v = static_cast(value); - Serialize(arc, key, v); - value = static_cast(v); - return arc; -} - -template -FSerializer &Serialize(FSerializer &arc, const char *key, TArray &value) -{ - if (arc.isWriting()) - { - if (value.Size() == 0) return arc; // do not save empty arrays - } - bool res = arc.BeginArray(key); - if (arc.isReading()) - { - if (!res) - { - value.Clear(); - return arc; - } - value.Resize(arc.ArraySize()); - } - for (unsigned i = 0; i < value.Size(); i++) - { - Serialize(arc, nullptr, value[i]); - } - return arc.EndArray(); -} - -FSerializer &Serialize(FSerializer &arc, const char *key, DVector3 &p) -{ - return arc.Array(key, &p[0], 3); -} - -FSerializer &Serialize(FSerializer &arc, const char *key, DRotator &p) -{ - return arc.Array(key, &p[0], 3); -} - -FSerializer &Serialize(FSerializer &arc, const char *key, DVector2 &p) -{ - return arc.Array(key, &p[0], 2); -} - -FSerializer &Serialize(FSerializer &arc, const char *key, DAngle &p) -{ - return Serialize(arc, key, p.Degrees); -} - -FSerializer &Serialize(FSerializer &arc, const char *key, FName &value) -{ - if (arc.isWriting()) - { - arc.WriteKey(key); - arc.mWriter->String(value.GetChars()); - } - else - { - auto val = arc.FindKey(key); - if (val != nullptr) - { - if (val->IsString()) - { - value = val->GetString(); - } - else - { - I_Error("String expected for '%s'", key); - } - } - } - return arc; -} - - -//========================================================================== -// -// -// -//========================================================================== - -FSerializer &Serialize(FSerializer &arc, const char *key, line_t &line) -{ - return arc.BeginObject(key) - ("flags", line.flags) - ("activation", line.activation) - ("special", line.special) - ("alpha", line.alpha) - .Args("args", line.args, line.special) - ("portalindex", line.portalindex) - //.Array("sides", line.sidedef, 2) - .EndObject(); - - // no need to store the sidedef references. Unless the map loader is changed they will not change between map loads. -} - -//========================================================================== -// -// -// -//========================================================================== - -FSerializer &Serialize(FSerializer &arc, const char *key, side_t::part &part) -{ - return arc.BeginObject(key) - ("xoffset", part.xOffset) - ("yoffset", part.yOffset) - ("xscale", part.xScale) - ("yscale", part.yScale) - ("texture", part.texture) - ("interpolation", part.interpolation) - .EndObject(); -} - -//========================================================================== -// -// -// -//========================================================================== - -FSerializer &Serialize(FSerializer &arc, const char *key, side_t &side) -{ - return arc.BeginObject(key) - .Array("textures", side.textures, 3) - ("light", side.Light) - ("flags", side.Flags) - //("leftside", side.LeftSide) - //("rightside", side.RightSide) - //("index", side.Index) - ("attacheddecals", side.AttachedDecals) - .EndObject(); -} - -FSerializer &Serialize(FSerializer &arc, const char *key, FLinkedSector &ls) -{ - return arc.BeginObject(key) - ("sector", ls.Sector) - ("type", ls.Type) - .EndObject(); -} - -FSerializer &Serialize(FSerializer &arc, const char *key, sector_t::splane &p) -{ - return arc.BeginObject(key) - ("xoffs", p.xform.xOffs) - ("yoffs", p.xform.yOffs) - ("xscale", p.xform.xScale) - ("yscale", p.xform.yScale) - ("angle", p.xform.Angle) - ("baseyoffs", p.xform.baseyOffs) - ("baseangle", p.xform.baseAngle) - ("flags", p.Flags) - ("light", p.Light) - ("texture", p.Texture) - ("texz", p.TexZ) - ("alpha", p.alpha) - .EndObject(); -} - -FSerializer &Serialize(FSerializer &arc, const char *key, secplane_t &p) -{ - arc.BeginObject(key) - ("normal", p.normal) - ("d", p.D) - .EndObject(); - - if (arc.isReading() && p.normal.Z != 0) - { - p.negiC = 1 / p.normal.Z; - } - return arc; -} - -FSerializer &Serialize(FSerializer &arc, const char *key, PalEntry &pe) -{ - return Serialize(arc, key, pe.d); -} - -FSerializer &Serialize(FSerializer &arc, const char *key, FDynamicColormap *&cm) -{ - if (arc.isWriting()) - { - arc.WriteKey(key); - arc.mWriter->StartArray(); - arc.mWriter->Uint(cm->Color); - arc.mWriter->Uint(cm->Fade); - arc.mWriter->Uint(cm->Desaturate); - arc.mWriter->EndArray(); - } - else - { - auto val = arc.FindKey(key); - if (val != nullptr) - { - if (val->IsObject()) - { - const rapidjson::Value &colorval = (*val)[0]; - const rapidjson::Value &fadeval = (*val)[1]; - const rapidjson::Value &desatval = (*val)[2]; - if (colorval.IsUint() && fadeval.IsUint() && desatval.IsUint()) - { - cm = GetSpecialLights(colorval.GetUint(), fadeval.GetUint(), desatval.GetUint()); - } - else - { - I_Error("object does not represent a colormap for '%s'", key); - } - } - else - { - I_Error("object does not represent a colormap for '%s'", key); - } - } - } - return arc; -} - - -FSerializer &Serialize(FSerializer &arc, const char *key, sector_t &p) -{ - return arc.BeginObject(key) - ("floorplane", p.floorplane) - ("ceilingplane", p.ceilingplane) - ("lightlevel", p.lightlevel) - ("special", p.special) - ("soundtraversed", p.soundtraversed) - ("seqtype", p.seqType) - ("seqname", p.SeqName) - ("friction", p.friction) - ("movefactor", p.movefactor) - ("stairlock", p.stairlock) - ("prevsec", p.prevsec) - ("nextsec", p.nextsec) - .Array("planes", p.planes, 2) - //("heightsec", p.heightsec) - //("bottommap", p.bottommap) - //("midmap", p.midmap) - //("topmap", p.topmap) - ("damageamount", p.damageamount) - ("damageinterval", p.damageinterval) - ("leakydamage", p.leakydamage) - ("damagetype", p.damagetype) - ("sky", p.sky) - ("moreflags", p.MoreFlags) - ("flags", p.Flags) - .Array("portals", p.Portals, 2) - ("zonenumber", p.ZoneNumber) - .Array("interpolations", p.interpolations, 4) - ("soundtarget", p.SoundTarget) - ("secacttarget", p.SecActTarget) - ("floordata", p.floordata) - ("ceilingdata", p.ceilingdata) - ("lightingdata", p.lightingdata) - ("fakefloor_sectors", p.e->FakeFloor.Sectors) - ("midtexf_lines", p.e->Midtex.Floor.AttachedLines) - ("midtexf_sectors", p.e->Midtex.Floor.AttachedSectors) - ("midtexc_lines", p.e->Midtex.Ceiling.AttachedLines) - ("midtexc_sectors", p.e->Midtex.Ceiling.AttachedSectors) - ("linked_floor", p.e->Linked.Floor.Sectors) - ("linked_ceiling", p.e->Linked.Ceiling.Sectors) - ("colormap", p.ColorMap) - .Terrain("floorterrain", p.terrainnum[0]) - .Terrain("ceilingterrain", p.terrainnum[1]) - .EndObject(); -} - - -FSerializer &Serialize(FSerializer &arc, const char *key, subsector_t *&ss) +FSerializer &Serialize(FSerializer &arc, const char *key, subsector_t *&ss, subsector_t **) { BYTE by; + const char *str; if (arc.isWriting()) { @@ -1068,26 +239,37 @@ FSerializer &Serialize(FSerializer &arc, const char *key, subsector_t *&ss) else if (by == 63) by = '+'; encoded[p++] = by; } - arc.mWriter->Key(key); - arc.mWriter->StartArray(); - arc.mWriter->Int(numvertexes); - arc.mWriter->Int(numsubsectors); - arc.mWriter->Int(numnodes); - arc.mWriter->String(&encoded[0], (numsubsectors + 5) / 6); - arc.mWriter->EndArray(); + encoded[p] = 0; + str = &encoded[0]; + if (arc.BeginArray(key)) + { + arc(nullptr, numvertexes) + (nullptr, numsubsectors) + .StringPtr(nullptr, str) + .EndArray(); + } } } else { - int num_verts, num_subs, num_nodes; + int num_verts, num_subs; + + if (arc.BeginArray(key)) + { + arc(nullptr, num_verts) + (nullptr, num_subs) + .StringPtr(nullptr, str) + .EndArray(); + } + } return arc; } -FSerializer &Serialize(FSerializer &arc, const char *key, ReverbContainer *&c) +FSerializer &Serialize(FSerializer &arc, const char *key, ReverbContainer *&c, ReverbContainer **def) { int id = (arc.isReading() || c == nullptr) ? 0 : c->ID; - Serialize(arc, key, id); + Serialize(arc, key, id, nullptr); if (arc.isReading()) { c = S_FindEnvironment(id); @@ -1095,9 +277,9 @@ FSerializer &Serialize(FSerializer &arc, const char *key, ReverbContainer *&c) return arc; } -FSerializer &Serialize(FSerializer &arc, const char *key, zone_t &z) +FSerializer &Serialize(FSerializer &arc, const char *key, zone_t &z, zone_t *def) { - return Serialize(arc, key, z.Environment); + return Serialize(arc, key, z.Environment, nullptr); } //============================================================================ @@ -1106,17 +288,20 @@ FSerializer &Serialize(FSerializer &arc, const char *key, zone_t &z) // //============================================================================ -FSerializer &Serialize(FSerializer &arc, const char *key, FLinePortal &port) +FSerializer &Serialize(FSerializer &arc, const char *key, FLinePortal &port, FLinePortal *def) { - return arc.BeginObject(key) - ("origin", port.mOrigin) - ("destination", port.mDestination) - ("displacement", port.mDisplacement) - ("type", port.mType) - ("flags", port.mFlags) - ("defflags", port.mDefFlags) - ("align", port.mAlign) - .EndObject(); + if (arc.BeginObject(key)) + { + arc("origin", port.mOrigin) + ("destination", port.mDestination) + ("displacement", port.mDisplacement) + ("type", port.mType) + ("flags", port.mFlags) + ("defflags", port.mDefFlags) + ("align", port.mAlign) + .EndObject(); + } + return arc; } //============================================================================ @@ -1125,19 +310,22 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FLinePortal &port) // //============================================================================ -FSerializer &Serialize(FSerializer &arc, const char *key, FSectorPortal &port) +FSerializer &Serialize(FSerializer &arc, const char *key, FSectorPortal &port, FSectorPortal *def) { - return arc.BeginObject(key) - ("type", port.mType) - ("flags", port.mFlags) - ("partner", port.mPartner) - ("plane", port.mPlane) - ("origin", port.mOrigin) - ("destination", port.mDestination) - ("displacement", port.mDisplacement) - ("planez", port.mPlaneZ) - ("skybox", port.mSkybox) - .EndObject(); + if (arc.BeginObject(key)) + { + arc("type", port.mType) + ("flags", port.mFlags) + ("partner", port.mPartner) + ("plane", port.mPlane) + ("origin", port.mOrigin) + ("destination", port.mDestination) + ("displacement", port.mDisplacement) + ("planez", port.mPlaneZ) + ("skybox", port.mSkybox) + .EndObject(); + } + return arc; } @@ -1148,7 +336,7 @@ void DThinker::SaveList(FSerializer &arc, DThinker *node) while (!(node->ObjectFlags & OF_Sentinel)) { assert(node->NextThinker != NULL && !(node->NextThinker->ObjectFlags & OF_EuthanizeMe)); - ::Serialize(arc, nullptr, node); + ::Serialize(arc, nullptr, node, nullptr); node = node->NextThinker; } } @@ -1156,9 +344,9 @@ void DThinker::SaveList(FSerializer &arc, DThinker *node) void DThinker::SerializeThinkers(FSerializer &arc, bool hubLoad) { - DThinker *thinker; - BYTE stat; - int statcount; + //DThinker *thinker; + //BYTE stat; + //int statcount; int i; if (arc.isWriting()) @@ -1179,207 +367,12 @@ void DThinker::SerializeThinkers(FSerializer &arc, bool hubLoad) } -FSerializer &Serialize(FSerializer &arc, const char *key, FRenderStyle &style) -{ - return arc.BeginObject(key) - ("blendop", style.BlendOp) - ("srcalpha", style.SrcAlpha) - ("dstalpha", style.DestAlpha) - ("flags", style.Flags) - .EndObject(); -} - -template -FSerializer &Serialize(FSerializer &arc, const char *key, TFlags &flags) -{ - return Serialize(arc, key, flags.Value); -} - -FSerializer &Serialize(FSerializer &arc, const char *key, FSoundID &sid) -{ - if (arc.isWriting()) - { - arc.WriteKey(key); - const char *sn = (const char*)sid; - if (sn != nullptr) arc.mWriter->String(sn); - else arc.mWriter->Null(); - } - else - { - auto val = arc.FindKey(key); - if (val != nullptr) - { - if (val->IsString()) - { - sid = val->GetString(); - } - else if (val->IsNull()) - { - sid = 0; - } - else - { - I_Error("string type expected for '%s'", key); - } - } - } - return arc; - -} - -FSerializer &Serialize(FSerializer &arc, const char *key, FState *&state) -{ - if (arc.isWriting()) - { - arc.WriteKey(key); - if (state == nullptr) - { - arc.mWriter->Null(); - } - else - { - PClassActor *info = FState::StaticFindStateOwner(state); - - if (info != NULL) - { - arc.mWriter->StartArray(); - arc.mWriter->String(info->TypeName.GetChars()); - arc.mWriter->Uint((uint32_t)(state - info->OwnedStates)); - arc.mWriter->EndArray(); - } - else - { - arc.mWriter->Null(); - } - } - } - else - { - auto val = arc.FindKey(key); - if (val != nullptr) - { - if (val->IsNull()) - { - state = nullptr; - } - else if (val->IsArray()) - { - //rapidjson::Value cls = (*val)[0]; - //rapidjson::Value ndx = (*val)[1]; - } - else - { - I_Error("array type expected for '%s'", key); - } - } - } - return arc; - -} - -FSerializer &Serialize(FSerializer &arc, const char *key, FStrifeDialogueNode *&node) -{ - uint32_t convnum; - if (arc.isWriting()) - { - arc.WriteKey(key); - if (node == nullptr) - { - arc.mWriter->Null(); - } - else - { - arc.mWriter->Uint(node->ThisNodeNum); - } - } - else - { - auto val = arc.FindKey(key); - if (val != nullptr) - { - if (val->IsNull()) - { - node = nullptr; - } - else if (val->IsUint()) - { - if (val->GetUint() >= StrifeDialogues.Size()) - { - node = NULL; - } - else - { - node = StrifeDialogues[val->GetUint()]; - } - } - else - { - I_Error("integer expected for '%s'", key); - } - } - } - return arc; - -} - -FSerializer &Serialize(FSerializer &arc, const char *key, FString *&pstr) -{ - uint32_t convnum; - if (arc.isWriting()) - { - arc.WriteKey(key); - if (pstr == nullptr) - { - arc.mWriter->Null(); - } - else - { - arc.mWriter->String(pstr->GetChars()); - } - } - else - { - auto val = arc.FindKey(key); - if (val != nullptr) - { - if (val->IsNull()) - { - pstr = nullptr; - } - else if (val->IsString()) - { - pstr = AActor::mStringPropertyData.Alloc(val->GetString()); - } - else - { - I_Error("string expected for '%s'", key); - } - } - } - return arc; - -} - - -/* -{ -FString tagstr; -if (arc.IsStoring() && Tag != NULL && Tag->Len() > 0) tagstr = *Tag; -arc << tagstr; -if (arc.IsLoading()) -{ -if (tagstr.Len() == 0) Tag = NULL; -else Tag = mStringPropertyData.Alloc(tagstr); -} -} -*/ - void SerializeWorld(FSerializer &arc) { - arc.Array("linedefs", lines, numlines) - .Array("sidedefs", sides, numsides) - .Array("sectors", sectors, numsectors) + arc.Array("linedefs", lines, &loadlines[0], numlines) + .Array("sidedefs", sides, &loadsides[0], numsides) + .Array("sectors", sectors, &loadsectors[0], numsectors) ("subsectors", subsectors) ("zones", Zones) ("lineportals", linePortals) @@ -1390,7 +383,7 @@ void DObject::SerializeUserVars(FSerializer &arc) { PSymbolTable *symt; FName varname; - DWORD count, j; + //DWORD count, j; int *varloc = NULL; symt = &GetClass()->Symbols; @@ -1411,23 +404,6 @@ void DObject::Serialize(FSerializer &arc) ObjectFlags |= OF_SerialSuccess; } -void SerializeObjects(FSerializer &arc) -{ - if (arc.isWriting()) - { - arc.BeginArray("objects"); - for (unsigned i = 0; i < arc.mDObjects.Size(); i++) - { - arc.BeginObject(nullptr); - arc.WriteKey("classtype"); - arc.mWriter->String(arc.mDObjects[i]->GetClass()->TypeName.GetChars()); - arc.mDObjects[i]->Serialize(arc); - arc.EndObject(); - } - arc.EndArray(); - } -} - //========================================================================== // // AActor :: Serialize @@ -1444,7 +420,7 @@ void AActor::Serialize(FSerializer &arc) Super::Serialize(arc); arc - .Sprite("sprite", sprite) + .Sprite("sprite", sprite, &def->sprite) A("pos", __Pos) A("angles", Angles) A("frame", frame) @@ -1471,9 +447,9 @@ void AActor::Serialize(FSerializer &arc) A("ppassheight", projectilepassheight) A("vel", Vel) A("tics", tics) - ("state", state) + A("state", state) ("damage", damage) - .Terrain("floorterrain", floorterrain) + .Terrain("floorterrain", floorterrain, &def->floorterrain) A("projectilekickback", projectileKickback) A("flags", flags) A("flags2", flags2) @@ -1506,7 +482,7 @@ void AActor::Serialize(FSerializer &arc) A("floorclip", Floorclip) A("tid", tid) A("special", special) - .Args("args", args, special) + .Args("args", args, def->args, special) A("accuracy", accuracy) A("stamina", stamina) ("goal", goal) @@ -1568,7 +544,7 @@ void AActor::Serialize(FSerializer &arc) A("pdmgreceived", PoisonDamageReceived) A("pdurreceived", PoisonDurationReceived) A("ppreceived", PoisonPeriodReceived) - A("poisoner", Poisoner) + ("poisoner", Poisoner) A("posiondamage", PoisonDamage) A("poisonduration", PoisonDuration) A("poisonperiod", PoisonPeriod) @@ -1586,7 +562,7 @@ void AActor::Serialize(FSerializer &arc) A("spriteangle", SpriteAngle) A("spriterotation", SpriteRotation) ("alternative", alternative) - ("tag", Tag); + A("tag", Tag); } @@ -1596,24 +572,24 @@ CCMD(writejson) { DWORD t = I_MSTime(); FSerializer arc; - arc.OpenWriter(true); + arc.OpenWriter(); arc.BeginObject(nullptr); DThinker::SerializeThinkers(arc, false); SerializeWorld(arc); - SerializeObjects(arc); + arc.WriteObjects(); arc.EndObject(); DWORD tt = I_MSTime(); Printf("JSON generation took %d ms\n", tt - t); FILE *f = fopen("out.json", "wb"); - fwrite(arc.mOutString.GetString(), 1, arc.mOutString.GetSize(), f); + unsigned siz; + const char *str = arc.GetOutput(&siz); + fwrite(str, 1, siz, f); fclose(f); + /* DWORD ttt = I_MSTime(); Printf("JSON save took %d ms\n", ttt - tt); - rapidjson::Document doc; - doc.Parse(arc.mOutString.GetString()); + FDocument doc(arc.w->mOutString.GetString(), arc.w->mOutString.GetSize()); DWORD tttt = I_MSTime(); Printf("JSON parse took %d ms\n", tttt - ttt); - doc.ParseInsitu((char*)arc.mOutString.GetString()); - DWORD ttttt = I_MSTime(); - Printf("JSON parse insitu took %d ms\n", ttttt - tttt); + */ } diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 6d8ce4418..e4702bf80 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -4118,7 +4118,6 @@ AActor *AActor::StaticSpawn (PClassActor *type, const DVector3 &pos, replace_t a actor->touching_sectorlist = NULL; // NULL head of sector list // phares 3/13/98 if (G_SkillProperty(SKILLP_FastMonsters) && actor->GetClass()->FastSpeed >= 0) actor->Speed = actor->GetClass()->FastSpeed; - actor->DamageMultiply = 1.; // set subsector and/or block links actor->LinkToWorld (SpawningMapThing); diff --git a/src/s_advsound.cpp b/src/s_advsound.cpp index 8bc1b4868..3d0fe1bac 100644 --- a/src/s_advsound.cpp +++ b/src/s_advsound.cpp @@ -2174,7 +2174,7 @@ void AAmbientSound::Tick () loop = CHAN_LOOP; } - if (ambient->sound != 0) + if (ambient->sound != FSoundID(0)) { // The second argument scales the ambient sound's volume. // 0 and 100 are normal volume. The maximum volume level diff --git a/src/s_sound.cpp b/src/s_sound.cpp index 54c8b5cf8..949dee7f8 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -3021,7 +3021,7 @@ CCMD (cachesound) for (int i = 1; i < argv.argc(); ++i) { FSoundID sfxnum = argv[i]; - if (sfxnum != 0) + if (sfxnum != FSoundID(0)) { S_CacheSound (&S_sfx[sfxnum]); } diff --git a/src/s_sound.h b/src/s_sound.h index e157bbaa1..774d859c8 100644 --- a/src/s_sound.h +++ b/src/s_sound.h @@ -126,6 +126,14 @@ public: ID = S_FindSound(name.GetChars()); return *this; } + bool operator !=(FSoundID other) const + { + return ID != other.ID; + } + bool operator !=(int other) const + { + return ID != other; + } operator int() const { return ID; diff --git a/src/serializer.cpp b/src/serializer.cpp new file mode 100644 index 000000000..9f85da9b6 --- /dev/null +++ b/src/serializer.cpp @@ -0,0 +1,1255 @@ +#define RAPIDJSON_48BITPOINTER_OPTIMIZATION 0 // disable this insanity which is bound to make the code break over time. +#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1 +#define RAPIDJSON_HAS_CXX11_RANGE_FOR 1 +#define RAPIDJSON_PARSE_DEFAULT_FLAGS kParseFullPrecisionFlag + +//#define PRETTY + +#include "rapidjson/rapidjson.h" +#include "rapidjson/writer.h" +#include "rapidjson/prettywriter.h" +#include "rapidjson/stringbuffer.h" +#include "rapidjson/document.h" +#include "serializer.h" +#include "r_data/colormaps.h" +#include "r_data/r_interpolate.h" +#include "r_defs.h" +#include "r_state.h" +#include "p_lnspec.h" +#include "i_system.h" +#include "w_wad.h" +#include "p_terrain.h" +#include "c_dispatch.h" +#include "p_setup.h" +#include "p_conversation.h" +#include "dsectoreffect.h" +#include "d_player.h" +#include "r_data/r_interpolate.h" +#include "g_shared/a_sharedglobal.h" + +char nulspace[1024 * 1024 * 4]; + +//========================================================================== +// +// +// +//========================================================================== + +struct FJSONObject +{ + rapidjson::Value *mObject; + rapidjson::Value::MemberIterator mIterator; + int mIndex; + + FJSONObject(rapidjson::Value *v) + { + mObject = v; + if (v->IsObject()) mIterator = v->MemberBegin(); + else if (v->IsArray()) mIndex = 0; + } +}; + +//========================================================================== +// +// some wrapper stuff to keep the RapidJSON dependencies out of the global headers. +// FSerializer should not expose any of this. +// +//========================================================================== + +struct FWriter +{ + // Since this is done by template parameters, we'd have to template the entire serializer to allow this switch at run time. Argh! +#ifndef PRETTY + typedef rapidjson::Writer > Writer; +#else + typedef rapidjson::PrettyWriter > Writer; +#endif + + Writer mWriter; + TArray mInObject; + rapidjson::StringBuffer mOutString; + TArray mDObjects; + TMap mObjectMap; + + bool inObject() const + { + return mInObject.Size() > 0 && inObject(); + } +}; + +//========================================================================== +// +// +// +//========================================================================== + +struct FReader +{ + TArray mObjects; + rapidjson::Value mDocObj; // just because RapidJSON is stupid and does not allow direct access to what's in the document. + + FReader(const char *buffer, size_t length) + { + rapidjson::Document doc; + doc.Parse(buffer, length); + mDocObj = doc.GetObject(); + mObjects.Push(FJSONObject(&mDocObj)); + } + + rapidjson::Value *FindKey(const char *key) + { + FJSONObject &obj = mObjects.Last(); + + if (obj.mObject->IsObject()) + { + if (obj.mIterator != obj.mObject->MemberEnd()) + { + if (!strcmp(key, obj.mIterator->name.GetString())) + { + return &(obj.mIterator++)->value; + } + } + } + else if (obj.mObject->IsArray()) + { + return &obj.mObject[obj.mIndex++]; + } + return nullptr; + } +}; + + +//========================================================================== +// +// +// +//========================================================================== + +bool FSerializer::OpenWriter() +{ + if (w != nullptr || r == nullptr) return false; + w = new FWriter; + + return true; +} + +//========================================================================== +// +// +// +//========================================================================== + +bool FSerializer::OpenReader(const char *buffer, size_t length) +{ + if (w != nullptr || r == nullptr) return false; + r = new FReader(buffer, length); + return true; +} + +//========================================================================== +// +// +// +//========================================================================== + +void FSerializer::Close() +{ + if (w != nullptr) + { + delete w; + w = nullptr; + } + if (r != nullptr) + { + delete r; + r = nullptr; + } +} + +//========================================================================== +// +// +// +//========================================================================== + +int FSerializer::ArraySize() +{ + if (r != nullptr && r->mObjects.Last().mObject->IsArray()) + { + return r->mObjects.Last().mObject->Size(); + } + else + { + return 0; + } +} + +//========================================================================== +// +// +// +//========================================================================== + +bool FSerializer::canSkip() const +{ + return isWriting() && w->inObject(); +} + +//========================================================================== +// +// +// +//========================================================================== + +void FSerializer::WriteKey(const char *key) +{ + if (isWriting() && w->inObject()) + { + if (key == nullptr) + { + I_Error("missing element name"); + } + w->mWriter.Key(key); + } +} + +//========================================================================== +// +// +// +//========================================================================== + +bool FSerializer::BeginObject(const char *name) +{ + if (isWriting()) + { + WriteKey(name); + w->mWriter.StartObject(); + w->mInObject.Push(true); + } + else + { + auto val = r->FindKey(name); + if (val != nullptr) + { + if (val->IsObject()) + { + r->mObjects.Push(FJSONObject(val)); + } + else + { + I_Error("Object expected for '%s'", name); + } + } + else + { + return false; + } + } + return true; +} + +//========================================================================== +// +// +// +//========================================================================== + +void FSerializer::EndObject() +{ + if (isWriting()) + { + if (w->inObject()) + { + w->mWriter.EndObject(); + w->mInObject.Pop(); + } + else + { + I_Error("EndObject call not inside an object"); + } + } + else + { + r->mObjects.Pop(); + } +} + +//========================================================================== +// +// +// +//========================================================================== + +bool FSerializer::BeginArray(const char *name) +{ + if (isWriting()) + { + WriteKey(name); + w->mWriter.StartArray(); + w->mInObject.Push(false); + } + else + { + auto val = r->FindKey(name); + if (val != nullptr) + { + if (val->IsArray()) + { + r->mObjects.Push(FJSONObject(val)); + } + else + { + I_Error("Array expected for '%s'", name); + } + } + else + { + return false; + } + } + return true; +} + +//========================================================================== +// +// +// +//========================================================================== + +void FSerializer::EndArray() +{ + if (isWriting()) + { + if (w->inObject()) + { + w->mWriter.EndArray(); + w->mInObject.Pop(); + } + else + { + I_Error("EndArray call not inside an array"); + } + } + else + { + r->mObjects.Pop(); + } +} + +//========================================================================== +// +// Special handler for args (because ACS specials' arg0 needs special treatment.) +// +//========================================================================== + +FSerializer &FSerializer::Args(const char *key, int *args, int *defargs, int special) +{ + if (isWriting()) + { + if (w->inObject() && defargs != nullptr && !memcmp(args, defargs, 5 * sizeof(int))) + { + return *this; + } + + WriteKey(key); + w->mWriter.StartArray(); + for (int i = 0; i < 5; i++) + { + if (i == 0 && args[i] < 0 && P_IsACSSpecial(special)) + { + w->mWriter.String(FName(ENamedName(-args[i])).GetChars()); + } + else + { + w->mWriter.Int(args[i]); + } + } + w->mWriter.EndArray(); + } + else + { + auto val = r->FindKey(key); + if (val != nullptr) + { + if (val->IsArray()) + { + unsigned int cnt = MIN(val->Size(), 5); + for (unsigned int i = 0; i < cnt; i++) + { + const rapidjson::Value &aval = (*val)[i]; + if (aval.IsInt()) + { + args[i] = aval.GetInt(); + } + else if (i == 0 && aval.IsString()) + { + args[i] = -FName(aval.GetString()); + } + else + { + I_Error("Integer expected for '%s[%d]'", key, i); + } + } + } + else + { + I_Error("array expected for '%s'", key); + } + } + } + return *this; +} + +//========================================================================== +// +// +// +//========================================================================== + +FSerializer &FSerializer::Terrain(const char *key, int &terrain, int *def) +{ + if (isWriting() && def != nullptr && terrain == *def) + { + return *this; + } + FName terr = P_GetTerrainName(terrain); + Serialize(*this, key, terr, nullptr); + if (isReading()) + { + terrain = P_FindTerrain(terr); + } + return *this; +} + +//========================================================================== +// +// +// +//========================================================================== + +FSerializer &FSerializer::Sprite(const char *key, uint16_t &spritenum, uint16_t *def) +{ + if (isWriting()) + { + if (w->inObject() && def != nullptr && *def == spritenum) return *this; + WriteKey(key); + w->mWriter.String(sprites[spritenum].name, 4); + } + else + { + auto val = r->FindKey(key); + if (val != nullptr) + { + if (val->IsString()) + { + int name = *reinterpret_cast(val->GetString()); + for (auto hint = NumStdSprites; hint-- != 0; ) + { + if (sprites[hint].dwName == name) + { + spritenum = hint; + break; + } + } + } + } + } + return *this; +} + +//========================================================================== +// +// +// +//========================================================================== + +FSerializer &FSerializer::StringPtr(const char *key, const char *&charptr) +{ + if (isWriting()) + { + WriteKey(key); + w->mWriter.String(charptr); + } + else + { + auto val = r->FindKey(key); + if (val != nullptr) + { + if (val->IsString()) + { + charptr = val->GetString(); + } + } + } + return *this; +} + +//========================================================================== +// +// Writes out all collected objects +// +//========================================================================== + +void FSerializer::WriteObjects() +{ + if (isWriting()) + { + BeginArray("objects"); + for (unsigned i = 0; i < w->mDObjects.Size(); i++) + { + BeginObject(nullptr); + WriteKey("classtype"); + w->mWriter.String(w->mDObjects[i]->GetClass()->TypeName.GetChars()); + w->mDObjects[i]->Serialize(*this); + EndObject(); + } + EndArray(); + } +} + +const char *FSerializer::GetOutput(unsigned *len) +{ + if (len != nullptr) + { + *len = (unsigned)w->mOutString.GetSize(); + } + return w->mOutString.GetString(); +} + +//========================================================================== +// +// +// +//========================================================================== + +FSerializer &Serialize(FSerializer &arc, const char *key, bool &value, bool *defval) +{ + if (arc.isWriting()) + { + if (!arc.w->inObject() || defval == nullptr || value != *defval) + { + arc.WriteKey(key); + arc.w->mWriter.Bool(value); + } + } + else + { + auto val = arc.r->FindKey(key); + if (val != nullptr) + { + if (val->IsBool()) + { + value = val->GetBool(); + } + else + { + I_Error("boolean type expected for '%s'", key); + } + } + } + return arc; +} + +//========================================================================== +// +// +// +//========================================================================== + +FSerializer &Serialize(FSerializer &arc, const char *key, int64_t &value, int64_t *defval) +{ + if (arc.isWriting()) + { + if (!arc.w->inObject() || defval == nullptr || value != *defval) + { + arc.WriteKey(key); + arc.w->mWriter.Int64(value); + } + } + else + { + auto val = arc.r->FindKey(key); + if (val != nullptr) + { + if (val->IsInt64()) + { + value = val->GetInt64(); + } + else + { + I_Error("integer type expected for '%s'", key); + } + } + } + return arc; +} + +//========================================================================== +// +// +// +//========================================================================== + +FSerializer &Serialize(FSerializer &arc, const char *key, uint64_t &value, uint64_t *defval) +{ + if (arc.isWriting()) + { + if (!arc.w->inObject() || defval == nullptr || value != *defval) + { + arc.WriteKey(key); + arc.w->mWriter.Uint64(value); + } + } + else + { + auto val = arc.r->FindKey(key); + if (val != nullptr) + { + if (val->IsUint64()) + { + value = val->GetUint64(); + } + else + { + I_Error("integer type expected for '%s'", key); + } + } + } + return arc; +} + + +//========================================================================== +// +// +// +//========================================================================== + +FSerializer &Serialize(FSerializer &arc, const char *key, int32_t &value, int32_t *defval) +{ + if (arc.isWriting()) + { + if (!arc.w->inObject() || defval == nullptr || value != *defval) + { + arc.WriteKey(key); + arc.w->mWriter.Int(value); + } + } + else + { + auto val = arc.r->FindKey(key); + if (val != nullptr) + { + if (val->IsInt()) + { + value = val->GetInt(); + } + else + { + I_Error("integer type expected for '%s'", key); + } + } + } + return arc; +} + +//========================================================================== +// +// +// +//========================================================================== + +FSerializer &Serialize(FSerializer &arc, const char *key, uint32_t &value, uint32_t *defval) +{ + if (arc.isWriting()) + { + if (!arc.w->inObject() || defval == nullptr || value != *defval) + { + arc.WriteKey(key); + arc.w->mWriter.Uint(value); + } + } + else + { + auto val = arc.r->FindKey(key); + if (val != nullptr) + { + if (val->IsUint()) + { + value = val->GetUint(); + } + else + { + I_Error("integer type expected for '%s'", key); + } + } + } + return arc; +} + +//========================================================================== +// +// +// +//========================================================================== + +FSerializer &Serialize(FSerializer &arc, const char *key, int8_t &value, int8_t *defval) +{ + int32_t vv = value; + int32_t vvd = defval? *defval : value-1; + Serialize(arc, key, vv, &vvd); + value = (int8_t)vv; + return arc; +} + +FSerializer &Serialize(FSerializer &arc, const char *key, uint8_t &value, uint8_t *defval) +{ + uint32_t vv = value; + uint32_t vvd = defval ? *defval : value - 1; + Serialize(arc, key, vv, &vvd); + value = (uint8_t)vv; + return arc; +} + +FSerializer &Serialize(FSerializer &arc, const char *key, int16_t &value, int16_t *defval) +{ + int32_t vv = value; + int32_t vvd = defval ? *defval : value - 1; + Serialize(arc, key, vv, &vvd); + value = (int16_t)vv; + return arc; +} + +FSerializer &Serialize(FSerializer &arc, const char *key, uint16_t &value, uint16_t *defval) +{ + uint32_t vv = value; + uint32_t vvd = defval ? *defval : value - 1; + Serialize(arc, key, vv, &vvd); + value = (uint16_t)vv; + return arc; +} + +//========================================================================== +// +// +// +//========================================================================== + +FSerializer &Serialize(FSerializer &arc, const char *key, double &value, double *defval) +{ + if (arc.isWriting()) + { + if (!arc.w->inObject() || defval == nullptr || value != *defval) + { + arc.WriteKey(key); + arc.w->mWriter.Double(value); + } + } + else + { + auto val = arc.r->FindKey(key); + if (val != nullptr) + { + if (val->IsDouble()) + { + value = val->GetDouble(); + } + else + { + I_Error("float type expected for '%s'", key); + } + } + } + return arc; +} + +//========================================================================== +// +// +// +//========================================================================== + +FSerializer &Serialize(FSerializer &arc, const char *key, float &value, float *defval) +{ + double vv = value; + double vvd = defval ? *defval : value - 1; + Serialize(arc, key, vv, &vvd); + value = (float)vv; + return arc; +} + +//========================================================================== +// +// +// +//========================================================================== + +template +FSerializer &SerializePointer(FSerializer &arc, const char *key, T *&value, T **defval, T *base) +{ + if (arc.isReading() || !arc.w->inObject() || defval == nullptr || value != *defval) + { + ptrdiff_t vv = value == nullptr ? -1 : value - base; + Serialize(arc, key, vv, nullptr); + value = vv < 0 ? nullptr : base + vv; + } + return arc; +} + +FSerializer &Serialize(FSerializer &arc, const char *key, side_t *&value, side_t **defval) +{ + return SerializePointer(arc, key, value, defval, sides); +} + +FSerializer &Serialize(FSerializer &arc, const char *key, sector_t *&value, sector_t **defval) +{ + return SerializePointer(arc, key, value, defval, sectors); +} + +FSerializer &Serialize(FSerializer &arc, const char *key, player_t *&value, player_t **defval) +{ + return SerializePointer(arc, key, value, defval, players); +} + +FSerializer &Serialize(FSerializer &arc, const char *key, line_t *&value, line_t **defval) +{ + return SerializePointer(arc, key, value, defval, lines); +} + +//========================================================================== +// +// +// +//========================================================================== + +FSerializer &Serialize(FSerializer &arc, const char *key, FTextureID &value, FTextureID *defval) +{ + if (arc.isWriting()) + { + if (!arc.w->inObject() || defval == nullptr || value != *defval) + { + if (!value.Exists()) + { + arc.WriteKey(key); + arc.w->mWriter.Null(); + return arc; + } + if (value.isNull()) + { + // save 'no texture' in a more space saving way + arc.WriteKey(key); + arc.w->mWriter.Int(0); + return arc; + } + FTextureID chk = value; + if (chk.GetIndex() >= TexMan.NumTextures()) chk.SetNull(); + FTexture *pic = TexMan[chk]; + const char *name; + + if (Wads.GetLinkedTexture(pic->SourceLump) == pic) + { + name = Wads.GetLumpFullName(pic->SourceLump); + } + else + { + name = pic->Name; + } + arc.WriteKey(key); + arc.w->mWriter.StartArray(); + arc.w->mWriter.String(name); + arc.w->mWriter.Int(pic->UseType); + arc.w->mWriter.EndObject(); + } + } + else + { + auto val = arc.r->FindKey(key); + if (val != nullptr) + { + if (val->IsObject()) + { + const rapidjson::Value &nameval = (*val)[0]; + const rapidjson::Value &typeval = (*val)[1]; + if (nameval.IsString() && typeval.IsInt()) + { + value = TexMan.GetTexture(nameval.GetString(), typeval.GetInt()); + } + else + { + I_Error("object does not represent a texture for '%s'", key); + } + } + else if (val->IsNull()) + { + value.SetInvalid(); + } + else if (val->IsInt() && val->GetInt() == 0) + { + value.SetNull(); + } + else + { + I_Error("object does not represent a texture for '%s'", key); + } + } + } + return arc; +} + +//========================================================================== +// +// This never uses defval and instead uses 'null' as default +// because object pointers cannot be safely defaulted to anything else. +// +//========================================================================== + +FSerializer &Serialize(FSerializer &arc, const char *key, DObject *&value, DObject ** /*defval*/) +{ + if (arc.isWriting()) + { + if (value != nullptr) + { + int ndx; + int *pndx = arc.w->mObjectMap.CheckKey(value); + if (pndx != nullptr) ndx = *pndx; + else + { + ndx = arc.w->mDObjects.Push(value); + arc.w->mObjectMap[value] = ndx; + } + Serialize(arc, key, ndx, nullptr); + } + } + else + { + auto val = arc.r->FindKey(key); + if (val != nullptr) + { + } + else + { + value = nullptr; + } + } + return arc; +} + +//========================================================================== +// +// +// +//========================================================================== + +FSerializer &Serialize(FSerializer &arc, const char *key, FName &value, FName *defval) +{ + if (arc.isWriting()) + { + if (!arc.w->inObject() || defval == nullptr || value != *defval) + { + arc.WriteKey(key); + arc.w->mWriter.String(value.GetChars()); + } + } + else + { + auto val = arc.r->FindKey(key); + if (val != nullptr) + { + if (val->IsString()) + { + value = val->GetString(); + } + else + { + I_Error("String expected for '%s'", key); + } + } + } + return arc; +} + +//========================================================================== +// +// +// +//========================================================================== + +FSerializer &Serialize(FSerializer &arc, const char *key, FDynamicColormap *&cm, FDynamicColormap **def) +{ + if (arc.isWriting()) + { + if (arc.w->inObject() && def != nullptr && cm->Color == (*def)->Color && cm->Fade == (*def)->Fade && cm->Desaturate == (*def)->Desaturate) + { + return arc; + } + + arc.WriteKey(key); + arc.w->mWriter.StartArray(); + arc.w->mWriter.Uint(cm->Color); + arc.w->mWriter.Uint(cm->Fade); + arc.w->mWriter.Uint(cm->Desaturate); + arc.w->mWriter.EndArray(); + } + else + { + auto val = arc.r->FindKey(key); + if (val != nullptr) + { + if (val->IsObject()) + { + const rapidjson::Value &colorval = (*val)[0]; + const rapidjson::Value &fadeval = (*val)[1]; + const rapidjson::Value &desatval = (*val)[2]; + if (colorval.IsUint() && fadeval.IsUint() && desatval.IsUint()) + { + cm = GetSpecialLights(colorval.GetUint(), fadeval.GetUint(), desatval.GetUint()); + } + else + { + I_Error("object does not represent a colormap for '%s'", key); + } + } + else + { + I_Error("object does not represent a colormap for '%s'", key); + } + } + } + return arc; +} + +//========================================================================== +// +// +// +//========================================================================== + +FSerializer &Serialize(FSerializer &arc, const char *key, FSoundID &sid, FSoundID *def) +{ + if (arc.isWriting()) + { + if (arc.w->inObject() && def != nullptr && sid != *def) + { + arc.WriteKey(key); + const char *sn = (const char*)sid; + if (sn != nullptr) arc.w->mWriter.String(sn); + else arc.w->mWriter.Null(); + } + } + else + { + auto val = arc.r->FindKey(key); + if (val != nullptr) + { + if (val->IsString()) + { + sid = val->GetString(); + } + else if (val->IsNull()) + { + sid = 0; + } + else + { + I_Error("string type expected for '%s'", key); + } + } + } + return arc; + +} + +//========================================================================== +// +// +// +//========================================================================== + +FSerializer &Serialize(FSerializer &arc, const char *key, PClassActor *&clst, PClassActor **def) +{ + if (arc.isWriting()) + { + if (arc.w->inObject() && def != nullptr && clst != *def) + { + arc.WriteKey(key); + arc.w->mWriter.String(clst->TypeName.GetChars()); + } + } + else + { + auto val = arc.r->FindKey(key); + if (val != nullptr) + { + if (val->IsString()) + { + clst = PClass::FindActor(val->GetString()); + } + else + { + I_Error("string type expected for '%s'", key); + } + } + } + return arc; + +} + +//========================================================================== +// +// +// +//========================================================================== + +FSerializer &Serialize(FSerializer &arc, const char *key, FState *&state, FState **def) +{ + if (arc.isWriting()) + { + if (arc.w->inObject() && def != nullptr && state != *def) + { + arc.WriteKey(key); + if (state == nullptr) + { + arc.w->mWriter.Null(); + } + else + { + PClassActor *info = FState::StaticFindStateOwner(state); + + if (info != NULL) + { + arc.w->mWriter.StartArray(); + arc.w->mWriter.String(info->TypeName.GetChars()); + arc.w->mWriter.Uint((uint32_t)(state - info->OwnedStates)); + arc.w->mWriter.EndArray(); + } + else + { + arc.w->mWriter.Null(); + } + } + } + } + else + { + auto val = arc.r->FindKey(key); + if (val != nullptr) + { + if (val->IsNull()) + { + state = nullptr; + } + else if (val->IsArray()) + { + //rapidjson::Value cls = (*val)[0]; + //rapidjson::Value ndx = (*val)[1]; + } + else + { + I_Error("array type expected for '%s'", key); + } + } + } + return arc; + +} + +//========================================================================== +// +// +// +//========================================================================== + +FSerializer &Serialize(FSerializer &arc, const char *key, FStrifeDialogueNode *&node, FStrifeDialogueNode **def) +{ + if (arc.isWriting()) + { + if (arc.w->inObject() && def != nullptr && node != *def) + { + arc.WriteKey(key); + if (node == nullptr) + { + arc.w->mWriter.Null(); + } + else + { + arc.w->mWriter.Uint(node->ThisNodeNum); + } + } + } + else + { + auto val = arc.r->FindKey(key); + if (val != nullptr) + { + if (val->IsNull()) + { + node = nullptr; + } + else if (val->IsUint()) + { + if (val->GetUint() >= StrifeDialogues.Size()) + { + node = NULL; + } + else + { + node = StrifeDialogues[val->GetUint()]; + } + } + else + { + I_Error("integer expected for '%s'", key); + } + } + } + return arc; + +} + +//========================================================================== +// +// +// +//========================================================================== + +FSerializer &Serialize(FSerializer &arc, const char *key, FString *&pstr, FString **def) +{ + if (arc.isWriting()) + { + if (arc.w->inObject() && def != nullptr && pstr != *def) + { + arc.WriteKey(key); + if (pstr == nullptr) + { + arc.w->mWriter.Null(); + } + else + { + arc.w->mWriter.String(pstr->GetChars()); + } + } + } + else + { + auto val = arc.r->FindKey(key); + if (val != nullptr) + { + if (val->IsNull()) + { + pstr = nullptr; + } + else if (val->IsString()) + { + pstr = AActor::mStringPropertyData.Alloc(val->GetString()); + } + else + { + I_Error("string expected for '%s'", key); + } + } + } + return arc; + +} +