mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	Implemented serialization of local player state in json form
This commit is contained in:
		| @@ -25,6 +25,7 @@ | ||||
| #include "lib/UnlockGuard.h" | ||||
| #include "lib/battle/BattleInfo.h" | ||||
| #include "lib/networkPacks/PacksForServer.h" | ||||
| #include "lib/networkPacks/SaveLocalState.h" | ||||
|  | ||||
| bool CCallback::teleportHero(const CGHeroInstance *who, const CGTownInstance *where) | ||||
| { | ||||
| @@ -323,6 +324,15 @@ void CCallback::recruitHero(const CGObjectInstance *townOrTavern, const CGHeroIn | ||||
| 	sendRequest(pack); | ||||
| } | ||||
|  | ||||
| void CCallback::saveLocalState(const JsonNode & data) | ||||
| { | ||||
| 	SaveLocalState state; | ||||
| 	state.data = data; | ||||
| 	state.player = *player; | ||||
|  | ||||
| 	sendRequest(state); | ||||
| } | ||||
|  | ||||
| void CCallback::save( const std::string &fname ) | ||||
| { | ||||
| 	cl->save(fname); | ||||
|   | ||||
| @@ -100,6 +100,7 @@ public: | ||||
| 	virtual void assembleArtifacts(const ObjectInstanceID & heroID, ArtifactPosition artifactSlot, bool assemble, ArtifactID assembleTo)=0; | ||||
| 	virtual void eraseArtifactByClient(const ArtifactLocation & al)=0; | ||||
| 	virtual bool dismissCreature(const CArmedInstance *obj, SlotID stackPos)=0; | ||||
| 	virtual void saveLocalState(const JsonNode & data)=0; | ||||
| 	virtual void endTurn()=0; | ||||
| 	virtual void buyArtifact(const CGHeroInstance *hero, ArtifactID aid)=0; //used to buy artifacts in towns (including spell book in the guild and war machines in blacksmith) | ||||
| 	virtual void setFormation(const CGHeroInstance * hero, EArmyFormation mode)=0; | ||||
| @@ -193,6 +194,7 @@ public: | ||||
| 	void recruitCreatures(const CGDwelling * obj, const CArmedInstance * dst, CreatureID ID, ui32 amount, si32 level=-1) override; | ||||
| 	bool dismissCreature(const CArmedInstance *obj, SlotID stackPos) override; | ||||
| 	bool upgradeCreature(const CArmedInstance *obj, SlotID stackPos, CreatureID newID=CreatureID::NONE) override; | ||||
| 	void saveLocalState(const JsonNode & data) override; | ||||
| 	void endTurn() override; | ||||
| 	void spellResearch(const CGTownInstance *town, SpellID spellAtSlot, bool accepted) override; | ||||
| 	void swapGarrisonHero(const CGTownInstance *town) override; | ||||
|   | ||||
| @@ -1333,6 +1333,8 @@ void CPlayerInterface::initializeHeroTownList() | ||||
| 			localState->addOwnedTown(town); | ||||
| 	} | ||||
|  | ||||
| 	localState->deserialize(*cb->getPlayerState(playerID)->playerLocalSettings); | ||||
|  | ||||
| 	if(adventureInt) | ||||
| 		adventureInt->onHeroChanged(nullptr); | ||||
| } | ||||
|   | ||||
| @@ -11,6 +11,7 @@ | ||||
| #include "PlayerLocalState.h" | ||||
|  | ||||
| #include "../CCallback.h" | ||||
| #include "../lib/json/JsonNode.h" | ||||
| #include "../lib/mapObjects/CGHeroInstance.h" | ||||
| #include "../lib/mapObjects/CGTownInstance.h" | ||||
| #include "../lib/pathfinder/CGPathNode.h" | ||||
| @@ -33,34 +34,10 @@ void PlayerLocalState::setSpellbookSettings(const PlayerSpellbookSetting & newSe | ||||
| 	spellbookSettings = newSettings; | ||||
| } | ||||
|  | ||||
| void PlayerLocalState::saveHeroPaths(std::map<const CGHeroInstance *, int3> & pathsMap) | ||||
| { | ||||
| 	for(auto & p : paths) | ||||
| 	{ | ||||
| 		if(p.second.nodes.size()) | ||||
| 			pathsMap[p.first] = p.second.endPos(); | ||||
| 		else | ||||
| 			logGlobal->debug("%s has assigned an empty path! Ignoring it...", p.first->getNameTranslated()); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void PlayerLocalState::loadHeroPaths(std::map<const CGHeroInstance *, int3> & pathsMap) | ||||
| { | ||||
| 	if(owner.cb) | ||||
| 	{ | ||||
| 		for(auto & p : pathsMap) | ||||
| 		{ | ||||
| 			CGPath path; | ||||
| 			owner.cb->getPathsInfo(p.first)->getPath(path, p.second); | ||||
| 			paths[p.first] = path; | ||||
| 			logGlobal->trace("Restored path for hero %s leading to %s with %d nodes", p.first->nodeName(), p.second.toString(), path.nodes.size()); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void PlayerLocalState::setPath(const CGHeroInstance * h, const CGPath & path) | ||||
| { | ||||
| 	paths[h] = path; | ||||
| 	syncronizeState(); | ||||
| } | ||||
|  | ||||
| const CGPath & PlayerLocalState::getPath(const CGHeroInstance * h) const | ||||
| @@ -80,6 +57,7 @@ bool PlayerLocalState::setPath(const CGHeroInstance * h, const int3 & destinatio | ||||
| 	if(!owner.cb->getPathsInfo(h)->getPath(path, destination)) | ||||
| 	{ | ||||
| 		paths.erase(h); //invalidate previously possible path if selected (before other hero blocked only path / fly spell expired) | ||||
| 		syncronizeState(); | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| @@ -103,6 +81,7 @@ void PlayerLocalState::erasePath(const CGHeroInstance * h) | ||||
| { | ||||
| 	paths.erase(h); | ||||
| 	adventureInt->onHeroChanged(h); | ||||
| 	syncronizeState(); | ||||
| } | ||||
|  | ||||
| void PlayerLocalState::verifyPath(const CGHeroInstance * h) | ||||
| @@ -180,6 +159,7 @@ void PlayerLocalState::setSelection(const CArmedInstance * selection) | ||||
|  | ||||
| 	if (adventureInt && selection) | ||||
| 		adventureInt->onSelectionChanged(selection); | ||||
| 	syncronizeState(); | ||||
| } | ||||
|  | ||||
| bool PlayerLocalState::isHeroSleeping(const CGHeroInstance * hero) const | ||||
| @@ -194,6 +174,7 @@ void PlayerLocalState::setHeroAsleep(const CGHeroInstance * hero) | ||||
| 	assert(!vstd::contains(sleepingHeroes, hero)); | ||||
|  | ||||
| 	sleepingHeroes.push_back(hero); | ||||
| 	syncronizeState(); | ||||
| } | ||||
|  | ||||
| void PlayerLocalState::setHeroAwaken(const CGHeroInstance * hero) | ||||
| @@ -203,6 +184,7 @@ void PlayerLocalState::setHeroAwaken(const CGHeroInstance * hero) | ||||
| 	assert(vstd::contains(sleepingHeroes, hero)); | ||||
|  | ||||
| 	vstd::erase(sleepingHeroes, hero); | ||||
| 	syncronizeState(); | ||||
| } | ||||
|  | ||||
| const std::vector<const CGHeroInstance *> & PlayerLocalState::getWanderingHeroes() | ||||
| @@ -225,6 +207,8 @@ void PlayerLocalState::addWanderingHero(const CGHeroInstance * hero) | ||||
|  | ||||
| 	if (currentSelection == nullptr) | ||||
| 		setSelection(hero); | ||||
|  | ||||
| 	syncronizeState(); | ||||
| } | ||||
|  | ||||
| void PlayerLocalState::removeWanderingHero(const CGHeroInstance * hero) | ||||
| @@ -246,6 +230,8 @@ void PlayerLocalState::removeWanderingHero(const CGHeroInstance * hero) | ||||
|  | ||||
| 	if (currentSelection == nullptr && !ownedTowns.empty()) | ||||
| 		setSelection(ownedTowns.front()); | ||||
|  | ||||
| 	syncronizeState(); | ||||
| } | ||||
|  | ||||
| void PlayerLocalState::swapWanderingHero(size_t pos1, size_t pos2) | ||||
| @@ -254,6 +240,8 @@ void PlayerLocalState::swapWanderingHero(size_t pos1, size_t pos2) | ||||
| 	std::swap(wanderingHeroes.at(pos1), wanderingHeroes.at(pos2)); | ||||
|  | ||||
| 	adventureInt->onHeroOrderChanged(); | ||||
|  | ||||
| 	syncronizeState(); | ||||
| } | ||||
|  | ||||
| const std::vector<const CGTownInstance *> & PlayerLocalState::getOwnedTowns() | ||||
| @@ -276,6 +264,8 @@ void PlayerLocalState::addOwnedTown(const CGTownInstance * town) | ||||
|  | ||||
| 	if (currentSelection == nullptr) | ||||
| 		setSelection(town); | ||||
|  | ||||
| 	syncronizeState(); | ||||
| } | ||||
|  | ||||
| void PlayerLocalState::removeOwnedTown(const CGTownInstance * town) | ||||
| @@ -292,6 +282,8 @@ void PlayerLocalState::removeOwnedTown(const CGTownInstance * town) | ||||
|  | ||||
| 	if (currentSelection == nullptr && !ownedTowns.empty()) | ||||
| 		setSelection(ownedTowns.front()); | ||||
|  | ||||
| 	syncronizeState(); | ||||
| } | ||||
|  | ||||
| void PlayerLocalState::swapOwnedTowns(size_t pos1, size_t pos2) | ||||
| @@ -299,5 +291,119 @@ void PlayerLocalState::swapOwnedTowns(size_t pos1, size_t pos2) | ||||
| 	assert(ownedTowns[pos1] && ownedTowns[pos2]); | ||||
| 	std::swap(ownedTowns.at(pos1), ownedTowns.at(pos2)); | ||||
|  | ||||
| 	syncronizeState(); | ||||
|  | ||||
| 	adventureInt->onTownOrderChanged(); | ||||
| } | ||||
|  | ||||
| void PlayerLocalState::syncronizeState() | ||||
| { | ||||
| 	JsonNode data; | ||||
| 	serialize(data); | ||||
| 	owner.cb->saveLocalState(data); | ||||
| } | ||||
|  | ||||
| void PlayerLocalState::serialize(JsonNode & dest) const | ||||
| { | ||||
| 	dest.clear(); | ||||
|  | ||||
| 	for (auto const * town : ownedTowns) | ||||
| 	{ | ||||
| 		JsonNode record; | ||||
| 		record["id"].Integer() = town->id; | ||||
| 		dest["towns"].Vector().push_back(record); | ||||
| 	} | ||||
|  | ||||
| 	for (auto const * hero : wanderingHeroes) | ||||
| 	{ | ||||
| 		JsonNode record; | ||||
| 		record["id"].Integer() = hero->id; | ||||
| 		if (vstd::contains(sleepingHeroes, hero)) | ||||
| 			record["sleeping"].Bool() = true; | ||||
|  | ||||
| 		if (paths.count(hero)) | ||||
| 		{ | ||||
| 			record["path"]["x"].Integer() = paths.at(hero).lastNode().coord.x; | ||||
| 			record["path"]["y"].Integer() = paths.at(hero).lastNode().coord.y; | ||||
| 			record["path"]["z"].Integer() = paths.at(hero).lastNode().coord.z; | ||||
| 		} | ||||
| 		dest["heroes"].Vector().push_back(record); | ||||
| 	} | ||||
| 	dest["spellbook"]["pageBattle"].Integer() = spellbookSettings.spellbookLastPageBattle; | ||||
| 	dest["spellbook"]["pageAdvmap"].Integer() = spellbookSettings.spellbookLastPageAdvmap; | ||||
| 	dest["spellbook"]["tabBattle"].Integer() = spellbookSettings.spellbookLastTabBattle; | ||||
| 	dest["spellbook"]["tabAdvmap"].Integer() = spellbookSettings.spellbookLastTabAdvmap; | ||||
|  | ||||
| 	dest["currentSelection"].Integer() = currentSelection->id; | ||||
| } | ||||
|  | ||||
| void PlayerLocalState::deserialize(const JsonNode & source) | ||||
| { | ||||
| 	// this method must be called after player state has been initialized | ||||
| 	assert(currentSelection != nullptr); | ||||
| 	assert(!ownedTowns.empty() || wanderingHeroes.empty()); | ||||
|  | ||||
| 	auto oldHeroes = wanderingHeroes; | ||||
| 	auto oldTowns = ownedTowns; | ||||
|  | ||||
| 	paths.clear(); | ||||
| 	sleepingHeroes.clear(); | ||||
| 	wanderingHeroes.clear(); | ||||
| 	ownedTowns.clear(); | ||||
|  | ||||
| 	for (auto const & town : source["towns"].Vector()) | ||||
| 	{ | ||||
| 		ObjectInstanceID objID(town["id"].Integer()); | ||||
| 		const CGTownInstance * townPtr = owner.cb->getTown(objID); | ||||
|  | ||||
| 		if (!townPtr) | ||||
| 			continue; | ||||
|  | ||||
| 		if (!vstd::contains(oldTowns, townPtr)) | ||||
| 			continue; | ||||
|  | ||||
| 		ownedTowns.push_back(townPtr); | ||||
| 		vstd::erase(oldTowns, townPtr); | ||||
| 	} | ||||
|  | ||||
| 	for (auto const & hero : source["heroes"].Vector()) | ||||
| 	{ | ||||
| 		ObjectInstanceID objID(hero["id"].Integer()); | ||||
| 		const CGHeroInstance * heroPtr = owner.cb->getHero(objID); | ||||
|  | ||||
| 		if (!heroPtr) | ||||
| 			continue; | ||||
|  | ||||
| 		if (!vstd::contains(oldHeroes, heroPtr)) | ||||
| 			continue; | ||||
|  | ||||
| 		wanderingHeroes.push_back(heroPtr); | ||||
| 		vstd::erase(oldHeroes, heroPtr); | ||||
|  | ||||
| 		if (hero["sleeping"].Bool()) | ||||
| 			sleepingHeroes.push_back(heroPtr); | ||||
|  | ||||
| 		if (hero["path"]["x"].isNumber() && hero["path"]["y"].isNumber() && hero["path"]["z"].isNumber()) | ||||
| 		{ | ||||
| 			int3 pathTarget(hero["path"]["x"].Integer(), hero["path"]["y"].Integer(), hero["path"]["z"].Integer()); | ||||
| 			setPath(heroPtr, pathTarget); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	spellbookSettings.spellbookLastPageBattle = source["spellbook"]["pageBattle"].Integer(); | ||||
| 	spellbookSettings.spellbookLastPageAdvmap = source["spellbook"]["pageAdvmap"].Integer(); | ||||
| 	spellbookSettings.spellbookLastTabBattle = source["spellbook"]["tabBattle"].Integer(); | ||||
| 	spellbookSettings.spellbookLastTabAdvmap = source["spellbook"]["tabAdvmap"].Integer(); | ||||
|  | ||||
| 	// append any owned heroes / towns that were not present in loaded state | ||||
| 	wanderingHeroes.insert(wanderingHeroes.end(), oldHeroes.begin(), oldHeroes.end()); | ||||
| 	ownedTowns.insert(ownedTowns.end(), oldTowns.begin(), oldTowns.end()); | ||||
|  | ||||
| //FIXME: broken, anything that is selected in here will be overwritten on NewTurn pack | ||||
| //	ObjectInstanceID selectedObjectID(source["currentSelection"].Integer()); | ||||
| //	const CGObjectInstance * objectPtr = owner.cb->getObjInstance(selectedObjectID); | ||||
| //	const CArmedInstance * armyPtr = dynamic_cast<const CArmedInstance*>(objectPtr); | ||||
| // | ||||
| //	if (armyPtr) | ||||
| //		setSelection(armyPtr); | ||||
| } | ||||
|   | ||||
| @@ -14,6 +14,7 @@ VCMI_LIB_NAMESPACE_BEGIN | ||||
| class CGHeroInstance; | ||||
| class CGTownInstance; | ||||
| class CArmedInstance; | ||||
| class JsonNode; | ||||
| struct CGPath; | ||||
| class int3; | ||||
|  | ||||
| @@ -45,9 +46,7 @@ class PlayerLocalState | ||||
|  | ||||
| 	PlayerSpellbookSetting spellbookSettings; | ||||
|  | ||||
| 	void saveHeroPaths(std::map<const CGHeroInstance *, int3> & paths); | ||||
| 	void loadHeroPaths(std::map<const CGHeroInstance *, int3> & paths); | ||||
|  | ||||
| 	void syncronizeState(); | ||||
| public: | ||||
|  | ||||
| 	explicit PlayerLocalState(CPlayerInterface & owner); | ||||
| @@ -87,6 +86,9 @@ public: | ||||
| 	const CGTownInstance * getCurrentTown() const; | ||||
| 	const CArmedInstance * getCurrentArmy() const; | ||||
|  | ||||
| 	void serialize(JsonNode & dest) const; | ||||
| 	void deserialize(const JsonNode & source); | ||||
|  | ||||
| 	/// Changes currently selected object | ||||
| 	void setSelection(const CArmedInstance *sel); | ||||
| }; | ||||
|   | ||||
| @@ -559,6 +559,7 @@ set(lib_MAIN_HEADERS | ||||
| 	networkPacks/PacksForServer.h | ||||
| 	networkPacks/SetRewardableConfiguration.h | ||||
| 	networkPacks/SetStackEffect.h | ||||
| 	networkPacks/SaveLocalState.h | ||||
| 	networkPacks/StackLocation.h | ||||
| 	networkPacks/TradeItem.h | ||||
|  | ||||
|   | ||||
| @@ -10,6 +10,7 @@ | ||||
| #include "StdInc.h" | ||||
|  | ||||
| #include "CPlayerState.h" | ||||
| #include "json/JsonNode.h" | ||||
| #include "mapObjects/CGDwelling.h" | ||||
| #include "mapObjects/CGTownInstance.h" | ||||
| #include "mapObjects/CGHeroInstance.h" | ||||
| @@ -20,8 +21,13 @@ | ||||
| VCMI_LIB_NAMESPACE_BEGIN | ||||
|  | ||||
| PlayerState::PlayerState() | ||||
|  : color(-1), human(false), cheated(false), enteredWinningCheatCode(false), | ||||
|    enteredLosingCheatCode(false), status(EPlayerStatus::INGAME) | ||||
| 	: color(-1) | ||||
| 	, playerLocalSettings(std::make_unique<JsonNode>()) | ||||
| 	, human(false) | ||||
| 	, cheated(false) | ||||
| 	, enteredWinningCheatCode(false) | ||||
| 	, enteredLosingCheatCode(false) | ||||
| 	, status(EPlayerStatus::INGAME) | ||||
| { | ||||
| 	setNodeType(PLAYER); | ||||
| } | ||||
|   | ||||
| @@ -16,7 +16,6 @@ | ||||
| #include "bonuses/CBonusSystemNode.h" | ||||
| #include "ResourceSet.h" | ||||
| #include "TurnTimerInfo.h" | ||||
| #include "ConstTransitivePtr.h" | ||||
|  | ||||
| VCMI_LIB_NAMESPACE_BEGIN | ||||
|  | ||||
| @@ -66,6 +65,7 @@ public: | ||||
| 	std::vector<QuestInfo> quests; //store info about all received quests | ||||
| 	std::vector<Bonus> battleBonuses; //additional bonuses to be added during battle with neutrals | ||||
| 	std::map<uint32_t, std::map<ArtifactPosition, ArtifactID>> costumesArtifacts; | ||||
| 	std::unique_ptr<JsonNode> playerLocalSettings; // Json with client-defined data, such as order of heroes or current hero paths. Not used by client/lib | ||||
|  | ||||
| 	bool cheated; | ||||
| 	bool enteredWinningCheatCode, enteredLosingCheatCode; //if true, this player has entered cheat codes for loss / victory | ||||
| @@ -116,6 +116,9 @@ public: | ||||
| 		h & status; | ||||
| 		h & turnTimer; | ||||
|  | ||||
| 		if (h.version >= Handler::Version::LOCAL_PLAYER_STATE_DATA) | ||||
| 			h & *playerLocalSettings; | ||||
|  | ||||
| 		if (h.version >= Handler::Version::PLAYER_STATE_OWNED_OBJECTS) | ||||
| 		{ | ||||
| 			h & ownedObjects; | ||||
|   | ||||
| @@ -13,6 +13,7 @@ | ||||
| #include "PacksForClientBattle.h" | ||||
| #include "PacksForServer.h" | ||||
| #include "PacksForLobby.h" | ||||
| #include "SaveLocalState.h" | ||||
| #include "SetRewardableConfiguration.h" | ||||
| #include "SetStackEffect.h" | ||||
|  | ||||
| @@ -177,6 +178,7 @@ public: | ||||
| 	virtual void visitLobbyForceSetPlayer(LobbyForceSetPlayer & pack) {} | ||||
| 	virtual void visitLobbyShowMessage(LobbyShowMessage & pack) {} | ||||
| 	virtual void visitLobbyPvPAction(LobbyPvPAction & pack) {} | ||||
| 	virtual void visitSaveLocalState(SaveLocalState & pack) {} | ||||
| }; | ||||
|  | ||||
| VCMI_LIB_NAMESPACE_END | ||||
|   | ||||
| @@ -12,6 +12,7 @@ | ||||
| #include "PacksForClient.h" | ||||
| #include "PacksForClientBattle.h" | ||||
| #include "PacksForServer.h" | ||||
| #include "SaveLocalState.h" | ||||
| #include "SetRewardableConfiguration.h" | ||||
| #include "StackLocation.h" | ||||
| #include "PacksForLobby.h" | ||||
| @@ -92,6 +93,12 @@ bool CLobbyPackToServer::isForServer() const | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| void SaveLocalState::visitTyped(ICPackVisitor & visitor) | ||||
| { | ||||
| 	visitor.visitSaveLocalState(*this); | ||||
| } | ||||
|  | ||||
|  | ||||
| void PackageApplied::visitTyped(ICPackVisitor & visitor) | ||||
| { | ||||
| 	visitor.visitPackageApplied(*this); | ||||
|   | ||||
							
								
								
									
										27
									
								
								lib/networkPacks/SaveLocalState.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								lib/networkPacks/SaveLocalState.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| /* | ||||
|  * SaveLocalState.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 "NetPacksBase.h" | ||||
|  | ||||
| #include "../json/JsonNode.h" | ||||
|  | ||||
| struct DLL_LINKAGE SaveLocalState : public CPackForServer | ||||
| { | ||||
| 	JsonNode data; | ||||
|  | ||||
| 	void visitTyped(ICPackVisitor & visitor) override; | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler & h) | ||||
| 	{ | ||||
| 		h & static_cast<CPackForServer &>(*this); | ||||
| 		h & data; | ||||
| 	} | ||||
| }; | ||||
| @@ -62,6 +62,7 @@ enum class ESerializationVersion : int32_t | ||||
| 	REWARDABLE_BANKS, // 863 - team state contains list of scouted objects, coast visitable rewardable objects | ||||
| 	REGION_LABEL, // 864 - labels for campaign regions | ||||
| 	SPELL_RESEARCH, // 865 - spell research | ||||
| 	LOCAL_PLAYER_STATE_DATA, // 866 - player state contains arbitrary client-side data | ||||
|  | ||||
| 	CURRENT = SPELL_RESEARCH | ||||
| 	CURRENT = LOCAL_PLAYER_STATE_DATA | ||||
| }; | ||||
|   | ||||
| @@ -34,6 +34,7 @@ | ||||
| #include "../networkPacks/PacksForClientBattle.h" | ||||
| #include "../networkPacks/PacksForLobby.h" | ||||
| #include "../networkPacks/PacksForServer.h" | ||||
| #include "../networkPacks/SaveLocalState.h" | ||||
| #include "../networkPacks/SetRewardableConfiguration.h" | ||||
| #include "../networkPacks/SetStackEffect.h" | ||||
|  | ||||
| @@ -290,6 +291,7 @@ void registerTypes(Serializer &s) | ||||
| 	s.template registerType<LobbySetExtraOptions>(240); | ||||
| 	s.template registerType<SpellResearch>(241); | ||||
| 	s.template registerType<SetResearchedSpells>(242); | ||||
| 	s.template registerType<SaveLocalState>(243); | ||||
| } | ||||
|  | ||||
| VCMI_LIB_NAMESPACE_END | ||||
|   | ||||
| @@ -4012,6 +4012,9 @@ bool CGameHandler::isBlockedByQueries(const CPackForServer *pack, PlayerColor pl | ||||
| 	if (dynamic_cast<const PlayerMessage *>(pack) != nullptr) | ||||
| 		return false; | ||||
|  | ||||
| 	if (dynamic_cast<const SaveLocalState *>(pack) != nullptr) | ||||
| 		return false; | ||||
|  | ||||
| 	auto query = queries->topQuery(player); | ||||
| 	if (query && query->blocksPack(pack)) | ||||
| 	{ | ||||
|   | ||||
| @@ -19,6 +19,7 @@ | ||||
| #include "queries/MapQueries.h" | ||||
|  | ||||
| #include "../lib/IGameCallback.h" | ||||
| #include "../lib/CPlayerState.h" | ||||
| #include "../lib/mapObjects/CGTownInstance.h" | ||||
| #include "../lib/mapObjects/CGHeroInstance.h" | ||||
| #include "../lib/gameState/CGameState.h" | ||||
| @@ -389,6 +390,13 @@ void ApplyGhNetPackVisitor::visitQueryReply(QueryReply & pack) | ||||
| 	result = gh.queryReply(pack.qid, pack.reply, pack.player); | ||||
| } | ||||
|  | ||||
| void ApplyGhNetPackVisitor::visitSaveLocalState(SaveLocalState & pack) | ||||
| { | ||||
| 	gh.throwIfWrongPlayer(&pack); | ||||
| 	*gh.gameState()->getPlayerState(pack.player)->playerLocalSettings = pack.data; | ||||
| 	result = true; | ||||
| } | ||||
|  | ||||
| void ApplyGhNetPackVisitor::visitMakeAction(MakeAction & pack) | ||||
| { | ||||
| 	gh.throwIfWrongPlayer(&pack); | ||||
|   | ||||
| @@ -62,4 +62,5 @@ public: | ||||
| 	void visitDigWithHero(DigWithHero & pack) override; | ||||
| 	void visitCastAdvSpell(CastAdvSpell & pack) override; | ||||
| 	void visitPlayerMessage(PlayerMessage & pack) override; | ||||
| 	void visitSaveLocalState(SaveLocalState & pack) override; | ||||
| }; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user