2016-09-18 11:26:34 +00:00
|
|
|
#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 "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"
|
|
|
|
|
2016-09-18 14:41:34 +00:00
|
|
|
TArray<sector_t> loadsectors;
|
|
|
|
TArray<line_t> loadlines;
|
|
|
|
TArray<side_t> loadsides;
|
|
|
|
|
2016-09-18 11:26:34 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
FSerializer &Serialize(FSerializer &arc, const char *key, FName &value);
|
|
|
|
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
typedef rapidjson::Value FJSONValue;
|
|
|
|
|
|
|
|
struct FJSONObject
|
|
|
|
{
|
|
|
|
rapidjson::Value *mObject;
|
|
|
|
rapidjson::Value::MemberIterator mIterator;
|
|
|
|
|
|
|
|
FJSONObject(rapidjson::Value *v)
|
|
|
|
{
|
|
|
|
mObject = v;
|
|
|
|
mIterator = v->MemberEnd();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class FSerializer
|
|
|
|
{
|
|
|
|
#ifndef PRETTY
|
|
|
|
typedef rapidjson::Writer<rapidjson::StringBuffer, rapidjson::ASCII<> > Writer;
|
|
|
|
#else
|
|
|
|
typedef rapidjson::PrettyWriter<rapidjson::StringBuffer, rapidjson::ASCII<> > Writer;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
public:
|
|
|
|
Writer *mWriter = nullptr;
|
|
|
|
TArray<bool> mInObject;
|
|
|
|
rapidjson::StringBuffer mOutString;
|
|
|
|
TArray<DObject *> mDObjects;
|
|
|
|
TMap<DObject *, int> mObjectMap;
|
|
|
|
TArray<FJSONObject> 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;
|
|
|
|
}
|
|
|
|
|
2016-09-18 14:41:34 +00:00
|
|
|
bool BeginArray(const char *name)
|
2016-09-18 11:26:34 +00:00
|
|
|
{
|
|
|
|
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
|
|
|
|
{
|
2016-09-18 14:41:34 +00:00
|
|
|
return false;
|
2016-09-18 11:26:34 +00:00
|
|
|
}
|
|
|
|
}
|
2016-09-18 14:41:34 +00:00
|
|
|
return true;
|
2016-09-18 11:26:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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<unsigned>(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<class T>
|
|
|
|
FSerializer &operator()(const char *key, T &obj)
|
|
|
|
{
|
|
|
|
return Serialize(*this, key, obj);
|
|
|
|
}
|
|
|
|
|
2016-09-18 14:41:34 +00:00
|
|
|
template<class T>
|
|
|
|
FSerializer &operator()(const char *key, T &obj, T & def)
|
|
|
|
{
|
|
|
|
if (isWriting() && !memcmp(&obj, &def, sizeof(T))) return *this;
|
|
|
|
return Serialize(*this, key, obj);
|
|
|
|
}
|
|
|
|
|
2016-09-18 11:26:34 +00:00
|
|
|
template<class T>
|
|
|
|
FSerializer &Array(const char *key, T *obj, int count)
|
|
|
|
{
|
2016-09-18 14:41:34 +00:00
|
|
|
if (BeginArray(key))
|
2016-09-18 11:26:34 +00:00
|
|
|
{
|
2016-09-18 14:41:34 +00:00
|
|
|
for (int i = 0; i < count; i++)
|
|
|
|
{
|
|
|
|
Serialize(*this, nullptr, obj[i]);
|
|
|
|
}
|
|
|
|
EndArray();
|
2016-09-18 11:26:34 +00:00
|
|
|
}
|
2016-09-18 14:41:34 +00:00
|
|
|
return *this;
|
2016-09-18 11:26:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FSerializer &Serialize(FSerializer &arc, const char *key, bool &value)
|
|
|
|
{
|
|
|
|
if (arc.isWriting())
|
|
|
|
{
|
|
|
|
arc.WriteKey(key);
|
|
|
|
arc.mWriter->Bool(value);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
auto val = arc.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)
|
|
|
|
{
|
|
|
|
if (arc.isWriting())
|
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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)
|
|
|
|
{
|
2016-09-18 14:41:34 +00:00
|
|
|
int ndx;
|
2016-09-18 11:26:34 +00:00
|
|
|
int *pndx = arc.mObjectMap.CheckKey(value);
|
|
|
|
if (pndx != nullptr) ndx = *pndx;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ndx = arc.mDObjects.Push(value);
|
|
|
|
arc.mObjectMap[value] = ndx;
|
|
|
|
}
|
2016-09-18 14:41:34 +00:00
|
|
|
Serialize(arc, key, ndx);
|
2016-09-18 11:26:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-09-18 14:41:34 +00:00
|
|
|
auto val = arc.FindKey(key);
|
|
|
|
if (val != nullptr)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
value = nullptr;
|
|
|
|
}
|
2016-09-18 11:26:34 +00:00
|
|
|
}
|
|
|
|
return arc;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class T>
|
|
|
|
FSerializer &Serialize(FSerializer &arc, const char *key, T *&value)
|
|
|
|
{
|
|
|
|
DObject *v = static_cast<DObject*>(value);
|
|
|
|
Serialize(arc, key, v);
|
|
|
|
value = static_cast<T*>(v);
|
|
|
|
return arc;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class T>
|
|
|
|
FSerializer &Serialize(FSerializer &arc, const char *key, TObjPtr<T> &value)
|
|
|
|
{
|
|
|
|
DObject *v = static_cast<DObject*>(value);
|
|
|
|
Serialize(arc, key, v);
|
|
|
|
value = static_cast<T*>(v);
|
|
|
|
return arc;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class T, class TT>
|
|
|
|
FSerializer &Serialize(FSerializer &arc, const char *key, TArray<T, TT> &value)
|
|
|
|
{
|
2016-09-18 14:41:34 +00:00
|
|
|
if (arc.isWriting())
|
|
|
|
{
|
|
|
|
if (value.Size() == 0) return arc; // do not save empty arrays
|
|
|
|
}
|
|
|
|
bool res = arc.BeginArray(key);
|
2016-09-18 11:26:34 +00:00
|
|
|
if (arc.isReading())
|
|
|
|
{
|
2016-09-18 14:41:34 +00:00
|
|
|
if (!res)
|
|
|
|
{
|
|
|
|
value.Clear();
|
|
|
|
return arc;
|
|
|
|
}
|
2016-09-18 11:26:34 +00:00
|
|
|
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)
|
2016-09-18 14:41:34 +00:00
|
|
|
//.Array("sides", line.sidedef, 2)
|
2016-09-18 11:26:34 +00:00
|
|
|
.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)
|
2016-09-18 14:41:34 +00:00
|
|
|
//("leftside", side.LeftSide)
|
|
|
|
//("rightside", side.RightSide)
|
|
|
|
//("index", side.Index)
|
2016-09-18 11:26:34 +00:00
|
|
|
("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);
|
2016-09-18 14:41:34 +00:00
|
|
|
arc.mWriter->StartArray();
|
2016-09-18 11:26:34 +00:00
|
|
|
arc.mWriter->Uint(cm->Color);
|
|
|
|
arc.mWriter->Uint(cm->Fade);
|
|
|
|
arc.mWriter->Uint(cm->Desaturate);
|
2016-09-18 14:41:34 +00:00
|
|
|
arc.mWriter->EndArray();
|
2016-09-18 11:26:34 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
auto val = arc.FindKey(key);
|
|
|
|
if (val != nullptr)
|
|
|
|
{
|
|
|
|
if (val->IsObject())
|
|
|
|
{
|
2016-09-18 14:41:34 +00:00
|
|
|
const rapidjson::Value &colorval = (*val)[0];
|
|
|
|
const rapidjson::Value &fadeval = (*val)[1];
|
|
|
|
const rapidjson::Value &desatval = (*val)[2];
|
2016-09-18 11:26:34 +00:00
|
|
|
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)
|
2016-09-18 14:41:34 +00:00
|
|
|
//("heightsec", p.heightsec)
|
|
|
|
//("bottommap", p.bottommap)
|
|
|
|
//("midmap", p.midmap)
|
|
|
|
//("topmap", p.topmap)
|
2016-09-18 11:26:34 +00:00
|
|
|
("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)
|
|
|
|
{
|
|
|
|
BYTE by;
|
|
|
|
|
2016-09-18 14:41:34 +00:00
|
|
|
if (arc.isWriting())
|
2016-09-18 11:26:34 +00:00
|
|
|
{
|
2016-09-18 14:41:34 +00:00
|
|
|
if (hasglnodes)
|
2016-09-18 11:26:34 +00:00
|
|
|
{
|
2016-09-18 14:41:34 +00:00
|
|
|
TArray<char> encoded((numsubsectors + 5) / 6);
|
|
|
|
int p = 0;
|
|
|
|
for (int i = 0; i < numsubsectors; i += 6)
|
2016-09-18 11:26:34 +00:00
|
|
|
{
|
2016-09-18 14:41:34 +00:00
|
|
|
by = 0;
|
|
|
|
for (int j = 0; j < 6; j++)
|
2016-09-18 11:26:34 +00:00
|
|
|
{
|
2016-09-18 14:41:34 +00:00
|
|
|
if (i + j < numsubsectors && (subsectors[i + j].flags & SSECF_DRAWN))
|
|
|
|
{
|
|
|
|
by |= (1 << j);
|
|
|
|
}
|
2016-09-18 11:26:34 +00:00
|
|
|
}
|
2016-09-18 14:41:34 +00:00
|
|
|
if (by < 10) by += '0';
|
|
|
|
else if (by < 36) by += 'A' - 10;
|
|
|
|
else if (by < 62) by += 'a' - 36;
|
|
|
|
else if (by == 62) by = '-';
|
|
|
|
else if (by == 63) by = '+';
|
|
|
|
encoded[p++] = by;
|
2016-09-18 11:26:34 +00:00
|
|
|
}
|
2016-09-18 14:41:34 +00:00
|
|
|
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();
|
2016-09-18 11:26:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int num_verts, num_subs, num_nodes;
|
|
|
|
}
|
|
|
|
return arc;
|
|
|
|
}
|
|
|
|
|
|
|
|
FSerializer &Serialize(FSerializer &arc, const char *key, ReverbContainer *&c)
|
|
|
|
{
|
|
|
|
int id = (arc.isReading() || c == nullptr) ? 0 : c->ID;
|
|
|
|
Serialize(arc, key, id);
|
|
|
|
if (arc.isReading())
|
|
|
|
{
|
|
|
|
c = S_FindEnvironment(id);
|
|
|
|
}
|
|
|
|
return arc;
|
|
|
|
}
|
|
|
|
|
|
|
|
FSerializer &Serialize(FSerializer &arc, const char *key, zone_t &z)
|
|
|
|
{
|
|
|
|
return Serialize(arc, key, z.Environment);
|
|
|
|
}
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
//
|
|
|
|
// Save a line portal for savegames.
|
|
|
|
//
|
|
|
|
//============================================================================
|
|
|
|
|
|
|
|
FSerializer &Serialize(FSerializer &arc, const char *key, FLinePortal &port)
|
|
|
|
{
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
//
|
|
|
|
// Save a sector portal for savegames.
|
|
|
|
//
|
|
|
|
//============================================================================
|
|
|
|
|
|
|
|
FSerializer &Serialize(FSerializer &arc, const char *key, FSectorPortal &port)
|
|
|
|
{
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DThinker::SaveList(FSerializer &arc, DThinker *node)
|
|
|
|
{
|
|
|
|
if (node != NULL)
|
|
|
|
{
|
|
|
|
while (!(node->ObjectFlags & OF_Sentinel))
|
|
|
|
{
|
|
|
|
assert(node->NextThinker != NULL && !(node->NextThinker->ObjectFlags & OF_EuthanizeMe));
|
|
|
|
::Serialize(arc, nullptr, node);
|
|
|
|
node = node->NextThinker;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void DThinker::SerializeThinkers(FSerializer &arc, bool hubLoad)
|
|
|
|
{
|
|
|
|
DThinker *thinker;
|
|
|
|
BYTE stat;
|
|
|
|
int statcount;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (arc.isWriting())
|
|
|
|
{
|
|
|
|
arc.BeginArray("thinkers");
|
|
|
|
for (i = 0; i <= MAX_STATNUM; i++)
|
|
|
|
{
|
|
|
|
arc.BeginArray(nullptr);
|
|
|
|
SaveList(arc, Thinkers[i].GetHead());
|
|
|
|
SaveList(arc, FreshThinkers[i].GetHead());
|
|
|
|
arc.EndArray();
|
|
|
|
}
|
|
|
|
arc.EndArray();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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<class T, class TT>
|
|
|
|
FSerializer &Serialize(FSerializer &arc, const char *key, TFlags<T, TT> &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)
|
|
|
|
("subsectors", subsectors)
|
|
|
|
("zones", Zones)
|
|
|
|
("lineportals", linePortals)
|
|
|
|
("sectorportals", sectorPortals);
|
|
|
|
}
|
|
|
|
|
|
|
|
void DObject::SerializeUserVars(FSerializer &arc)
|
|
|
|
{
|
|
|
|
PSymbolTable *symt;
|
|
|
|
FName varname;
|
|
|
|
DWORD count, j;
|
|
|
|
int *varloc = NULL;
|
|
|
|
|
|
|
|
symt = &GetClass()->Symbols;
|
|
|
|
|
|
|
|
if (arc.isWriting())
|
|
|
|
{
|
|
|
|
// Write all fields that aren't serialized by native code.
|
|
|
|
//GetClass()->WriteValue(arc, this);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//GetClass()->ReadValue(arc, this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2016-09-18 14:41:34 +00:00
|
|
|
#define A(a,b) ((a), (b), def->b)
|
|
|
|
|
2016-09-18 11:26:34 +00:00
|
|
|
void AActor::Serialize(FSerializer &arc)
|
|
|
|
{
|
|
|
|
int damage = 0; // just a placeholder until the insanity surrounding the damage property can be fixed
|
2016-09-18 14:41:34 +00:00
|
|
|
AActor *def = GetDefault();
|
2016-09-18 11:26:34 +00:00
|
|
|
|
|
|
|
Super::Serialize(arc);
|
|
|
|
|
|
|
|
arc
|
|
|
|
.Sprite("sprite", sprite)
|
2016-09-18 14:41:34 +00:00
|
|
|
A("pos", __Pos)
|
|
|
|
A("angles", Angles)
|
|
|
|
A("frame", frame)
|
|
|
|
A("scale", Scale)
|
|
|
|
A("renderstyle", RenderStyle)
|
|
|
|
A("renderflags", renderflags)
|
|
|
|
A("picnum", picnum)
|
|
|
|
A("floorpic", floorpic)
|
|
|
|
A("ceilingpic", ceilingpic)
|
|
|
|
A("tidtohate", TIDtoHate)
|
|
|
|
A("lastlookpn", LastLookPlayerNumber)
|
2016-09-18 11:26:34 +00:00
|
|
|
("lastlookactor", LastLookActor)
|
2016-09-18 14:41:34 +00:00
|
|
|
A("effects", effects)
|
|
|
|
A("alpha", Alpha)
|
|
|
|
A("fillcolor", fillcolor)
|
|
|
|
A("sector", Sector)
|
|
|
|
A("floorz", floorz)
|
|
|
|
A("ceilingz", ceilingz)
|
|
|
|
A("dropoffz", dropoffz)
|
|
|
|
A("floorsector", floorsector)
|
|
|
|
A("ceilingsector", ceilingsector)
|
|
|
|
A("radius", radius)
|
|
|
|
A("height", Height)
|
|
|
|
A("ppassheight", projectilepassheight)
|
|
|
|
A("vel", Vel)
|
|
|
|
A("tics", tics)
|
2016-09-18 11:26:34 +00:00
|
|
|
("state", state)
|
|
|
|
("damage", damage)
|
|
|
|
.Terrain("floorterrain", floorterrain)
|
2016-09-18 14:41:34 +00:00
|
|
|
A("projectilekickback", projectileKickback)
|
|
|
|
A("flags", flags)
|
|
|
|
A("flags2", flags2)
|
|
|
|
A("flags3", flags3)
|
|
|
|
A("flags4", flags4)
|
|
|
|
A("flags5", flags5)
|
|
|
|
A("flags6", flags6)
|
|
|
|
A("flags7", flags7)
|
|
|
|
A("weaponspecial", weaponspecial)
|
|
|
|
A("special1", special1)
|
|
|
|
A("special2", special2)
|
|
|
|
A("specialf1", specialf1)
|
|
|
|
A("specialf2", specialf2)
|
|
|
|
A("health", health)
|
|
|
|
A("movedir", movedir)
|
|
|
|
A("visdir", visdir)
|
|
|
|
A("movecount", movecount)
|
|
|
|
A("strafecount", strafecount)
|
2016-09-18 11:26:34 +00:00
|
|
|
("target", target)
|
|
|
|
("lastenemy", lastenemy)
|
|
|
|
("lastheard", LastHeard)
|
2016-09-18 14:41:34 +00:00
|
|
|
A("reactiontime", reactiontime)
|
|
|
|
A("threshold", threshold)
|
|
|
|
A("player", player)
|
|
|
|
A("spawnpoint", SpawnPoint)
|
|
|
|
A("spawnangle", SpawnAngle)
|
|
|
|
A("starthealth", StartHealth)
|
|
|
|
A("skillrespawncount", skillrespawncount)
|
2016-09-18 11:26:34 +00:00
|
|
|
("tracer", tracer)
|
2016-09-18 14:41:34 +00:00
|
|
|
A("floorclip", Floorclip)
|
|
|
|
A("tid", tid)
|
|
|
|
A("special", special)
|
2016-09-18 11:26:34 +00:00
|
|
|
.Args("args", args, special)
|
2016-09-18 14:41:34 +00:00
|
|
|
A("accuracy", accuracy)
|
|
|
|
A("stamina", stamina)
|
2016-09-18 11:26:34 +00:00
|
|
|
("goal", goal)
|
2016-09-18 14:41:34 +00:00
|
|
|
A("waterlevel", waterlevel)
|
|
|
|
A("minmissilechance", MinMissileChance)
|
|
|
|
A("spawnflags", SpawnFlags)
|
2016-09-18 11:26:34 +00:00
|
|
|
("inventory", Inventory)
|
2016-09-18 14:41:34 +00:00
|
|
|
A("inventoryid", InventoryID)
|
|
|
|
A("floatbobphase", FloatBobPhase)
|
|
|
|
A("translation", Translation)
|
|
|
|
A("seesound", SeeSound)
|
|
|
|
A("attacksound", AttackSound)
|
|
|
|
A("paimsound", PainSound)
|
|
|
|
A("deathsound", DeathSound)
|
|
|
|
A("activesound", ActiveSound)
|
|
|
|
A("usesound", UseSound)
|
|
|
|
A("bouncesound", BounceSound)
|
|
|
|
A("wallbouncesound", WallBounceSound)
|
|
|
|
A("crushpainsound", CrushPainSound)
|
|
|
|
A("speed", Speed)
|
|
|
|
A("floatspeed", FloatSpeed)
|
|
|
|
A("mass", Mass)
|
|
|
|
A("painchance", PainChance)
|
|
|
|
A("spawnstate", SpawnState)
|
|
|
|
A("seestate", SeeState)
|
|
|
|
A("meleestate", MeleeState)
|
|
|
|
A("missilestate", MissileState)
|
|
|
|
A("maxdropoffheight", MaxDropOffHeight)
|
|
|
|
A("maxstepheight", MaxStepHeight)
|
|
|
|
A("bounceflags", BounceFlags)
|
|
|
|
A("bouncefactor", bouncefactor)
|
|
|
|
A("wallbouncefactor", wallbouncefactor)
|
|
|
|
A("bouncecount", bouncecount)
|
|
|
|
A("maxtargetrange", maxtargetrange)
|
|
|
|
A("meleethreshold", meleethreshold)
|
|
|
|
A("meleerange", meleerange)
|
|
|
|
A("damagetype", DamageType)
|
|
|
|
A("damagetypereceived", DamageTypeReceived)
|
|
|
|
A("paintype", PainType)
|
|
|
|
A("deathtype", DeathType)
|
|
|
|
A("gravity", Gravity)
|
|
|
|
A("fastchasestrafecount", FastChaseStrafeCount)
|
2016-09-18 11:26:34 +00:00
|
|
|
("master", master)
|
2016-09-18 14:41:34 +00:00
|
|
|
A("smokecounter", smokecounter)
|
2016-09-18 11:26:34 +00:00
|
|
|
("blockingmobj", BlockingMobj)
|
2016-09-18 14:41:34 +00:00
|
|
|
A("blockingline", BlockingLine)
|
|
|
|
A("visibletoteam", VisibleToTeam)
|
|
|
|
A("pushfactor", pushfactor)
|
|
|
|
A("species", Species)
|
|
|
|
A("score", Score)
|
|
|
|
A("designatedteam", DesignatedTeam)
|
|
|
|
A("lastpush", lastpush)
|
|
|
|
A("lastbump", lastbump)
|
|
|
|
A("painthreshold", PainThreshold)
|
|
|
|
A("damagefactor", DamageFactor)
|
|
|
|
A("damagemultiply", DamageMultiply)
|
|
|
|
A("waveindexxy", WeaveIndexXY)
|
|
|
|
A("weaveindexz", WeaveIndexZ)
|
|
|
|
A("pdmgreceived", PoisonDamageReceived)
|
|
|
|
A("pdurreceived", PoisonDurationReceived)
|
|
|
|
A("ppreceived", PoisonPeriodReceived)
|
|
|
|
A("poisoner", Poisoner)
|
|
|
|
A("posiondamage", PoisonDamage)
|
|
|
|
A("poisonduration", PoisonDuration)
|
|
|
|
A("poisonperiod", PoisonPeriod)
|
|
|
|
A("poisondamagetype", PoisonDamageType)
|
|
|
|
A("poisondmgtypereceived", PoisonDamageTypeReceived)
|
|
|
|
A("conversationroot", ConversationRoot)
|
|
|
|
A("conversation", Conversation)
|
|
|
|
A("friendplayer", FriendPlayer)
|
|
|
|
A("telefogsourcetype", TeleFogSourceType)
|
|
|
|
A("telefogdesttype", TeleFogDestType)
|
|
|
|
A("ripperlevel", RipperLevel)
|
|
|
|
A("riplevelmin", RipLevelMin)
|
|
|
|
A("riplevelmax", RipLevelMax)
|
|
|
|
A("devthreshold", DefThreshold)
|
|
|
|
A("spriteangle", SpriteAngle)
|
|
|
|
A("spriterotation", SpriteRotation)
|
2016-09-18 11:26:34 +00:00
|
|
|
("alternative", alternative)
|
|
|
|
("tag", Tag);
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CCMD(writejson)
|
|
|
|
{
|
|
|
|
DWORD t = I_MSTime();
|
|
|
|
FSerializer arc;
|
|
|
|
arc.OpenWriter(true);
|
|
|
|
arc.BeginObject(nullptr);
|
|
|
|
DThinker::SerializeThinkers(arc, false);
|
|
|
|
SerializeWorld(arc);
|
|
|
|
SerializeObjects(arc);
|
|
|
|
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);
|
|
|
|
fclose(f);
|
|
|
|
DWORD ttt = I_MSTime();
|
|
|
|
Printf("JSON save took %d ms\n", ttt - tt);
|
|
|
|
rapidjson::Document doc;
|
|
|
|
doc.Parse(arc.mOutString.GetString());
|
|
|
|
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);
|
|
|
|
}
|