Browse Source

Experimental drafts of Json serializer

AlexVinS 9 years ago
parent
commit
22b93106c8

+ 9 - 9
Global.h

@@ -55,7 +55,7 @@ static_assert(sizeof(bool) == 1, "Bool needs to be 1 byte in size.");
 #  define VCMI_UNIX
 #  define VCMI_XDG
 #  ifdef __ANDROID__
-#    define VCMI_ANDROID 
+#    define VCMI_ANDROID
 #  endif
 #elif defined(__FreeBSD_kernel__) || defined(__FreeBSD__)
 #  define VCMI_UNIX
@@ -285,7 +285,7 @@ std::ostream & operator<<(std::ostream & out, const std::vector<T> & container)
 
 namespace vstd
 {
-	
+
 	// combine hashes. Present in boost but not in std
 	template <class T>
 	inline void hash_combine(std::size_t& seed, const T& v)
@@ -293,7 +293,7 @@ namespace vstd
 		std::hash<T> hasher;
 		seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
 	}
-	
+
 	//returns true if container c contains item i
 	template <typename Container, typename Item>
 	bool contains(const Container & c, const Item &i)
@@ -505,7 +505,7 @@ namespace vstd
 	void erase_if(std::set<Elem> &setContainer, Predicate pred)
 	{
 		auto itr = setContainer.begin();
-		auto endItr = setContainer.end(); 
+		auto endItr = setContainer.end();
 		while(itr != endItr)
 		{
 			auto tmpItr = itr++;
@@ -519,7 +519,7 @@ namespace vstd
 	void erase_if(std::map<Key, Val> &container, Predicate pred)
 	{
 		auto itr = container.begin();
-		auto endItr = container.end(); 
+		auto endItr = container.end();
 		while(itr != endItr)
 		{
 			auto tmpItr = itr++;
@@ -554,7 +554,7 @@ namespace vstd
 			return vf(lhs) < vf(rhs);
 		});
 	}
-		
+
 	//Returns iterator to the element for which the value of ValueFunction is maximal
 	template<class ForwardRange, class ValueFunction>
 	auto maxElementByFun(const ForwardRange& rng, ValueFunction vf) -> decltype(std::begin(rng))
@@ -627,7 +627,7 @@ namespace vstd
 	{
 		if(index < r.size())
 			return r[index];
-		
+
 		return defaultValue;
 	}
 
@@ -668,12 +668,12 @@ namespace vstd
 		boost::sort(vec);
 		vec.erase(std::unique(vec.begin(), vec.end()), vec.end());
 	}
-	
+
 	template <typename T>
 	void concatenate(std::vector<T> &dest, const std::vector<T> &src)
 	{
 		dest.reserve(dest.size() + src.size());
-		dest.insert(dest.end(), src.begin(), src.end());	
+		dest.insert(dest.end(), src.begin(), src.end());
 	}
 
 	template <typename T>

+ 4 - 0
lib/CMakeLists.txt

