Save inventory data used UserDefault #2751
-
|
How to save JSON object in UserDefault, I have plan to save inventory data but don't know how to implement. Any suggest? |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 2 replies
-
|
What do you mean by JSON object? If it's something like an object that contains a structure ( |
Beta Was this translation helpful? Give feedback.
-
|
Hi, Generally we have a GameData class that we convert it to JSON with RapidJSON and save to some place, locally, remote, UserDefault, etc and method that save/load it to/from JSON. Sample code: // GameData.h
#pragma once
// keep includes minimal and portable
#include <string>
#include <vector>
#include <unordered_map>
#include <fstream>
#include <sstream>
// rapidjson
#include <rapidjson/document.h>
#include <rapidjson/writer.h>
#include <rapidjson/prettywriter.h>
#include <rapidjson/stringbuffer.h>
// axmol
#include "base/UserDefault.h"
#include "platform/FileUtils.h"
namespace ax
{
class GameData
{
public:
// basic game state
int coins = 0;
int level = 1;
// simple collections
std::unordered_map<std::string, int> inventory; // e.g. {"potion": 3, "key": 1}
std::vector<int> completedLevels; // e.g. [1,2,3]
// serialize current state to a compact json string
std::string toJsonString(bool pretty = false) const
{
// build a rapidjson object
rapidjson::Document doc;
doc.SetObject();
auto& alloc = doc.GetAllocator();
// primitives
doc.AddMember("coins", coins, alloc);
doc.AddMember("level", level, alloc);
// inventory as object
rapidjson::Value inv(rapidjson::kObjectType);
for (const auto& kv : inventory)
{
rapidjson::Value k;
k.SetString(kv.first.c_str(), static_cast<rapidjson::SizeType>(kv.first.size()), alloc);
inv.AddMember(k, kv.second, alloc);
}
doc.AddMember("inventory", inv, alloc);
// completed levels as array
rapidjson::Value comp(rapidjson::kArrayType);
for (int lv : completedLevels)
{
comp.PushBack(lv, alloc);
}
doc.AddMember("completedLevels", comp, alloc);
// write to string
rapidjson::StringBuffer buffer;
if (pretty)
{
rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(buffer);
writer.SetIndent(' ', 2);
doc.Accept(writer);
}
else
{
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
doc.Accept(writer);
}
return buffer.GetString();
}
// load state from a json string
bool fromJsonString(const std::string& json)
{
rapidjson::Document doc;
if (doc.Parse(json.c_str()).HasParseError() || !doc.IsObject())
{
return false;
}
// read primitives if present
if (doc.HasMember("coins") && doc["coins"].IsInt()) coins = doc["coins"].GetInt();
if (doc.HasMember("level") && doc["level"].IsInt()) level = doc["level"].GetInt();
// read inventory
inventory.clear();
if (doc.HasMember("inventory") && doc["inventory"].IsObject())
{
for (auto it = doc["inventory"].MemberBegin(); it != doc["inventory"].MemberEnd(); ++it)
{
if (it->value.IsInt())
{
inventory[it->name.GetString()] = it->value.GetInt();
}
}
}
// read completed levels
completedLevels.clear();
if (doc.HasMember("completedLevels") && doc["completedLevels"].IsArray())
{
for (auto& v : doc["completedLevels"].GetArray())
{
if (v.IsInt()) completedLevels.push_back(v.GetInt());
}
}
return true;
}
// save to axmol user defaults (persistent key-value store)
bool saveToUserDefault(const std::string& key, bool pretty = false) const
{
const auto json = toJsonString(pretty);
UserDefault::getInstance()->setStringForKey(key.c_str(), json);
UserDefault::getInstance()->flush();
return true;
}
// load from axmol user defaults
bool loadFromUserDefault(const std::string& key)
{
const auto json = UserDefault::getInstance()->getStringForKey(key.c_str(), "");
if (json.empty()) return false;
return fromJsonString(json);
}
// save to a file in writable path
bool saveToFile(const std::string& relativePath, bool pretty = false) const
{
const auto full = FileUtils::getInstance()->getWritablePath() + relativePath;
std::ofstream ofs(full, std::ios::binary);
if (!ofs.is_open()) return false;
const auto json = toJsonString(pretty);
ofs.write(json.data(), static_cast<std::streamsize>(json.size()));
return ofs.good();
}
// load from a file in writable path
bool loadFromFile(const std::string& relativePath)
{
const auto full = FileUtils::getInstance()->getWritablePath() + relativePath;
std::ifstream ifs(full, std::ios::binary);
if (!ifs.is_open()) return false;
std::stringstream ss;
ss << ifs.rdbuf();
return fromJsonString(ss.str());
}
// convenient reset
void resetDefaults()
{
coins = 0;
level = 1;
inventory.clear();
completedLevels.clear();
}
};
} // namespace ax |
Beta Was this translation helpful? Give feedback.
Hi,
Generally we have a GameData class that we convert it to JSON with RapidJSON and save to some place, locally, remote, UserDefault, etc and method that save/load it to/from JSON.
Sample code: