Files
GTASource/game/SaveLoad/savegame_scriptdatafile.cpp

606 lines
12 KiB
C++
Raw Permalink Normal View History

2025-02-23 17:40:52 +08:00
//
// sample_parser/datadicts.cpp
//
// Copyright (C) 1999-2011 Rockstar Games. All Rights Reserved.
//
#include "savegame_scriptdatafile.h"
#include "savegame_scriptdatafile_parser.h"
// Rage headers
#include "data/rson.h"
#include "diag/output.h"
#include "file/asset.h"
#include "fwnet/netchannel.h"
#include "parsercore/streamxml.h"
#include "system/nelem.h"
#include "system/param.h"
SAVEGAME_OPTIMISATIONS()
NETWORK_OPTIMISATIONS()
#if __BANK
PARAM(outputCloudFiles, "Write cloud files to PC harddisk for debugging");
#endif
static void PutNewline(fiStream& out, bool prettyPrint)
{
if (prettyPrint)
{
out.FastPutCh('\n');
}
}
static void PutIndent(fiStream& out, bool prettyPrint, int indent)
{
if (!prettyPrint)
return;
for (int i = 0; i < indent; i++)
out.FastPutCh('\t');
}
const char* const sveNode::sm_TypeNames[] = {
"none",
"bool",
"int",
"float",
"string",
"vec3",
"dict",
"array",
};
atFinalHashString finalHashStringOfX("x");
atFinalHashString finalHashStringOfY("y");
atFinalHashString finalHashStringOfZ("z");
sveNode* sveNode::ReadJsonValue(RsonReader& reader)
{
// look at the first characters in the value to decide what kind of node to create
char valueBuf[32];
reader.GetRawValueString(valueBuf, NELEM(valueBuf));
char firstChar = valueBuf[0];
switch(firstChar)
{
case '\0':
Errorf("No value found!");
return rage_new sveString();
case '\"':
return sveString::ReadJsonStringValue(reader);
case 't':
case 'f':
return sveBool::ReadJsonBoolValue(reader);
case '{':
{
sveDict* dict = sveDict::ReadJsonDictValue(reader);
// check to see if its really a vec3
if (dict->GetCount() != 3)
{
return dict;
}
sveNode* x = (*dict)[finalHashStringOfX];
if (!x || x->GetType() != SVE_FLOAT)
{
return dict;
}
sveNode* y = (*dict)[finalHashStringOfY];
if (!y || y->GetType() != SVE_FLOAT)
{
return dict;
}
sveNode* z = (*dict)[finalHashStringOfZ];
if (!z || z->GetType() != SVE_FLOAT)
{
return dict;
}
sveNode* vec = rage_new sveVec3(Vec3V(x->Downcast<sveFloat>()->GetValue(), y->Downcast<sveFloat>()->GetValue(), z->Downcast<sveFloat>()->GetValue()));
delete dict;
return vec;
}
case '[':
return sveArray::ReadJsonArrayValue(reader);
default:
if (stricmp(valueBuf, "null") == 0)
{ // Graeme - I need this check when retrieving the contents of the photo directory from the cloud. If the directory is empty, the value is null
return rage_new sveInt(0);
}
if (!Verifyf(firstChar == '-' || (firstChar >= '0' && firstChar <= '9'), "Unexpected start of value string: %.10s", valueBuf))
{
return rage_new sveInt(0);
}
// scan as an int
// then check the next char, if it's a '.', 'E' or 'e', go back and scan as a float
char* endInt = NULL;
strtol(valueBuf, &endInt, 0);
if (!Verifyf(endInt != NULL, "Couldn't convert valueBuf: %s", valueBuf))
{
Errorf("Couldn't convert valueBuf: %s", valueBuf);
return rage_new sveInt(0);
}
if (*endInt == '.' || *endInt == 'E' || *endInt == 'e')
{
return sveFloat::ReadJsonFloatValue(reader);
}
else
{
return sveInt::ReadJsonIntValue(reader);
}
}
}
void sveBool::WriteJson( fiStream& out, int /*indent*/, bool /*prettyPrint */) const
{
fprintf(&out, m_Value ? "true" : "false");
}
sveBool* sveBool::ReadJsonBoolValue(RsonReader& reader)
{
bool val;
if (reader.AsBool(val))
{
return rage_new sveBool(val);
}
Errorf("Couldn't read bool value from JSON");
return rage_new sveBool(false);
}
void sveInt::WriteJson( fiStream& out, int /*indent*/, bool /*prettyPrint*/ ) const
{
fprintf(&out, "%d", m_Value);
}
sveInt* sveInt::ReadJsonIntValue(RsonReader& reader)
{
int val;
if (reader.AsInt(val))
{
return rage_new sveInt(val);
}
Errorf("Couldn't read int value from JSON");
return rage_new sveInt(0);
}
void sveFloat::WriteJson( fiStream& out, int /*indent*/, bool /*prettyPrint*/ ) const
{
if(Abs(m_Value) < SMALL_FLOAT)
{
fprintf(&out, "0.0");
}
else
{
fprintf(&out, "%.3f", m_Value);
}
}
sveFloat* sveFloat::ReadJsonFloatValue(RsonReader& reader)
{
float val;
if (reader.AsFloat(val))
{
return rage_new sveFloat(val);
}
Errorf("Couldn't read float value from JSON");
return rage_new sveFloat(0.0f);
}
void sveString::WriteJson( fiStream& out, int /*indent*/, bool /*prettyPrint*/ ) const
{
out.FastPutCh('"');
for(const char* c = m_Value; *c; ++c)
{
switch(*c)
{
case '"':
out.FastPutCh('\\');
out.FastPutCh('"');
break;
case '\\':
out.FastPutCh('\\');
out.FastPutCh('\\');
break;
case '\n':
out.FastPutCh('\\');
out.FastPutCh('n');
break;
case '\r':
out.FastPutCh('\\');
out.FastPutCh('r');
break;
case '\t':
out.FastPutCh('\\');
out.FastPutCh('t');
break;
case '\f':
out.FastPutCh('\\');
out.FastPutCh('f');
break;
default:
out.FastPutCh(*c);
}
}
out.FastPutCh('"');
}
sveString* sveString::ReadJsonStringValue(RsonReader& reader)
{
int length = reader.GetValueLength();
if (length)
{
char* buf = rage_new char[length+1];
sveString* strNode = NULL;
if (reader.GetValue(buf, length+1))
{
strNode = rage_new sveString(buf);
}
delete buf;
return strNode;
}
else
{
return rage_new sveString();
}
}
void sveVec3::WriteJson( fiStream& out, int /*indent*/, bool /*prettyPrint*/ ) const
{
fprintf(&out, "{");
if(Abs(m_Value.GetXf()) < SMALL_FLOAT)
{
fprintf(&out, "\"x\":0.0");
}
else
{
fprintf(&out, "\"x\":%.3f", m_Value.GetXf());
}
if(Abs(m_Value.GetYf()) < SMALL_FLOAT)
{
fprintf(&out, ",\"y\":0.0");
}
else
{
fprintf(&out, ",\"y\":%.3f", m_Value.GetYf());
}
if(Abs(m_Value.GetZf()) < SMALL_FLOAT)
{
fprintf(&out, ",\"z\":0.0");
}
else
{
fprintf(&out, ",\"z\":%.3f", m_Value.GetZf());
}
fprintf(&out, "}");
}
sveDict::~sveDict()
{
for(ValueMap::Iterator iter = m_Values.CreateIterator(); !iter.AtEnd(); iter.Next())
{
delete (*iter);
}
}
void sveDict::Insert( rage::atFinalHashString name, bool val )
{
sveNode* newNode = rage_new sveBool(val);
Insert(name, newNode);
}
void sveDict::Insert( rage::atFinalHashString name, int val )
{
sveNode* newNode = rage_new sveInt(val);
Insert(name, newNode);
}
void sveDict::Insert( rage::atFinalHashString name, float val )
{
sveNode* newNode = rage_new sveFloat(val);
Insert(name, newNode);
}
void sveDict::Insert( rage::atFinalHashString name, rage::Vec3V_In val )
{
sveNode* newNode = rage_new sveVec3(val);
Insert(name, newNode);
}
void sveDict::Insert( rage::atFinalHashString name, const char* val )
{
sveNode* newNode = rage_new sveString(val);
Insert(name, newNode);
}
void sveDict::Remove( rage::atFinalHashString name )
{
sveNode** oldNode = m_Values.Access(name);
if (oldNode)
{
delete *oldNode;
m_Values.Delete(name);
}
}
struct sveDictPair {
const char* name;
sveNode* data;
};
bool SveNodeSort(const sveDictPair& a, const sveDictPair& b)
{
if (AssertVerify(a.name) && AssertVerify(b.name))
{
return strcmp(a.name, b.name) < 0;
}
return false;
}
void sveDict::WriteJson( fiStream& out, int indent, bool prettyPrint ) const
{
int numKids = m_Values.GetNumUsed();
if (numKids > 0)
{
if (indent > 0)
PutNewline(out, prettyPrint);
PutIndent(out, prettyPrint, indent);
}
fprintf(&out, "{");
indent++;
if (numKids > 0)
PutNewline(out, prettyPrint);
sveDictPair* pairs = Alloca(sveDictPair, numKids);
int currKid = 0;
for(ValueMap::ConstIterator iter = m_Values.CreateIterator(); !iter.AtEnd(); iter.Next())
{
pairs[currKid].name = iter.GetKey().GetCStr();
pairs[currKid].data = iter.GetData();
currKid++;
}
std::sort(pairs, pairs + numKids, SveNodeSort);
for(int i = 0; i < numKids; i++)
{
PutIndent(out, prettyPrint, indent);
fprintf(&out, "\"%s\":", pairs[i].name);
pairs[i].data->WriteJson(out, indent, prettyPrint);
if (i != numKids-1)
{
// not the last element
out.FastPutCh(',');
PutNewline(out, prettyPrint);
}
}
indent--;
if (numKids > 0)
{
PutNewline(out, prettyPrint);
PutIndent(out, prettyPrint, indent);
}
fprintf(&out, "}");
}
sveDict* sveDict::ReadJsonDictValue(RsonReader& reader)
{
sveDict* newDict = rage_new sveDict;
RsonReader child;
if (!reader.GetFirstMember(&child))
{
return newDict;
}
do
{
char nameBuf[128];
if (child.GetName(nameBuf, 128))
{
sveNode* childNode = sveNode::ReadJsonValue(child);
newDict->Insert(atFinalHashString(nameBuf), childNode);
}
}
while(child.GetNextSibling(&child));
return newDict;
}
////////////////////////// sCloudFile /////////////////////////////////////////////
std::unique_ptr<sCloudFile> sCloudFile::LoadFile(const void* pData, unsigned nDataSize, const char* OUTPUT_ONLY(szName))
{
// log out
DIAG_CONTEXT_MESSAGE("Reading JSON document from %s", szName);
#if __BANK
if (PARAM_outputCloudFiles.Get())
OutputCloudFile(pData, nDataSize, szName);
#endif
// validate the JSON file
if (!gnetVerifyf(RsonReader::ValidateJson(static_cast<const char*>(pData), nDataSize), "sCloudFile::LoadFile :: Error parsing %s. Include cloud_ValidateError.log in the logs.", szName))
{
OUTPUT_ONLY(OutputCloudFile(pData, nDataSize, "ValidateError");)
gnetError("sCloudFile::LoadFile :: Error parsing %s. Include cloud_ValidateError.log in the logs.", szName);
return nullptr;
}
RsonReader reader;
if (!reader.Init(static_cast<const char*>(pData), 0, nDataSize))
{
gnetError("sCloudFile::LoadFile :: Failed to initialised RsonReader for %s.", szName);
return nullptr;
}
// create our save file
return sCloudFile::ReadJsonFileValue(reader);
}
std::unique_ptr<sCloudFile> sCloudFile::ReadJsonFileValue(RsonReader& reader)
{
std::unique_ptr<sCloudFile> pFile(rage_new sCloudFile);
RsonReader child;
if (!reader.GetFirstMember(&child))
return pFile;
do
{
char nameBuf[128];
if (child.GetName(nameBuf, 128))
{
sveNode* pChildNode = sveNode::ReadJsonValue(child);
if (pChildNode)
pFile->Insert(atFinalHashString(nameBuf), pChildNode);
else
{
return nullptr;
}
}
} while (child.GetNextSibling(&child));
// finished, return our file
return pFile;
}
void sCloudFile::OutputCloudFile(const void* pData, unsigned nDataSize, const char* szName)
{
// build an output name
static const unsigned kMaxName = 128;
char szOutputName[kMaxName];
snprintf(szOutputName, kMaxName, "cloud_%s.log", szName);
// log to file
fiStream* pStream(ASSET.Create(szOutputName, ""));
if (pStream)
{
pStream->Write(pData, nDataSize);
pStream->Close();
}
}
////////////////////////// sveArray /////////////////////////////////////////////
sveArray::~sveArray()
{
for(int i = 0; i < m_Values.GetCount(); i++)
{
delete m_Values[i];
}
}
void sveArray::Append( bool val )
{
sveNode* newNode = rage_new sveBool(val);
Append(newNode);
}
void sveArray::Append( int val )
{
sveNode* newNode = rage_new sveInt(val);
Append(newNode);
}
void sveArray::Append( float val )
{
sveNode* newNode = rage_new sveFloat(val);
Append(newNode);
}
void sveArray::Append( rage::Vec3V_In val )
{
sveNode* newNode = rage_new sveVec3(val);
Append(newNode);
}
void sveArray::Append( const char* val )
{
sveNode* newNode = rage_new sveString(val);
Append(newNode);
}
void sveArray::Remove( int index )
{
delete m_Values[index];
m_Values.Delete(index);
}
void sveArray::WriteJson( fiStream& out, int indent, bool prettyPrint ) const
{
int numKids = m_Values.GetCount();
if (numKids == 0)
{
PutIndent(out, prettyPrint, indent);
fprintf(&out, "[]");
return;
}
PutNewline(out, prettyPrint);
PutIndent(out, prettyPrint, indent);
fprintf(&out, "[");
PutNewline(out, prettyPrint);
indent++;
for(int i = 0; i < numKids; i++)
{
PutIndent(out, prettyPrint, indent);
m_Values[i]->WriteJson(out, indent, prettyPrint);
if (i != numKids-1)
{
// not the last element
out.FastPutCh(',');
PutNewline(out, prettyPrint);
}
}
indent--;
PutNewline(out, prettyPrint);
PutIndent(out, prettyPrint, indent);
fprintf(&out, "]");
}
sveArray* sveArray::ReadJsonArrayValue(RsonReader& reader)
{
sveArray* newArr = rage_new sveArray;
RsonReader child;
if (!reader.GetFirstMember(&child))
{
return newArr;
}
do
{
sveNode* childNode = sveNode::ReadJsonValue(child);
if(Verifyf(childNode, "Invalid child node"))
{
newArr->Append(childNode);
}
}
while(child.GetNextSibling(&child));
return newArr;
}