mirror of
https://github.com/DrBeef/Raze.git
synced 2024-11-15 00:41:55 +00:00
- update "common" subfolder.
# Conflicts: # source/CMakeLists.txt
This commit is contained in:
parent
ada5ad5ec3
commit
091d90aba5
8 changed files with 751 additions and 308 deletions
|
@ -713,7 +713,6 @@ set (PCH_SOURCES
|
|||
core/savegamehelp.cpp
|
||||
core/quotes.cpp
|
||||
core/screenshot.cpp
|
||||
core/serializer.cpp
|
||||
core/raze_music.cpp
|
||||
core/raze_sound.cpp
|
||||
|
||||
|
@ -786,9 +785,11 @@ set (PCH_SOURCES
|
|||
common/engine/sc_man.cpp
|
||||
common/engine/palettecontainer.cpp
|
||||
common/engine/stringtable.cpp
|
||||
common/engine/serializer.cpp
|
||||
common/objects/dobject.cpp
|
||||
common/objects/dobjgc.cpp
|
||||
common/objects/dobjtype.cpp
|
||||
common/scripting/core/dictionary.cpp
|
||||
common/scripting/core/symbols.cpp
|
||||
common/scripting/core/types.cpp
|
||||
common/scripting/core/scopebarrier.cpp
|
||||
|
@ -955,10 +956,9 @@ include_directories(
|
|||
common/console
|
||||
common/engine
|
||||
common/objects
|
||||
common/scripting/interface
|
||||
common/scripting/core
|
||||
common/scripting/vm
|
||||
common/scripting/jit
|
||||
common/scripting/core
|
||||
${CMAKE_BINARY_DIR}/libraries/gdtoa
|
||||
|
||||
${SYSTEM_SOURCES_DIR}
|
||||
|
@ -1074,11 +1074,11 @@ source_group("Common\\Engine" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/c
|
|||
source_group("Common\\Objects" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/objects/.+")
|
||||
source_group("Common\\Fonts" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/fonts/.+")
|
||||
source_group("Common\\File System" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/filesystem/.+")
|
||||
source_group("Common\\File System" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/filesystem/.+")
|
||||
source_group("Common\\Scripting" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/scripting/.+")
|
||||
source_group("Common\\Scripting\\Core" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/scripting/core/.+")
|
||||
source_group("Common\\Scripting\\VM" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/scripting/vm/.+")
|
||||
source_group("Common\\Scripting\\JIT" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/scripting/jit/.+")
|
||||
source_group("Common\\Scripting\\VM" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/scripting/vm/.+")
|
||||
source_group("Common\\Textures" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/textures/.+")
|
||||
source_group("Common\\Third Party" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/thirdparty/.+")
|
||||
source_group("Common\\Third Party\\Math" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/thirdparty/math/.+")
|
||||
source_group("Common\\Third Party\\RapidJSON" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/thirdparty/rapidjson/.+")
|
||||
|
|
17
source/common/engine/serialize_obj.h
Normal file
17
source/common/engine/serialize_obj.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
#pragma once
|
||||
|
||||
// These are in a separate header because they require some rather 'dirty' headers to work which should not be part of serializer.h
|
||||
|
||||
template<class T>
|
||||
FSerializer &Serialize(FSerializer &arc, const char *key, TObjPtr<T> &value, TObjPtr<T> *)
|
||||
{
|
||||
Serialize(arc, key, value.o, nullptr);
|
||||
return arc;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
FSerializer &Serialize(FSerializer &arc, const char *key, TObjPtr<T> &value, T *)
|
||||
{
|
||||
Serialize(arc, key, value.o, nullptr);
|
||||
return arc;
|
||||
}
|
|
@ -50,12 +50,15 @@
|
|||
#include "cmdlib.h"
|
||||
#include "utf8.h"
|
||||
#include "printf.h"
|
||||
#include "raze_sound.h"
|
||||
#include "s_soundinternal.h"
|
||||
#include "engineerrors.h"
|
||||
#include "textures.h"
|
||||
#include "texturemanager.h"
|
||||
|
||||
bool save_full = false;
|
||||
extern DObject *WP_NOCHANGE;
|
||||
bool save_full = false; // for testing. Should be removed afterward.
|
||||
|
||||
#include "serializer_internal.h"
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
|
@ -66,7 +69,7 @@ bool save_full = false;
|
|||
//==========================================================================
|
||||
|
||||
static TArray<char> out;
|
||||
static const char *StringToUnicode(const char *cc, int size = -1)
|
||||
const char *StringToUnicode(const char *cc, int size)
|
||||
{
|
||||
int ch;
|
||||
const uint8_t *c = (const uint8_t*)cc;
|
||||
|
@ -94,7 +97,7 @@ static const char *StringToUnicode(const char *cc, int size = -1)
|
|||
return &out[0];
|
||||
}
|
||||
|
||||
static const char *UnicodeToString(const char *cc)
|
||||
const char *UnicodeToString(const char *cc)
|
||||
{
|
||||
out.Resize((unsigned)strlen(cc) + 1);
|
||||
int ndx = 0;
|
||||
|
@ -110,225 +113,6 @@ static const char *UnicodeToString(const char *cc)
|
|||
return &out[0];
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
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
|
||||
{
|
||||
typedef rapidjson::Writer<rapidjson::StringBuffer, rapidjson::UTF8<> > Writer;
|
||||
typedef rapidjson::PrettyWriter<rapidjson::StringBuffer, rapidjson::UTF8<> > PrettyWriter;
|
||||
|
||||
Writer *mWriter1;
|
||||
PrettyWriter *mWriter2;
|
||||
TArray<bool> mInObject;
|
||||
rapidjson::StringBuffer mOutString;
|
||||
TArray<DObject *> mDObjects;
|
||||
TMap<DObject *, int> mObjectMap;
|
||||
|
||||
FWriter(bool pretty)
|
||||
{
|
||||
if (!pretty)
|
||||
{
|
||||
mWriter1 = new Writer(mOutString);
|
||||
mWriter2 = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
mWriter1 = nullptr;
|
||||
mWriter2 = new PrettyWriter(mOutString);
|
||||
}
|
||||
}
|
||||
|
||||
~FWriter()
|
||||
{
|
||||
if (mWriter1) delete mWriter1;
|
||||
if (mWriter2) delete mWriter2;
|
||||
}
|
||||
|
||||
|
||||
bool inObject() const
|
||||
{
|
||||
return mInObject.Size() > 0 && mInObject.Last();
|
||||
}
|
||||
|
||||
void StartObject()
|
||||
{
|
||||
if (mWriter1) mWriter1->StartObject();
|
||||
else if (mWriter2) mWriter2->StartObject();
|
||||
}
|
||||
|
||||
void EndObject()
|
||||
{
|
||||
if (mWriter1) mWriter1->EndObject();
|
||||
else if (mWriter2) mWriter2->EndObject();
|
||||
}
|
||||
|
||||
void StartArray()
|
||||
{
|
||||
if (mWriter1) mWriter1->StartArray();
|
||||
else if (mWriter2) mWriter2->StartArray();
|
||||
}
|
||||
|
||||
void EndArray()
|
||||
{
|
||||
if (mWriter1) mWriter1->EndArray();
|
||||
else if (mWriter2) mWriter2->EndArray();
|
||||
}
|
||||
|
||||
void Key(const char *k)
|
||||
{
|
||||
if (mWriter1) mWriter1->Key(k);
|
||||
else if (mWriter2) mWriter2->Key(k);
|
||||
}
|
||||
|
||||
void Null()
|
||||
{
|
||||
if (mWriter1) mWriter1->Null();
|
||||
else if (mWriter2) mWriter2->Null();
|
||||
}
|
||||
|
||||
void StringU(const char *k, bool encode)
|
||||
{
|
||||
if (encode) k = StringToUnicode(k);
|
||||
if (mWriter1) mWriter1->String(k);
|
||||
else if (mWriter2) mWriter2->String(k);
|
||||
}
|
||||
|
||||
void String(const char *k)
|
||||
{
|
||||
k = StringToUnicode(k);
|
||||
if (mWriter1) mWriter1->String(k);
|
||||
else if (mWriter2) mWriter2->String(k);
|
||||
}
|
||||
|
||||
void String(const char *k, int size)
|
||||
{
|
||||
k = StringToUnicode(k, size);
|
||||
if (mWriter1) mWriter1->String(k);
|
||||
else if (mWriter2) mWriter2->String(k);
|
||||
}
|
||||
|
||||
void Bool(bool k)
|
||||
{
|
||||
if (mWriter1) mWriter1->Bool(k);
|
||||
else if (mWriter2) mWriter2->Bool(k);
|
||||
}
|
||||
|
||||
void Int(int32_t k)
|
||||
{
|
||||
if (mWriter1) mWriter1->Int(k);
|
||||
else if (mWriter2) mWriter2->Int(k);
|
||||
}
|
||||
|
||||
void Int64(int64_t k)
|
||||
{
|
||||
if (mWriter1) mWriter1->Int64(k);
|
||||
else if (mWriter2) mWriter2->Int64(k);
|
||||
}
|
||||
|
||||
void Uint(uint32_t k)
|
||||
{
|
||||
if (mWriter1) mWriter1->Uint(k);
|
||||
else if (mWriter2) mWriter2->Uint(k);
|
||||
}
|
||||
|
||||
void Uint64(int64_t k)
|
||||
{
|
||||
if (mWriter1) mWriter1->Uint64(k);
|
||||
else if (mWriter2) mWriter2->Uint64(k);
|
||||
}
|
||||
|
||||
void Double(double k)
|
||||
{
|
||||
if (mWriter1)
|
||||
{
|
||||
mWriter1->Double(k);
|
||||
}
|
||||
else if (mWriter2)
|
||||
{
|
||||
mWriter2->Double(k);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
struct FReader
|
||||
{
|
||||
TArray<FJSONObject> mObjects;
|
||||
rapidjson::Document mDoc;
|
||||
TArray<DObject *> mDObjects;
|
||||
rapidjson::Value *mKeyValue = nullptr;
|
||||
bool mObjectsRead = false;
|
||||
|
||||
FReader(const char *buffer, size_t length)
|
||||
{
|
||||
mDoc.Parse(buffer, length);
|
||||
mObjects.Push(FJSONObject(&mDoc));
|
||||
}
|
||||
|
||||
rapidjson::Value *FindKey(const char *key)
|
||||
{
|
||||
FJSONObject &obj = mObjects.Last();
|
||||
|
||||
if (obj.mObject->IsObject())
|
||||
{
|
||||
if (key == nullptr)
|
||||
{
|
||||
// we are performing an iteration of the object through GetKey.
|
||||
auto p = mKeyValue;
|
||||
mKeyValue = nullptr;
|
||||
return p;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Find the given key by name;
|
||||
auto it = obj.mObject->FindMember(key);
|
||||
if (it == obj.mObject->MemberEnd()) return nullptr;
|
||||
return &it->value;
|
||||
}
|
||||
}
|
||||
else if (obj.mObject->IsArray() && (unsigned)obj.mIndex < obj.mObject->Size())
|
||||
{
|
||||
return &(*obj.mObject)[obj.mIndex++];
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
|
@ -402,6 +186,7 @@ void FSerializer::Close()
|
|||
}
|
||||
if (r != nullptr)
|
||||
{
|
||||
CloseReaderCustom();
|
||||
delete r;
|
||||
r = nullptr;
|
||||
}
|
||||
|
@ -635,6 +420,43 @@ FSerializer &FSerializer::ScriptNum(const char *key, int &num)
|
|||
return *this;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// this is merely a placeholder to satisfy the VM's spriteid type.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FSerializer &FSerializer::Sprite(const char *key, int32_t &spritenum, int32_t *def)
|
||||
{
|
||||
if (isWriting())
|
||||
{
|
||||
if (w->inObject() && def != nullptr && *def == spritenum) return *this;
|
||||
WriteKey(key);
|
||||
w->Int(spritenum);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto val = r->FindKey(key);
|
||||
if (val != nullptr && val->IsInt())
|
||||
{
|
||||
spritenum = val->GetInt();
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// only here so that it can be virtually overridden. Without reference this cannot save anything.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FSerializer& FSerializer::StatePointer(const char* key, void* ptraddr, bool *res)
|
||||
{
|
||||
if (res) *res = false;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
|
@ -835,7 +657,7 @@ void FSerializer::ReadObjects(bool hubtravel)
|
|||
obj->SerializeUserVars(*this);
|
||||
obj->Serialize(*this);
|
||||
}
|
||||
catch (CEngineError &err)
|
||||
catch (CRecoverableError &err)
|
||||
{
|
||||
// In case something in here throws an error, let's continue and deal with it later.
|
||||
Printf(TEXTCOLOR_RED "'%s'\n while restoring %s\n", err.GetMessage(), obj ? obj->GetClass()->TypeName.GetChars() : "invalid object");
|
||||
|
@ -1136,6 +958,15 @@ FSerializer &Serialize(FSerializer &arc, const char *key, uint32_t &value, uint3
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
FSerializer& Serialize(FSerializer& arc, const char* key, char& value, char* 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, int8_t &value, int8_t *defval)
|
||||
{
|
||||
int32_t vv = value;
|
||||
|
@ -1229,25 +1060,6 @@ FSerializer &Serialize(FSerializer &arc, const char *key, float &value, float *d
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
template<class T>
|
||||
FSerializer &SerializePointer(FSerializer &arc, const char *key, T *&value, T **defval, T *base)
|
||||
{
|
||||
assert(base != nullptr);
|
||||
if (arc.isReading() || !arc.w->inObject() || defval == nullptr || value != *defval)
|
||||
{
|
||||
int64_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, FTextureID &value, FTextureID *defval)
|
||||
{
|
||||
if (arc.isWriting())
|
||||
|
@ -1344,13 +1156,11 @@ FSerializer &Serialize(FSerializer &arc, const char *key, DObject *&value, DObje
|
|||
if (value != nullptr && !(value->ObjectFlags & (OF_EuthanizeMe | OF_Transient)))
|
||||
{
|
||||
int ndx;
|
||||
/*
|
||||
if (value == WP_NOCHANGE)
|
||||
{
|
||||
ndx = -1;
|
||||
}
|
||||
else
|
||||
*/
|
||||
{
|
||||
int *pndx = arc.w->mObjectMap.CheckKey(value);
|
||||
if (pndx != nullptr)
|
||||
|
@ -1391,7 +1201,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, DObject *&value, DObje
|
|||
int index = val->GetInt();
|
||||
if (index == -1)
|
||||
{
|
||||
value = nullptr;// WP_NOCHANGE;
|
||||
value = WP_NOCHANGE;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1463,19 +1273,20 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FName &value, FName *d
|
|||
|
||||
//==========================================================================
|
||||
//
|
||||
// Note that the sound name here is not reliable because it's a file name, not a unique alias.
|
||||
// Currently the index is the only means to retrieve the sound on loading.
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FSerializer &Serialize(FSerializer &arc, const char *key, FSoundID &sid, FSoundID *def)
|
||||
{
|
||||
#if 1
|
||||
int id = sid;
|
||||
Serialize(arc, key, id, nullptr);
|
||||
if (arc.isReading()) sid = FSoundID(id);
|
||||
#else
|
||||
if (arc.isWriting())
|
||||
if (!arc.soundNamesAreUnique)
|
||||
{
|
||||
//If sound name here is not reliable, we need to save by index instead.
|
||||
int id = sid;
|
||||
Serialize(arc, key, id, nullptr);
|
||||
if (arc.isReading()) sid = FSoundID(id);
|
||||
}
|
||||
else if (arc.isWriting())
|
||||
{
|
||||
if (!arc.w->inObject() || def == nullptr || sid != *def)
|
||||
{
|
||||
|
@ -1507,7 +1318,6 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FSoundID &sid, FSoundI
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return arc;
|
||||
|
||||
}
|
||||
|
@ -1625,6 +1435,86 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, FFont *&fon
|
|||
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Dictionary
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FString DictionaryToString(const Dictionary &dict)
|
||||
{
|
||||
Dictionary::ConstPair *pair;
|
||||
Dictionary::ConstIterator i { dict.Map };
|
||||
|
||||
rapidjson::StringBuffer buffer;
|
||||
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
|
||||
writer.StartObject();
|
||||
|
||||
while (i.NextPair(pair))
|
||||
{
|
||||
writer.Key(pair->Key);
|
||||
writer.String(pair->Value);
|
||||
}
|
||||
|
||||
writer.EndObject();
|
||||
|
||||
FString contents { buffer.GetString(), buffer.GetSize() };
|
||||
return contents;
|
||||
}
|
||||
|
||||
Dictionary *DictionaryFromString(const FString &string)
|
||||
{
|
||||
if (string.Compare("null") == 0)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Dictionary *const dict = Create<Dictionary>();
|
||||
|
||||
if (string.IsEmpty())
|
||||
{
|
||||
return dict;
|
||||
}
|
||||
|
||||
rapidjson::Document doc;
|
||||
doc.Parse(string.GetChars(), string.Len());
|
||||
|
||||
if (doc.GetType() != rapidjson::Type::kObjectType)
|
||||
{
|
||||
I_Error("Dictionary is expected to be a JSON object.");
|
||||
return dict;
|
||||
}
|
||||
|
||||
for (auto i = doc.MemberBegin(); i != doc.MemberEnd(); ++i)
|
||||
{
|
||||
if (i->value.GetType() != rapidjson::Type::kStringType)
|
||||
{
|
||||
I_Error("Dictionary value is expected to be a JSON string.");
|
||||
return dict;
|
||||
}
|
||||
|
||||
dict->Map.Insert(i->name.GetString(), i->value.GetString());
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
template<> FSerializer &Serialize(FSerializer &arc, const char *key, Dictionary *&dict, Dictionary **)
|
||||
{
|
||||
if (arc.isWriting())
|
||||
{
|
||||
FString contents { dict ? DictionaryToString(*dict) : "null" };
|
||||
return arc(key, contents);
|
||||
}
|
||||
else
|
||||
{
|
||||
FString contents;
|
||||
arc(key, contents);
|
||||
dict = DictionaryFromString(contents);
|
||||
return arc;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Handler to retrieve a numeric value of any kind.
|
|
@ -9,6 +9,7 @@
|
|||
#include "vectors.h"
|
||||
#include "palentry.h"
|
||||
#include "name.h"
|
||||
#include "dictionary.h"
|
||||
|
||||
extern bool save_full;
|
||||
|
||||
|
@ -61,11 +62,14 @@ class FSerializer
|
|||
public:
|
||||
FWriter *w = nullptr;
|
||||
FReader *r = nullptr;
|
||||
bool soundNamesAreUnique = false; // While in GZDoom, sound names are unique, that isn't universally true - let the serializer handle both cases with a flag.
|
||||
|
||||
unsigned ArraySize();
|
||||
void WriteKey(const char *key);
|
||||
void WriteObjects();
|
||||
|
||||
private:
|
||||
virtual void CloseReaderCustom() {}
|
||||
public:
|
||||
|
||||
~FSerializer()
|
||||
|
@ -73,6 +77,7 @@ public:
|
|||
mErrors = 0; // The destructor may not throw an exception so silence the error checker.
|
||||
Close();
|
||||
}
|
||||
void SetUniqueSoundNames() { soundNamesAreUnique = true; }
|
||||
bool OpenWriter(bool pretty = true);
|
||||
bool OpenReader(const char *buffer, size_t length);
|
||||
bool OpenReader(FCompressedBuffer *input);
|
||||
|
@ -86,6 +91,11 @@ public:
|
|||
const char *GetKey();
|
||||
const char *GetOutput(unsigned *len = nullptr);
|
||||
FCompressedBuffer GetCompressedOutput();
|
||||
// The sprite serializer is a special case because it is needed by the VM to handle its 'spriteid' type.
|
||||
virtual FSerializer &Sprite(const char *key, int32_t &spritenum, int32_t *def);
|
||||
// This is only needed by the type system.
|
||||
virtual FSerializer& StatePointer(const char* key, void* ptraddr, bool *res);
|
||||
|
||||
FSerializer &StringPtr(const char *key, const char *&charptr); // This only retrieves the address but creates no permanent copy of the string unlike the regular char* serializer.
|
||||
FSerializer &AddString(const char *key, const char *charptr);
|
||||
const char *GetString(const char *key);
|
||||
|
@ -173,6 +183,8 @@ public:
|
|||
int mErrors = 0;
|
||||
};
|
||||
|
||||
FSerializer& Serialize(FSerializer& arc, const char* key, char& value, char* defval);
|
||||
|
||||
FSerializer &Serialize(FSerializer &arc, const char *key, bool &value, bool *defval);
|
||||
FSerializer &Serialize(FSerializer &arc, const char *key, int64_t &value, int64_t *defval);
|
||||
FSerializer &Serialize(FSerializer &arc, const char *key, uint64_t &value, uint64_t *defval);
|
||||
|
@ -191,7 +203,6 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FSoundID &sid, FSoundI
|
|||
FSerializer &Serialize(FSerializer &arc, const char *key, FString &sid, FString *def);
|
||||
FSerializer &Serialize(FSerializer &arc, const char *key, NumericValue &sid, NumericValue *def);
|
||||
|
||||
|
||||
template<class T>
|
||||
FSerializer &Serialize(FSerializer &arc, const char *key, T *&value, T **)
|
||||
{
|
||||
|
@ -229,6 +240,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, TArray<T, TT> &value,
|
|||
|
||||
template<> FSerializer& Serialize(FSerializer& arc, const char* key, PClass*& clst, PClass** def);
|
||||
template<> FSerializer& Serialize(FSerializer& arc, const char* key, FFont*& font, FFont** def);
|
||||
template<> FSerializer &Serialize(FSerializer &arc, const char *key, Dictionary *&dict, Dictionary **def);
|
||||
|
||||
inline FSerializer &Serialize(FSerializer &arc, const char *key, DVector3 &p, DVector3 *def)
|
||||
{
|
||||
|
@ -298,4 +310,7 @@ inline SaveRecord::SaveRecord(const char* nm, void (*handler)(FSerializer& arc))
|
|||
saveRecords.records.Push(this);
|
||||
}
|
||||
|
||||
FString DictionaryToString(const Dictionary &dict);
|
||||
Dictionary *DictionaryFromString(const FString &string);
|
||||
|
||||
#endif
|
240
source/common/engine/serializer_internal.h
Normal file
240
source/common/engine/serializer_internal.h
Normal file
|
@ -0,0 +1,240 @@
|
|||
const char* UnicodeToString(const char* cc);
|
||||
const char* StringToUnicode(const char* cc, int size = -1);
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
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, although it is needed by special serializers.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
struct FWriter
|
||||
{
|
||||
typedef rapidjson::Writer<rapidjson::StringBuffer, rapidjson::UTF8<> > Writer;
|
||||
typedef rapidjson::PrettyWriter<rapidjson::StringBuffer, rapidjson::UTF8<> > PrettyWriter;
|
||||
|
||||
Writer *mWriter1;
|
||||
PrettyWriter *mWriter2;
|
||||
TArray<bool> mInObject;
|
||||
rapidjson::StringBuffer mOutString;
|
||||
TArray<DObject *> mDObjects;
|
||||
TMap<DObject *, int> mObjectMap;
|
||||
|
||||
FWriter(bool pretty)
|
||||
{
|
||||
if (!pretty)
|
||||
{
|
||||
mWriter1 = new Writer(mOutString);
|
||||
mWriter2 = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
mWriter1 = nullptr;
|
||||
mWriter2 = new PrettyWriter(mOutString);
|
||||
}
|
||||
}
|
||||
|
||||
~FWriter()
|
||||
{
|
||||
if (mWriter1) delete mWriter1;
|
||||
if (mWriter2) delete mWriter2;
|
||||
}
|
||||
|
||||
|
||||
bool inObject() const
|
||||
{
|
||||
return mInObject.Size() > 0 && mInObject.Last();
|
||||
}
|
||||
|
||||
void StartObject()
|
||||
{
|
||||
if (mWriter1) mWriter1->StartObject();
|
||||
else if (mWriter2) mWriter2->StartObject();
|
||||
}
|
||||
|
||||
void EndObject()
|
||||
{
|
||||
if (mWriter1) mWriter1->EndObject();
|
||||
else if (mWriter2) mWriter2->EndObject();
|
||||
}
|
||||
|
||||
void StartArray()
|
||||
{
|
||||
if (mWriter1) mWriter1->StartArray();
|
||||
else if (mWriter2) mWriter2->StartArray();
|
||||
}
|
||||
|
||||
void EndArray()
|
||||
{
|
||||
if (mWriter1) mWriter1->EndArray();
|
||||
else if (mWriter2) mWriter2->EndArray();
|
||||
}
|
||||
|
||||
void Key(const char *k)
|
||||
{
|
||||
if (mWriter1) mWriter1->Key(k);
|
||||
else if (mWriter2) mWriter2->Key(k);
|
||||
}
|
||||
|
||||
void Null()
|
||||
{
|
||||
if (mWriter1) mWriter1->Null();
|
||||
else if (mWriter2) mWriter2->Null();
|
||||
}
|
||||
|
||||
void StringU(const char *k, bool encode)
|
||||
{
|
||||
if (encode) k = StringToUnicode(k);
|
||||
if (mWriter1) mWriter1->String(k);
|
||||
else if (mWriter2) mWriter2->String(k);
|
||||
}
|
||||
|
||||
void String(const char *k)
|
||||
{
|
||||
k = StringToUnicode(k);
|
||||
if (mWriter1) mWriter1->String(k);
|
||||
else if (mWriter2) mWriter2->String(k);
|
||||
}
|
||||
|
||||
void String(const char *k, int size)
|
||||
{
|
||||
k = StringToUnicode(k, size);
|
||||
if (mWriter1) mWriter1->String(k);
|
||||
else if (mWriter2) mWriter2->String(k);
|
||||
}
|
||||
|
||||
void Bool(bool k)
|
||||
{
|
||||
if (mWriter1) mWriter1->Bool(k);
|
||||
else if (mWriter2) mWriter2->Bool(k);
|
||||
}
|
||||
|
||||
void Int(int32_t k)
|
||||
{
|
||||
if (mWriter1) mWriter1->Int(k);
|
||||
else if (mWriter2) mWriter2->Int(k);
|
||||
}
|
||||
|
||||
void Int64(int64_t k)
|
||||
{
|
||||
if (mWriter1) mWriter1->Int64(k);
|
||||
else if (mWriter2) mWriter2->Int64(k);
|
||||
}
|
||||
|
||||
void Uint(uint32_t k)
|
||||
{
|
||||
if (mWriter1) mWriter1->Uint(k);
|
||||
else if (mWriter2) mWriter2->Uint(k);
|
||||
}
|
||||
|
||||
void Uint64(int64_t k)
|
||||
{
|
||||
if (mWriter1) mWriter1->Uint64(k);
|
||||
else if (mWriter2) mWriter2->Uint64(k);
|
||||
}
|
||||
|
||||
void Double(double k)
|
||||
{
|
||||
if (mWriter1)
|
||||
{
|
||||
mWriter1->Double(k);
|
||||
}
|
||||
else if (mWriter2)
|
||||
{
|
||||
mWriter2->Double(k);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
struct FReader
|
||||
{
|
||||
TArray<FJSONObject> mObjects;
|
||||
rapidjson::Document mDoc;
|
||||
TArray<DObject *> mDObjects;
|
||||
rapidjson::Value *mKeyValue = nullptr;
|
||||
bool mObjectsRead = false;
|
||||
|
||||
FReader(const char *buffer, size_t length)
|
||||
{
|
||||
mDoc.Parse(buffer, length);
|
||||
mObjects.Push(FJSONObject(&mDoc));
|
||||
}
|
||||
|
||||
rapidjson::Value *FindKey(const char *key)
|
||||
{
|
||||
FJSONObject &obj = mObjects.Last();
|
||||
|
||||
if (obj.mObject->IsObject())
|
||||
{
|
||||
if (key == nullptr)
|
||||
{
|
||||
// we are performing an iteration of the object through GetKey.
|
||||
auto p = mKeyValue;
|
||||
mKeyValue = nullptr;
|
||||
return p;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Find the given key by name;
|
||||
auto it = obj.mObject->FindMember(key);
|
||||
if (it == obj.mObject->MemberEnd()) return nullptr;
|
||||
return &it->value;
|
||||
}
|
||||
}
|
||||
else if (obj.mObject->IsArray() && (unsigned)obj.mIndex < obj.mObject->Size())
|
||||
{
|
||||
return &(*obj.mObject)[obj.mIndex++];
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
template<class T>
|
||||
FSerializer &SerializePointer(FSerializer &arc, const char *key, T *&value, T **defval, T *base)
|
||||
{
|
||||
assert(base != nullptr);
|
||||
if (arc.isReading() || !arc.w->inObject() || defval == nullptr || value != *defval)
|
||||
{
|
||||
int64_t vv = value == nullptr ? -1 : value - base;
|
||||
Serialize(arc, key, vv, nullptr);
|
||||
value = vv < 0 ? nullptr : base + vv;
|
||||
}
|
||||
return arc;
|
||||
}
|
||||
|
218
source/common/scripting/core/dictionary.cpp
Normal file
218
source/common/scripting/core/dictionary.cpp
Normal file
|
@ -0,0 +1,218 @@
|
|||
#include "dictionary.h"
|
||||
|
||||
#include "vm.h"
|
||||
#include "serializer.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
//=====================================================================================
|
||||
//
|
||||
// DObject implementations for Dictionary and DictionaryIterator
|
||||
//
|
||||
//=====================================================================================
|
||||
|
||||
IMPLEMENT_CLASS(Dictionary, false, false);
|
||||
|
||||
IMPLEMENT_CLASS(DictionaryIterator, false, true);
|
||||
|
||||
IMPLEMENT_POINTERS_START(DictionaryIterator)
|
||||
IMPLEMENT_POINTER(Dict)
|
||||
IMPLEMENT_POINTERS_END
|
||||
|
||||
//=====================================================================================
|
||||
//
|
||||
// Dictionary functions
|
||||
//
|
||||
//=====================================================================================
|
||||
|
||||
void Dictionary::Serialize(FSerializer &arc)
|
||||
{
|
||||
Super::Serialize(arc);
|
||||
|
||||
constexpr char key[] { "dictionary" };
|
||||
|
||||
if (arc.isWriting())
|
||||
{
|
||||
// Pass this instance to serializer.
|
||||
Dictionary *pointerToThis = this;
|
||||
arc(key, pointerToThis);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Receive new Dictionary, copy contents, clean up.
|
||||
Dictionary *pointerToDeserializedDictionary;
|
||||
arc(key, pointerToDeserializedDictionary);
|
||||
Map.TransferFrom(pointerToDeserializedDictionary->Map);
|
||||
delete pointerToDeserializedDictionary;
|
||||
}
|
||||
}
|
||||
|
||||
static Dictionary *DictCreate()
|
||||
{
|
||||
Dictionary *dict { Create<Dictionary>() };
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
static void DictInsert(Dictionary *dict, const FString &key, const FString &value)
|
||||
{
|
||||
dict->Map.Insert(key, value);
|
||||
}
|
||||
|
||||
static void DictAt(const Dictionary *dict, const FString &key, FString *result)
|
||||
{
|
||||
const FString *value = dict->Map.CheckKey(key);
|
||||
*result = value ? *value : "";
|
||||
}
|
||||
|
||||
static void DictToString(const Dictionary *dict, FString *result)
|
||||
{
|
||||
*result = DictionaryToString(*dict);
|
||||
}
|
||||
|
||||
static void DictRemove(Dictionary *dict, const FString &key)
|
||||
{
|
||||
dict->Map.Remove(key);
|
||||
}
|
||||
|
||||
//=====================================================================================
|
||||
//
|
||||
// Dictionary exports
|
||||
//
|
||||
//=====================================================================================
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(_Dictionary, Create, DictCreate)
|
||||
{
|
||||
ACTION_RETURN_POINTER(DictCreate());
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(_Dictionary, Insert, DictInsert)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(Dictionary);
|
||||
PARAM_STRING(key);
|
||||
PARAM_STRING(value);
|
||||
DictInsert(self, key, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(_Dictionary, At, DictAt)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(Dictionary);
|
||||
PARAM_STRING(key);
|
||||
FString result;
|
||||
DictAt(self, key, &result);
|
||||
ACTION_RETURN_STRING(result);
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(_Dictionary, ToString, DictToString)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(Dictionary);
|
||||
FString result;
|
||||
DictToString(self, &result);
|
||||
ACTION_RETURN_STRING(result);
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(_Dictionary, FromString, DictionaryFromString)
|
||||
{
|
||||
PARAM_PROLOGUE;
|
||||
PARAM_STRING(string);
|
||||
ACTION_RETURN_POINTER(DictionaryFromString(string));
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(_Dictionary, Remove, DictRemove)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(Dictionary);
|
||||
PARAM_STRING(key);
|
||||
DictRemove(self, key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=====================================================================================
|
||||
//
|
||||
// DictionaryIterator functions
|
||||
//
|
||||
//=====================================================================================
|
||||
|
||||
DictionaryIterator::DictionaryIterator()
|
||||
: Iterator(nullptr)
|
||||
, Pair(nullptr)
|
||||
, Dict(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
void DictionaryIterator::Serialize(FSerializer &arc)
|
||||
{
|
||||
if (arc.isWriting())
|
||||
{
|
||||
I_Error("Attempt to save pointer to unhandled type DictionaryIterator");
|
||||
}
|
||||
}
|
||||
|
||||
void DictionaryIterator::init(Dictionary *dict)
|
||||
{
|
||||
Iterator = std::make_unique<Dictionary::ConstIterator>(dict->Map);
|
||||
Dict = dict;
|
||||
|
||||
GC::WriteBarrier(this, Dict);
|
||||
}
|
||||
|
||||
static DictionaryIterator *DictIteratorCreate(Dictionary *dict)
|
||||
{
|
||||
DictionaryIterator *iterator = Create<DictionaryIterator>();
|
||||
iterator->init(dict);
|
||||
|
||||
return iterator;
|
||||
}
|
||||
|
||||
static int DictIteratorNext(DictionaryIterator *self)
|
||||
{
|
||||
assert(self->Iterator != nullptr);
|
||||
|
||||
const bool hasNext { self->Iterator->NextPair(self->Pair) };
|
||||
return hasNext;
|
||||
}
|
||||
|
||||
static void DictIteratorKey(const DictionaryIterator *self, FString *result)
|
||||
{
|
||||
*result = self->Pair ? self->Pair->Key : FString {};
|
||||
}
|
||||
|
||||
static void DictIteratorValue(const DictionaryIterator *self, FString *result)
|
||||
{
|
||||
*result = self->Pair ? self->Pair->Value : FString {};
|
||||
}
|
||||
|
||||
//=====================================================================================
|
||||
//
|
||||
// DictionaryIterator exports
|
||||
//
|
||||
//=====================================================================================
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(_DictionaryIterator, Create, DictIteratorCreate)
|
||||
{
|
||||
PARAM_PROLOGUE;
|
||||
PARAM_POINTER(dict, Dictionary);
|
||||
ACTION_RETURN_POINTER(DictIteratorCreate(dict));
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(_DictionaryIterator, Next, DictIteratorNext)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(DictionaryIterator);
|
||||
ACTION_RETURN_BOOL(DictIteratorNext(self));
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(_DictionaryIterator, Key, DictIteratorKey)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(DictionaryIterator);
|
||||
FString result;
|
||||
DictIteratorKey(self, &result);
|
||||
ACTION_RETURN_STRING(result);
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(_DictionaryIterator, Value, DictIteratorValue)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(DictionaryIterator);
|
||||
FString result;
|
||||
DictIteratorValue(self, &result);
|
||||
ACTION_RETURN_STRING(result);
|
||||
}
|
70
source/common/scripting/core/dictionary.h
Normal file
70
source/common/scripting/core/dictionary.h
Normal file
|
@ -0,0 +1,70 @@
|
|||
#pragma once
|
||||
|
||||
#include "tarray.h"
|
||||
#include "zstring.h"
|
||||
#include "dobject.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
/**
|
||||
* @brief The Dictionary class exists to be exported to ZScript.
|
||||
*
|
||||
* It is a string-to-string map.
|
||||
*
|
||||
* It is derived from DObject to be a part of normal GC process.
|
||||
*/
|
||||
class Dictionary final : public DObject
|
||||
{
|
||||
DECLARE_CLASS(Dictionary, DObject)
|
||||
|
||||
public:
|
||||
|
||||
using StringMap = TMap<FString, FString>;
|
||||
using ConstIterator = StringMap::ConstIterator;
|
||||
using ConstPair = StringMap::ConstPair;
|
||||
|
||||
void Serialize(FSerializer &arc) override;
|
||||
|
||||
StringMap Map;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The DictionaryIterator class exists to be exported to ZScript.
|
||||
*
|
||||
* It provides iterating over a Dictionary. The order is not specified.
|
||||
*
|
||||
* It is derived from DObject to be a part of normal GC process.
|
||||
*/
|
||||
class DictionaryIterator final : public DObject
|
||||
{
|
||||
DECLARE_CLASS(DictionaryIterator, DObject)
|
||||
HAS_OBJECT_POINTERS
|
||||
|
||||
public:
|
||||
|
||||
~DictionaryIterator() override = default;
|
||||
|
||||
/**
|
||||
* IMPLEMENT_CLASS macro needs a constructor without parameters.
|
||||
*
|
||||
* @see init().
|
||||
*/
|
||||
DictionaryIterator();
|
||||
|
||||
void Serialize(FSerializer &arc) override;
|
||||
|
||||
/**
|
||||
* @brief init function complements constructor.
|
||||
* @attention always call init after constructing DictionaryIterator.
|
||||
*/
|
||||
void init(Dictionary *dict);
|
||||
|
||||
std::unique_ptr<Dictionary::ConstIterator> Iterator;
|
||||
Dictionary::ConstPair *Pair;
|
||||
|
||||
/**
|
||||
* @brief Dictionary attribute exists for holding a pointer to iterated
|
||||
* dictionary, so it is known by GC.
|
||||
*/
|
||||
Dictionary *Dict;
|
||||
};
|
|
@ -1078,6 +1078,46 @@ bool PName::ReadValue(FSerializer &ar, const char *key, void *addr) const
|
|||
}
|
||||
}
|
||||
|
||||
/* PStatePointer **********************************************************/
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PStatePointer Default Constructor
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
PStatePointer::PStatePointer()
|
||||
{
|
||||
mDescriptiveName = "Pointer<State>";
|
||||
PointedType = NewStruct(NAME_State, nullptr, true);
|
||||
IsConst = true;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PStatePointer :: WriteValue
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void PStatePointer::WriteValue(FSerializer& ar, const char* key, const void* addr) const
|
||||
{
|
||||
ar.StatePointer(key, const_cast<void*>(addr), nullptr);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PStatePointer :: ReadValue
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool PStatePointer::ReadValue(FSerializer& ar, const char* key, void* addr) const
|
||||
{
|
||||
bool res = false;
|
||||
ar.StatePointer(key, addr, &res);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/* PSpriteID ******************************************************************/
|
||||
|
||||
//==========================================================================
|
||||
|
@ -1102,9 +1142,7 @@ PSpriteID::PSpriteID()
|
|||
void PSpriteID::WriteValue(FSerializer &ar, const char *key, const void *addr) const
|
||||
{
|
||||
int32_t val = *(int*)addr;
|
||||
#ifdef GZDOOM
|
||||
ar.Sprite(key, val, nullptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -1116,9 +1154,7 @@ void PSpriteID::WriteValue(FSerializer &ar, const char *key, const void *addr) c
|
|||
bool PSpriteID::ReadValue(FSerializer &ar, const char *key, void *addr) const
|
||||
{
|
||||
int32_t val = 0;
|
||||
#ifdef GZDOOM
|
||||
ar.Sprite(key, val, nullptr);
|
||||
#endif
|
||||
*(int*)addr = val;
|
||||
return true;
|
||||
}
|
||||
|
@ -1440,49 +1476,6 @@ PPointer *NewPointer(PClass *cls, bool isconst)
|
|||
return static_cast<PPointer *>(ptype);
|
||||
}
|
||||
|
||||
/* PStatePointer **********************************************************/
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PStatePointer Default Constructor
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
PStatePointer::PStatePointer()
|
||||
{
|
||||
mDescriptiveName = "Pointer<State>";
|
||||
PointedType = NewStruct(NAME_State, nullptr, true);
|
||||
IsConst = true;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PStatePointer :: WriteValue
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void PStatePointer::WriteValue(FSerializer &ar, const char *key, const void *addr) const
|
||||
{
|
||||
#ifdef GZDOOM
|
||||
ar(key, *(FState **)addr);
|
||||
#endif
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PStatePointer :: ReadValue
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool PStatePointer::ReadValue(FSerializer &ar, const char *key, void *addr) const
|
||||
{
|
||||
bool res = false;
|
||||
#ifdef GZDOOM
|
||||
::Serialize(ar, key, *(FState **)addr, nullptr, &res);
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* PClassPointer **********************************************************/
|
||||
|
|
Loading…
Reference in a new issue