@@ -104,6 +104,10 @@ set(lib_SRCS
 		Connection.cpp
 		NetPacksLib.cpp
 
+		serializer/JsonSerializer.cpp
+		serializer/JsonDeserializer.cpp
+		serializer/JsonSerializeFormat.cpp
+
 		registerTypes/RegisterTypes.cpp
 		registerTypes/TypesClientPacks1.cpp
 		registerTypes/TypesClientPacks2.cpp

+ 7 - 0
lib/VCMI_lib.cbp

@@ -152,6 +152,7 @@
 		<Unit filename="CGeneralTextHandler.h" />
 		<Unit filename="CHeroHandler.cpp" />
 		<Unit filename="CHeroHandler.h" />
+		<Unit filename="CMakeLists.txt" />
 		<Unit filename="CModHandler.cpp" />
 		<Unit filename="CModHandler.h" />
 		<Unit filename="CObstacleInstance.cpp" />
@@ -315,6 +316,12 @@
 		<Unit filename="rmg/CZoneGraphGenerator.h" />
 		<Unit filename="rmg/CZonePlacer.cpp" />
 		<Unit filename="rmg/CZonePlacer.h" />
+		<Unit filename="serializer/JsonDeserializer.cpp" />
+		<Unit filename="serializer/JsonDeserializer.h" />
+		<Unit filename="serializer/JsonSerializeFormat.cpp" />
+		<Unit filename="serializer/JsonSerializeFormat.h" />
+		<Unit filename="serializer/JsonSerializer.cpp" />
+		<Unit filename="serializer/JsonSerializer.h" />
 		<Unit filename="spells/AdventureSpellMechanics.cpp" />
 		<Unit filename="spells/AdventureSpellMechanics.h" />
 		<Unit filename="spells/BattleSpellMechanics.cpp" />

+ 75 - 64
lib/mapping/MapFormatJson.cpp

@@ -23,8 +23,31 @@
 #include "../mapObjects/CObjectClassesHandler.h"
 #include "../mapObjects/CGHeroInstance.h"
 #include "../mapObjects/CGTownInstance.h"
-
 #include "../StringConstants.h"
+#include "../serializer/JsonDeserializer.h"
+#include "../serializer/JsonSerializer.h"
+
+namespace HeaderDetail
+{
+	static const std::map<std::string, ui8> difficultyReverseMap =
+	{
+		{"", 1},
+		{"EASY", 0},
+		{"NORMAL", 1},
+		{"HARD", 2},
+		{"EXPERT", 3},
+		{"IMPOSSIBLE", 4}
+	};
+
+	static const std::map<ui8, std::string> difficultyForwardMap =
+	{
+		{0, "EASY"},
+		{1, "NORMAL"},
+		{2, "HARD"},
+		{3, "EXPERT"},
+		{4, "IMPOSSIBLE"}
+	};
+}
 
 namespace TriggeredEventsDetail
 {
@@ -46,7 +69,7 @@ namespace TriggeredEventsDetail
 
 		auto pos = vstd::find_pos(conditionNames, conditionName);
 
-		event.condition = EventCondition::EWinLoseType(pos));
+		event.condition = EventCondition::EWinLoseType(pos);
 		if (node.Vector().size() > 1)
 		{
 			const JsonNode & data = node.Vector()[1];
@@ -272,7 +295,7 @@ std::unique_ptr<CMapHeader> CMapLoaderJson::loadMapHeader()
 	return std::move(mapHeader);
 }
 
-const JsonNode CMapLoaderJson::readJson(const std::string & archiveFilename)
+const JsonNode CMapLoaderJson::getFromArchive(const std::string & archiveFilename)
 {
 	ResourceID resource(archiveFilename, EResType::TEXT);
 
@@ -306,93 +329,89 @@ void CMapLoaderJson::readMap()
 void CMapLoaderJson::readHeader()
 {
 	//do not use map field here, use only mapHeader
-	const JsonNode header = readJson(HEADER_FILE_NAME);
+	JsonNode header = getFromArchive(HEADER_FILE_NAME);
+	JsonDeserializer handler(header);
 
 	mapHeader->version = EMapFormat::VCMI;//todo: new version field
 
 	//todo: multilevel map load support
-	const JsonNode levels = header["mapLevels"];
-	mapHeader->height = levels["surface"]["height"].Float();
-	mapHeader->width = levels["surface"]["width"].Float();
-	mapHeader->twoLevel = !levels["underground"].isNull();
+	{
+		auto levels = handler.enterStruct("mapLevels");
+
+		{
+			auto surface = levels.enterStruct("surface");
+			mapHeader->height = surface.get()["height"].Float();
+			mapHeader->width = surface.get()["width"].Float();
+		}
+		{
+			auto underground = levels.enterStruct("underground");
+			mapHeader->twoLevel = !underground.get().isNull();
+		}
+	}
 
 	mapHeader->name = header["name"].String();
 	mapHeader->description = header["description"].String();
 
 	//todo: support arbitrary percentage
 
-	static const std::map<std::string, ui8> difficultyMap =
-	{
-		{"", 1},
-		{"EASY", 0},
-		{"NORMAL", 1},
-		{"HARD", 2},
-		{"EXPERT", 3},
-		{"IMPOSSIBLE", 4}
-	};
-
-	mapHeader->difficulty = difficultyMap.at(header["difficulty"].String());
-	mapHeader->levelLimit = header["levelLimit"].Float();
+	mapHeader->difficulty = HeaderDetail::difficultyReverseMap.at(header["difficulty"].String());
+	mapHeader->levelLimit = header["heroLevelLimit"].Float();
 
 
 //	std::vector<bool> allowedHeroes;
 //	std::vector<ui16> placeholdedHeroes;
 
 	readTriggeredEvents(header);
-	readPlayerInfo(header);
-	readTeams(header);
+
+	readPlayerInfo(handler);
+
+	readTeams(handler);
 	//TODO: readHeader
 }
 
-void CMapLoaderJson::readPlayerInfo(const JsonNode & input)
+void CMapLoaderJson::readPlayerInfo(JsonDeserializer & handler)
 {
-	const JsonNode & src = input["players"];
-	int howManyTeams = 0;
+	auto playersData = handler.enterStruct("players");
 
 	for(int player = 0; player < PlayerColor::PLAYER_LIMIT_I; player++)
 	{
 		PlayerInfo & info = mapHeader->players.at(player);
 
-		const JsonNode & playerSrc = src[GameConstants::PLAYER_COLOR_NAMES[player]];
+		auto playerData = playersData.enterStruct(GameConstants::PLAYER_COLOR_NAMES[player]);
 
-		if(playerSrc.isNull())
+		if(playerData.get().isNull())
 		{
 			info.canComputerPlay = false;
 			info.canHumanPlay = false;
 		}
 		else
 		{
-			readPlayerInfo(info, playerSrc);
-		}
-	}
-	mapHeader->howManyTeams = howManyTeams;
-}
-
-void CMapLoaderJson::readPlayerInfo(PlayerInfo& info, const JsonNode& input)
-{
-	//allowed factions
+			//allowed factions
 
-//	info.isFactionRandom =
+		//	info.isFactionRandom =
 
-	info.canComputerPlay = true;
-	info.canHumanPlay = input["canPlay"].String() != "AIOnly";
+			info.canComputerPlay = true;
+			info.canHumanPlay = playerData.get()["canPlay"].String() != "AIOnly";
 
-	//placedHeroes
+			//placedHeroes
 
-	//mainTown
+			//mainTown
 
-	info.generateHeroAtMainTown = input["generateHeroAtMainTown"].Bool();
+			info.generateHeroAtMainTown = playerData.get()["generateHeroAtMainTown"].Bool();
 
-	//mainHero
+			//mainHero
 
-	//mainHeroPortrait
+			//mainHeroPortrait
 
-	//mainCustomHeroName
+			//mainCustomHeroName
+		}
+	}
 }
 
