mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-20 20:23:03 +02:00
Merge pull request #4741 from IvanSavenko/serialize_local_state
Serialize local state of player interface
This commit is contained in:
commit
81f0222c68
@ -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"
|
||||
@ -23,34 +24,20 @@ PlayerLocalState::PlayerLocalState(CPlayerInterface & owner)
|
||||
{
|
||||
}
|
||||
|
||||
void PlayerLocalState::saveHeroPaths(std::map<const CGHeroInstance *, int3> & pathsMap)
|
||||
const PlayerSpellbookSetting & PlayerLocalState::getSpellbookSettings()
|
||||
{
|
||||
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());
|
||||
}
|
||||
return spellbookSettings;
|
||||
}
|
||||
|
||||
void PlayerLocalState::loadHeroPaths(std::map<const CGHeroInstance *, int3> & pathsMap)
|
||||
void PlayerLocalState::setSpellbookSettings(const PlayerSpellbookSetting & newSettings)
|
||||
{
|
||||
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());
|
||||
}
|
||||
}
|
||||
spellbookSettings = newSettings;
|
||||
}
|
||||
|
||||
void PlayerLocalState::setPath(const CGHeroInstance * h, const CGPath & path)
|
||||
{
|
||||
paths[h] = path;
|
||||
syncronizeState();
|
||||
}
|
||||
|
||||
const CGPath & PlayerLocalState::getPath(const CGHeroInstance * h) const
|
||||
@ -70,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;
|
||||
}
|
||||
|
||||
@ -93,6 +81,7 @@ void PlayerLocalState::erasePath(const CGHeroInstance * h)
|
||||
{
|
||||
paths.erase(h);
|
||||
adventureInt->onHeroChanged(h);
|
||||
syncronizeState();
|
||||
}
|
||||
|
||||
void PlayerLocalState::verifyPath(const CGHeroInstance * h)
|
||||
@ -170,6 +159,7 @@ void PlayerLocalState::setSelection(const CArmedInstance * selection)
|
||||
|
||||
if (adventureInt && selection)
|
||||
adventureInt->onSelectionChanged(selection);
|
||||
syncronizeState();
|
||||
}
|
||||
|
||||
bool PlayerLocalState::isHeroSleeping(const CGHeroInstance * hero) const
|
||||
@ -184,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)
|
||||
@ -193,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()
|
||||
@ -215,6 +207,8 @@ void PlayerLocalState::addWanderingHero(const CGHeroInstance * hero)
|
||||
|
||||
if (currentSelection == nullptr)
|
||||
setSelection(hero);
|
||||
|
||||
syncronizeState();
|
||||
}
|
||||
|
||||
void PlayerLocalState::removeWanderingHero(const CGHeroInstance * hero)
|
||||
@ -236,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)
|
||||
@ -244,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()
|
||||
@ -266,6 +264,8 @@ void PlayerLocalState::addOwnedTown(const CGTownInstance * town)
|
||||
|
||||
if (currentSelection == nullptr)
|
||||
setSelection(town);
|
||||
|
||||
syncronizeState();
|
||||
}
|
||||
|
||||
void PlayerLocalState::removeOwnedTown(const CGTownInstance * town)
|
||||
@ -282,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)
|
||||
@ -289,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;
|
||||
|
||||
@ -21,6 +22,15 @@ VCMI_LIB_NAMESPACE_END
|
||||
|
||||
class CPlayerInterface;
|
||||
|
||||
struct PlayerSpellbookSetting
|
||||
{
|
||||
//on which page we left spellbook
|
||||
int spellbookLastPageBattle = 0;
|
||||
int spellbookLastPageAdvmap = 0;
|
||||
int spellbookLastTabBattle = 4;
|
||||
int spellbookLastTabAdvmap = 4;
|
||||
};
|
||||
|
||||
/// Class that contains potentially serializeable state of a local player
|
||||
class PlayerLocalState
|
||||
{
|
||||
@ -34,18 +44,10 @@ class PlayerLocalState
|
||||
std::vector<const CGHeroInstance *> wanderingHeroes; //our heroes on the adventure map (not the garrisoned ones)
|
||||
std::vector<const CGTownInstance *> ownedTowns; //our towns on the adventure map
|
||||
|
||||
void saveHeroPaths(std::map<const CGHeroInstance *, int3> & paths);
|
||||
void loadHeroPaths(std::map<const CGHeroInstance *, int3> & paths);
|
||||
PlayerSpellbookSetting spellbookSettings;
|
||||
|
||||
void syncronizeState();
|
||||
public:
|
||||
struct SpellbookLastSetting
|
||||
{
|
||||
//on which page we left spellbook
|
||||
int spellbookLastPageBattle = 0;
|
||||
int spellbookLastPageAdvmap = 0;
|
||||
int spellbookLastTabBattle = 4;
|
||||
int spellbookLastTabAdvmap = 4;
|
||||
} spellbookSettings;
|
||||
|
||||
explicit PlayerLocalState(CPlayerInterface & owner);
|
||||
|
||||
@ -53,6 +55,9 @@ public:
|
||||
void setHeroAsleep(const CGHeroInstance * hero);
|
||||
void setHeroAwaken(const CGHeroInstance * hero);
|
||||
|
||||
const PlayerSpellbookSetting & getSpellbookSettings();
|
||||
void setSpellbookSettings(const PlayerSpellbookSetting & newSettings);
|
||||
|
||||
const std::vector<const CGTownInstance *> & getOwnedTowns();
|
||||
const CGTownInstance * getOwnedTown(size_t index);
|
||||
void addOwnedTown(const CGTownInstance * hero);
|
||||
@ -81,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);
|
||||
};
|
||||
|
@ -205,9 +205,9 @@ CSpellWindow::CSpellWindow(const CGHeroInstance * _myHero, CPlayerInterface * _m
|
||||
}
|
||||
}
|
||||
|
||||
selectedTab = battleSpellsOnly ? myInt->localState->spellbookSettings.spellbookLastTabBattle : myInt->localState->spellbookSettings.spellbookLastTabAdvmap;
|
||||
selectedTab = battleSpellsOnly ? myInt->localState->getSpellbookSettings().spellbookLastTabBattle : myInt->localState->getSpellbookSettings().spellbookLastTabAdvmap;
|
||||
schoolTab->setFrame(selectedTab, 0);
|
||||
int cp = battleSpellsOnly ? myInt->localState->spellbookSettings.spellbookLastPageBattle : myInt->localState->spellbookSettings.spellbookLastPageAdvmap;
|
||||
int cp = battleSpellsOnly ? myInt->localState->getSpellbookSettings().spellbookLastPageBattle : myInt->localState->getSpellbookSettings().spellbookLastPageAdvmap;
|
||||
// spellbook last page battle index is not reset after battle, so this needs to stay here
|
||||
vstd::abetween(cp, 0, std::max(0, pagesWithinCurrentTab() - 1));
|
||||
setCurrentPage(cp);
|
||||
@ -313,8 +313,18 @@ void CSpellWindow::processSpells()
|
||||
|
||||
void CSpellWindow::fexitb()
|
||||
{
|
||||
(myInt->battleInt ? myInt->localState->spellbookSettings.spellbookLastTabBattle : myInt->localState->spellbookSettings.spellbookLastTabAdvmap) = selectedTab;
|
||||
(myInt->battleInt ? myInt->localState->spellbookSettings.spellbookLastPageBattle : myInt->localState->spellbookSettings.spellbookLastPageAdvmap) = currentPage;
|
||||
auto spellBookState = myInt->localState->getSpellbookSettings();
|
||||
if(myInt->battleInt)
|
||||
{
|
||||
spellBookState.spellbookLastTabBattle = selectedTab;
|
||||
spellBookState.spellbookLastPageBattle = currentPage;
|
||||
}
|
||||
else
|
||||
{
|
||||
spellBookState.spellbookLastTabAdvmap = selectedTab;
|
||||
spellBookState.spellbookLastPageAdvmap = currentPage;
|
||||
}
|
||||
myInt->localState->setSpellbookSettings(spellBookState);
|
||||
|
||||
if(onSpellSelect)
|
||||
onSpellSelect(SpellID::NONE);
|
||||
@ -619,8 +629,10 @@ void CSpellWindow::SpellArea::clickPressed(const Point & cursorPosition)
|
||||
|
||||
auto guard = vstd::makeScopeGuard([this]()
|
||||
{
|
||||
owner->myInt->localState->spellbookSettings.spellbookLastTabAdvmap = owner->selectedTab;
|
||||
owner->myInt->localState->spellbookSettings.spellbookLastPageAdvmap = owner->currentPage;
|
||||
auto spellBookState = owner->myInt->localState->getSpellbookSettings();
|
||||
spellBookState.spellbookLastTabAdvmap = owner->selectedTab;
|
||||
spellBookState.spellbookLastPageAdvmap = owner->currentPage;
|
||||
owner->myInt->localState->setSpellbookSettings(spellBookState);
|
||||
});
|
||||
|
||||
spells::detail::ProblemImpl problem;
|
||||
|
@ -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
|
||||
|
@ -4013,6 +4013,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;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user