-void CMapLoaderJson::readTeams(const JsonNode& input)
+void CMapLoaderJson::readTeams(JsonDeserializer & handler)
 {
-	const JsonNode & src = input["teams"];
+	auto teamsData = handler.enterStruct("teams");
+	const JsonNode & src = teamsData.get();
 
     if(src.getType() != JsonNode::DATA_VECTOR)
 	{
@@ -566,12 +585,12 @@ void CMapLoaderJson::readTerrainLevel(const JsonNode& src, const int index)
 void CMapLoaderJson::readTerrain()
 {
 	{
-		const JsonNode surface = readJson("surface_terrain.json");
+		const JsonNode surface = getFromArchive("surface_terrain.json");
 		readTerrainLevel(surface, 0);
 	}
 	if(map->twoLevel)
 	{
-		const JsonNode underground = readJson("underground_terrain.json");
+		const JsonNode underground = getFromArchive("underground_terrain.json");
 		readTerrainLevel(underground, 1);
 	}
 
@@ -642,7 +661,7 @@ void CMapLoaderJson::readObjects()
 
 	std::vector<std::unique_ptr<MapObjectLoader>> loaders;//todo: optimize MapObjectLoader memory layout
 
-	const JsonNode data = readJson(OBJECTS_FILE_NAME);
+	const JsonNode data = getFromArchive(OBJECTS_FILE_NAME);
 
 	//get raw data
 	for(const auto & p : data.Struct())
@@ -703,6 +722,8 @@ void CMapSaverJson::saveMap(const std::unique_ptr<CMap>& map)
 void CMapSaverJson::writeHeader()
 {
 	JsonNode header;
+	JsonSerializer handler(header);
+
 	header["versionMajor"].Float() = VERSION_MAJOR;
 	header["versionMinor"].Float() = VERSION_MINOR;
 
@@ -724,17 +745,9 @@ void CMapSaverJson::writeHeader()
 
 
 	//todo: support arbitrary percentage
-	static const std::map<ui8, std::string> difficultyMap =
-	{
-		{0, "EASY"},
-		{1, "NORMAL"},
-		{2, "HARD"},
-		{3, "EXPERT"},
-		{4, "IMPOSSIBLE"}
-	};
 
-	header["difficulty"].String() = difficultyMap.at(map->difficulty);
-	header["levelLimit"].Float() = map->levelLimit;
+	header["difficulty"].String() = HeaderDetail::difficultyForwardMap.at(map->difficulty);
+	header["heroLevelLimit"].Float() = map->levelLimit;
 
 	writeTriggeredEvents(header);
 
@@ -789,17 +802,15 @@ void CMapSaverJson::writeTeams(JsonNode& output)
 	{
 		const PlayerInfo & player = map->players.at(idx);
 		int team = player.team.getNum();
-		if(vstd::isbetween(team, 0, map->howManyTeams-1) && player.canAnyonePlay())
+		if(vstd::iswithin(team, 0, map->howManyTeams-1) && player.canAnyonePlay())
 			teamsData.at(team).insert(PlayerColor(idx));
 	}
-//just an optimization but breaks test
-#if 0
+
 	//remove single-member teams
 	vstd::erase_if(teamsData, [](std::set<PlayerColor> & elem) -> bool
 	{
 		return elem.size() <= 1;
 	});
-#endif
 
 	//construct output
 	dest.setType(JsonNode::DATA_VECTOR);

+ 5 - 8
lib/mapping/MapFormatJson.h

@@ -22,6 +22,8 @@ struct TerrainTile;
 struct PlayerInfo;
 class CGObjectInstance;
 class AObjectTypeHandler;
+class JsonDeserializer;
+class JsonSerializer;
 
 class DLL_LINKAGE CMapFormatJson
 {
@@ -149,18 +151,13 @@ private:
 	/**
 	 * Reads player information.
 	 */
-	void readPlayerInfo(const JsonNode & input);
-
-	/**
-	 * Reads one player information.
-	 */
-	void readPlayerInfo(PlayerInfo & info, const JsonNode & input);
+	void readPlayerInfo(JsonDeserializer & handler);
 
 	/**
 	 * Reads team settings to header
 	 * @param input serialized header
 	 */
-	void readTeams(const JsonNode & input);
+	void readTeams(JsonDeserializer & handler);
 
 	void readTerrainTile(const std::string & src, TerrainTile & tile);
 
@@ -173,7 +170,7 @@ private:
 	 */
 	void readObjects();
 
-	const JsonNode readJson(const std::string & archiveFilename);
+	const JsonNode getFromArchive(const std::string & archiveFilename);
 
 	CInputStream * buffer;
 	std::shared_ptr<CIOApi> ioApi;

+ 23 - 0
lib/serializer/JsonDeserializer.cpp

@@ -0,0 +1,23 @@
+/*
+ * JsonDeserializer.cpp, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+
+
+#include "StdInc.h"
+#include "JsonDeserializer.h"
+
+#include "../JsonNode.h"
+
+JsonDeserializer::JsonDeserializer(JsonNode & root_):
+	JsonSerializeFormat(root_)
+{
+
+}
+
+

+ 23 - 0
lib/serializer/JsonDeserializer.h

@@ -0,0 +1,23 @@
+/*
+ * JsonDeserializer.h, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+
+#pragma once
+
+#include  "JsonSerializeFormat.h"
+
+class JsonNode;
+
+class JsonDeserializer: public JsonSerializeFormat
+{
+public:
+	static const bool saving = false;
+
+	JsonDeserializer(JsonNode & root_);
+};

+ 81 - 0
lib/serializer/JsonSerializeFormat.cpp

@@ -0,0 +1,81 @@
+/*
+ * JsonSerializeFormat.cpp, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+
+
+#include "StdInc.h"
+#include "JsonSerializeFormat.h"
+
+#include "../JsonNode.h"
+
+//JsonStructSerializer
+JsonStructSerializer::JsonStructSerializer(JsonStructSerializer&& other):
+	restoreState(false),
+	owner(other.owner),
+	parentNode(other.parentNode),
+	thisNode(other.thisNode)
+{
+
+}
+
+JsonStructSerializer::~JsonStructSerializer()
+{
+	if(restoreState)
+		owner.current = parentNode;
+}
+
+JsonStructSerializer::JsonStructSerializer(JsonSerializeFormat& owner_, const std::string& fieldName):
+	restoreState(true),
+	owner(owner_),
+	parentNode(owner.current),
+	thisNode(&(parentNode->operator[](fieldName)))
+{
+	owner.current = thisNode;
+}
+
+JsonStructSerializer::JsonStructSerializer(JsonStructSerializer & parent, const std::string & fieldName):
+	restoreState(true),
+	owner(parent.owner),
+	parentNode(parent.thisNode),
+	thisNode(&(parentNode->operator[](fieldName)))
+{
+	owner.current = thisNode;
+}
+
+
+JsonStructSerializer JsonStructSerializer::enterStruct(const std::string & fieldName)
+{
+	return JsonStructSerializer(*this, fieldName);
+}
+
+JsonNode& JsonStructSerializer::get()
+{
+	return *thisNode;
+}
+
+JsonSerializeFormat * JsonStructSerializer::operator->()
+{
+	return &owner;
+}
+
+
+//JsonSerializeFormat
+JsonSerializeFormat::JsonSerializeFormat(JsonNode & root_):
+	root(&root_),
+	current(root)
+{
+
+}
+
+JsonStructSerializer JsonSerializeFormat::enterStruct(const std::string & fieldName)
+{
+	JsonStructSerializer res(*this, fieldName);
+
+	return res;
+}

+ 58 - 0
lib/serializer/JsonSerializeFormat.h

@@ -0,0 +1,58 @@
+/*
+ * JsonSerializeFormat.h, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+
+#pragma once
+
+class JsonNode;
+
+class JsonSerializeFormat;
+
+class JsonStructSerializer: public boost::noncopyable
+{
+public:
+	JsonStructSerializer(JsonStructSerializer && other);
+	virtual ~JsonStructSerializer();
+
+	JsonStructSerializer enterStruct(const std::string & fieldName);
+
+	JsonNode & get();
+
+	JsonSerializeFormat * operator->();
+private:
+	JsonStructSerializer(JsonSerializeFormat & owner_, const std::string & fieldName);
+	JsonStructSerializer(JsonStructSerializer & parent, const std::string & fieldName);
+
+	bool restoreState;
+	JsonSerializeFormat & owner;
+	JsonNode * parentNode;
+	JsonNode * thisNode;
+	friend class JsonSerializeFormat;
+};
+
+class JsonSerializeFormat
+{
+public:
+	JsonSerializeFormat(JsonNode & root_);
+	virtual ~JsonSerializeFormat() = default;
+
+	JsonNode & getRoot()
+	{
+		return *root;
+	};
+
+	JsonStructSerializer enterStruct(const std::string & fieldName);
+
+protected:
+	JsonNode * root;
+	JsonNode * current;
+private:
+	friend class JsonStructSerializer;
+};
+

+ 23 - 0
lib/serializer/JsonSerializer.cpp

@@ -0,0 +1,23 @@
+/*
+ * JsonSerializer.cpp, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+
+
+#include "StdInc.h"
+#include "JsonSerializer.h"
+
+#include "../JsonNode.h"
+
+JsonSerializer::JsonSerializer(JsonNode & root_):
+	JsonSerializeFormat(root_)
+{
+
+}
+
+

+ 25 - 0
lib/serializer/JsonSerializer.h

@@ -0,0 +1,25 @@
+/*
+ * JsonSerializer.h, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+
+#pragma once
+
+#include  "JsonSerializeFormat.h"
+
+class JsonNode;
+
+class JsonSerializer: public JsonSerializeFormat
+{
+public:
+	static const bool saving = true;
+
+	JsonSerializer(JsonNode & root_);
+
+
+};