1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-11-25 22:42:04 +02:00

show statistics ingame

This commit is contained in:
Laserlicht
2025-11-22 13:14:50 +01:00
parent f3fd5c05af
commit afb045ef14
26 changed files with 119 additions and 0 deletions

View File

@@ -349,6 +349,7 @@
"vcmi.keyBindings.keyBinding.adventureViewPuzzle": "Adventure view puzzle", "vcmi.keyBindings.keyBinding.adventureViewPuzzle": "Adventure view puzzle",
"vcmi.keyBindings.keyBinding.adventureViewScenario": "Adventure view scenario", "vcmi.keyBindings.keyBinding.adventureViewScenario": "Adventure view scenario",
"vcmi.keyBindings.keyBinding.adventureViewSelected": "Adventure view selected", "vcmi.keyBindings.keyBinding.adventureViewSelected": "Adventure view selected",
"vcmi.keyBindings.keyBinding.adventureViewStatistic": "Adventure view statistic",
"vcmi.keyBindings.keyBinding.adventureViewWorld": "Adventure view world", "vcmi.keyBindings.keyBinding.adventureViewWorld": "Adventure view world",
"vcmi.keyBindings.keyBinding.adventureViewWorld1": "Adventure view world1", "vcmi.keyBindings.keyBinding.adventureViewWorld1": "Adventure view world1",
"vcmi.keyBindings.keyBinding.adventureViewWorld2": "Adventure view world2", "vcmi.keyBindings.keyBinding.adventureViewWorld2": "Adventure view world2",

View File

@@ -348,6 +348,7 @@
"vcmi.keyBindings.keyBinding.adventureViewPuzzle": "Abenteuer Rätsel anzeigen", "vcmi.keyBindings.keyBinding.adventureViewPuzzle": "Abenteuer Rätsel anzeigen",
"vcmi.keyBindings.keyBinding.adventureViewScenario": "Abenteuer Szenario anzeigen", "vcmi.keyBindings.keyBinding.adventureViewScenario": "Abenteuer Szenario anzeigen",
"vcmi.keyBindings.keyBinding.adventureViewSelected": "Abenteuer Auswahl anzeigen", "vcmi.keyBindings.keyBinding.adventureViewSelected": "Abenteuer Auswahl anzeigen",
"vcmi.keyBindings.keyBinding.adventureViewStatistic": "Abenteuer Statistik anzeigen",
"vcmi.keyBindings.keyBinding.adventureViewWorld": "Abenteuer Weltansicht", "vcmi.keyBindings.keyBinding.adventureViewWorld": "Abenteuer Weltansicht",
"vcmi.keyBindings.keyBinding.adventureViewWorld1": "Abenteuer Weltansicht 1", "vcmi.keyBindings.keyBinding.adventureViewWorld1": "Abenteuer Weltansicht 1",
"vcmi.keyBindings.keyBinding.adventureViewWorld2": "Abenteuer Weltansicht 2", "vcmi.keyBindings.keyBinding.adventureViewWorld2": "Abenteuer Weltansicht 2",

View File

@@ -37,6 +37,7 @@
#include "mainmenu/CMainMenu.h" #include "mainmenu/CMainMenu.h"
#include "mainmenu/CHighScoreScreen.h" #include "mainmenu/CHighScoreScreen.h"
#include "mainmenu/CStatisticScreen.h"
#include "mapView/mapHandler.h" #include "mapView/mapHandler.h"
@@ -1847,3 +1848,8 @@ void CPlayerInterface::unregisterBattleInterface(std::shared_ptr<CBattleGameInte
GAME->server().client->unregisterBattleInterface(autofightingAI, playerID); GAME->server().client->unregisterBattleInterface(autofightingAI, playerID);
autofightingAI.reset(); autofightingAI.reset();
} }
void CPlayerInterface::responseStatistic(StatisticDataSet & statistic)
{
ENGINE->windows().createAndPushWindow<CStatisticScreen>(statistic);
}

View File

@@ -12,6 +12,7 @@
#include "ArtifactsUIController.h" #include "ArtifactsUIController.h"
#include "../lib/callback/CGameInterface.h" #include "../lib/callback/CGameInterface.h"
#include "../lib/gameState/GameStatistics.h"
#include "../lib/FunctionList.h" #include "../lib/FunctionList.h"
#include "gui/CIntObject.h" #include "gui/CIntObject.h"
@@ -147,6 +148,7 @@ protected: // Call-ins from server, should not be called directly, but only via
void playerEndsTurn(PlayerColor player) override; void playerEndsTurn(PlayerColor player) override;
void showWorldViewEx(const std::vector<ObjectPosInfo> & objectPositions, bool showTerrain) override; void showWorldViewEx(const std::vector<ObjectPosInfo> & objectPositions, bool showTerrain) override;
void setColorScheme(ColorScheme scheme) override; void setColorScheme(ColorScheme scheme) override;
void responseStatistic(StatisticDataSet & statistic) override;
//for battles //for battles
void actionFinished(const BattleID & battleID, const BattleAction& action) override;//occurs AFTER action taken by active stack or by the hero void actionFinished(const BattleID & battleID, const BattleAction& action) override;//occurs AFTER action taken by active stack or by the hero

View File

@@ -106,6 +106,7 @@ public:
void visitEntitiesChanged(EntitiesChanged & pack) override; void visitEntitiesChanged(EntitiesChanged & pack) override;
void visitPlayerCheated(PlayerCheated & pack) override; void visitPlayerCheated(PlayerCheated & pack) override;
void visitChangeTownName(ChangeTownName & pack) override; void visitChangeTownName(ChangeTownName & pack) override;
void visitResponseStatistic(ResponseStatistic & pack) override;
}; };
class ApplyFirstClientNetPackVisitor : public VCMI_LIB_WRAP_NAMESPACE(ICPackVisitor) class ApplyFirstClientNetPackVisitor : public VCMI_LIB_WRAP_NAMESPACE(ICPackVisitor)

View File

@@ -1098,3 +1098,8 @@ void ApplyClientNetPackVisitor::visitChangeTownName(ChangeTownName & pack)
ENGINE->windows().totalRedraw(); ENGINE->windows().totalRedraw();
} }
} }
void ApplyClientNetPackVisitor::visitResponseStatistic(ResponseStatistic & pack)
{
callInterfaceIfPresent(cl, pack.player, &IGameEventsReceiver::responseStatistic, pack.statistic);
}

View File

@@ -73,6 +73,7 @@ std::vector<AdventureMapShortcutState> AdventureMapShortcuts::getShortcuts()
{ EShortcut::ADVENTURE_VIEW_WORLD_X1, optionInWorldView(), [this]() { this->worldViewScale1x(); } }, { EShortcut::ADVENTURE_VIEW_WORLD_X1, optionInWorldView(), [this]() { this->worldViewScale1x(); } },
{ EShortcut::ADVENTURE_VIEW_WORLD_X2, optionInWorldView(), [this]() { this->worldViewScale2x(); } }, { EShortcut::ADVENTURE_VIEW_WORLD_X2, optionInWorldView(), [this]() { this->worldViewScale2x(); } },
{ EShortcut::ADVENTURE_VIEW_WORLD_X4, optionInWorldView(), [this]() { this->worldViewScale4x(); } }, { EShortcut::ADVENTURE_VIEW_WORLD_X4, optionInWorldView(), [this]() { this->worldViewScale4x(); } },
{ EShortcut::ADVENTURE_VIEW_STATISTIC, optionViewStatistic(), [this]() { this->viewStatistic(); } },
{ EShortcut::ADVENTURE_TOGGLE_MAP_LEVEL, optionCanToggleLevel(), [this]() { this->switchMapLevel(); } }, { EShortcut::ADVENTURE_TOGGLE_MAP_LEVEL, optionCanToggleLevel(), [this]() { this->switchMapLevel(); } },
{ EShortcut::ADVENTURE_QUEST_LOG, optionCanViewQuests(), [this]() { this->showQuestlog(); } }, { EShortcut::ADVENTURE_QUEST_LOG, optionCanViewQuests(), [this]() { this->showQuestlog(); } },
{ EShortcut::ADVENTURE_TOGGLE_SLEEP, optionHeroSelected(), [this]() { this->toggleSleepWake(); } }, { EShortcut::ADVENTURE_TOGGLE_SLEEP, optionHeroSelected(), [this]() { this->toggleSleepWake(); } },
@@ -153,6 +154,11 @@ void AdventureMapShortcuts::worldViewScale4x()
owner.openWorldView(16); owner.openWorldView(16);
} }
void AdventureMapShortcuts::viewStatistic()
{
GAME->interface()->cb->requestStatistic();
}
void AdventureMapShortcuts::switchMapLevel() void AdventureMapShortcuts::switchMapLevel()
{ {
owner.hotkeySwitchMapLevel(); owner.hotkeySwitchMapLevel();
@@ -677,3 +683,11 @@ bool AdventureMapShortcuts::optionHeroDig()
auto hero = GAME->interface()->localState->getCurrentHero(); auto hero = GAME->interface()->localState->getCurrentHero();
return optionInMapView() && hero && hero->diggingStatus() == EDiggingStatus::CAN_DIG; return optionInMapView() && hero && hero->diggingStatus() == EDiggingStatus::CAN_DIG;
} }
bool AdventureMapShortcuts::optionViewStatistic()
{
if(!GAME->interface()->makingTurn)
return false;
auto day = GAME->interface()->cb->getDate(Date::DAY);
return optionInMapView() && day > 1;
}

View File

@@ -43,6 +43,7 @@ class AdventureMapShortcuts
void worldViewScale1x(); void worldViewScale1x();
void worldViewScale2x(); void worldViewScale2x();
void worldViewScale4x(); void worldViewScale4x();
void viewStatistic();
void switchMapLevel(); void switchMapLevel();
void showQuestlog(); void showQuestlog();
void toggleTrackHero(); void toggleTrackHero();
@@ -103,6 +104,7 @@ public:
bool optionMarketplace(); bool optionMarketplace();
bool optionHeroBoat(EPathfindingLayer layer); bool optionHeroBoat(EPathfindingLayer layer);
bool optionHeroDig(); bool optionHeroDig();
bool optionViewStatistic();
void setState(EAdventureState newState); void setState(EAdventureState newState);
EAdventureState getState() const; EAdventureState getState() const;

View File

@@ -149,6 +149,7 @@ enum class EShortcut
ADVENTURE_VIEW_WORLD_X1, ADVENTURE_VIEW_WORLD_X1,
ADVENTURE_VIEW_WORLD_X2, ADVENTURE_VIEW_WORLD_X2,
ADVENTURE_VIEW_WORLD_X4, ADVENTURE_VIEW_WORLD_X4,
ADVENTURE_VIEW_STATISTIC,
ADVENTURE_TRACK_HERO, ADVENTURE_TRACK_HERO,
ADVENTURE_TOGGLE_MAP_LEVEL, ADVENTURE_TOGGLE_MAP_LEVEL,
ADVENTURE_KINGDOM_OVERVIEW, ADVENTURE_KINGDOM_OVERVIEW,

View File

@@ -203,6 +203,7 @@ EShortcut ShortcutHandler::findShortcut(const std::string & identifier ) const
{"adventureViewWorld1", EShortcut::ADVENTURE_VIEW_WORLD_X1 }, {"adventureViewWorld1", EShortcut::ADVENTURE_VIEW_WORLD_X1 },
{"adventureViewWorld2", EShortcut::ADVENTURE_VIEW_WORLD_X2 }, {"adventureViewWorld2", EShortcut::ADVENTURE_VIEW_WORLD_X2 },
{"adventureViewWorld4", EShortcut::ADVENTURE_VIEW_WORLD_X4 }, {"adventureViewWorld4", EShortcut::ADVENTURE_VIEW_WORLD_X4 },
{"adventureViewStatistic", EShortcut::ADVENTURE_VIEW_STATISTIC },
{"adventureTrackHero", EShortcut::ADVENTURE_TRACK_HERO, }, {"adventureTrackHero", EShortcut::ADVENTURE_TRACK_HERO, },
{"adventureToggleMapLevel", EShortcut::ADVENTURE_TOGGLE_MAP_LEVEL}, {"adventureToggleMapLevel", EShortcut::ADVENTURE_TOGGLE_MAP_LEVEL},
{"adventureKingdomOverview", EShortcut::ADVENTURE_KINGDOM_OVERVIEW}, {"adventureKingdomOverview", EShortcut::ADVENTURE_KINGDOM_OVERVIEW},

View File

@@ -55,6 +55,7 @@ class NetworkLagPredictionTestVisitor final : public ICPackVisitor
//void visitMakeAction(MakeAction & pack) override; //void visitMakeAction(MakeAction & pack) override;
//void visitDigWithHero(DigWithHero & pack) override; //void visitDigWithHero(DigWithHero & pack) override;
//void visitCastAdvSpell(CastAdvSpell & pack) override; //void visitCastAdvSpell(CastAdvSpell & pack) override;
//void visitRequestStatistic(RequestStatistic & pack) override;
//void visitPlayerMessage(PlayerMessage & pack) override; //void visitPlayerMessage(PlayerMessage & pack) override;
//void visitSaveLocalState(SaveLocalState & pack) override; //void visitSaveLocalState(SaveLocalState & pack) override;

View File

@@ -102,6 +102,7 @@ private:
//void visitBattleResultsApplied(BattleResultsApplied & pack) override; //void visitBattleResultsApplied(BattleResultsApplied & pack) override;
//void visitBattleResultAccepted(BattleResultAccepted & pack) override; //void visitBattleResultAccepted(BattleResultAccepted & pack) override;
//void visitTurnTimeUpdate(TurnTimeUpdate & pack) override; //void visitTurnTimeUpdate(TurnTimeUpdate & pack) override;
//void visitResponseStatistic(ResponseStatistic & pack) override;
public: public:
PackRollbackGeneratorVisitor(const CGameState & gs) PackRollbackGeneratorVisitor(const CGameState & gs)

View File

@@ -44,6 +44,7 @@
"adventureViewPuzzle": "P", "adventureViewPuzzle": "P",
"adventureViewScenario": "I", "adventureViewScenario": "I",
"adventureViewSelected": [ "Return", "Keypad Enter"], "adventureViewSelected": [ "Return", "Keypad Enter"],
"adventureViewStatistic": "J",
"adventureViewWorld": "V", "adventureViewWorld": "V",
"adventureViewWorld1": "1", "adventureViewWorld1": "1",
"adventureViewWorld2": "2", "adventureViewWorld2": "2",

View File

@@ -392,6 +392,12 @@ void CCallback::castSpell(const CGHeroInstance *hero, SpellID spellID, const int
sendRequest(cas); sendRequest(cas);
} }
void CCallback::requestStatistic()
{
RequestStatistic sr;
sendRequest(sr);
}
int CCallback::mergeOrSwapStacks(const CArmedInstance *s1, const CArmedInstance *s2, SlotID p1, SlotID p2) int CCallback::mergeOrSwapStacks(const CArmedInstance *s1, const CArmedInstance *s2, SlotID p1, SlotID p2)
{ {
if(s1->getCreature(p1) == s2->getCreature(p2)) if(s1->getCreature(p1) == s2->getCreature(p2))

View File

@@ -84,6 +84,7 @@ public:
void buildBoat(const IShipyard *obj) override; void buildBoat(const IShipyard *obj) override;
void dig(const CGObjectInstance *hero) override; void dig(const CGObjectInstance *hero) override;
void castSpell(const CGHeroInstance *hero, SpellID spellID, const int3 &pos = int3(-1, -1, -1)) override; void castSpell(const CGHeroInstance *hero, SpellID spellID, const int3 &pos = int3(-1, -1, -1)) override;
void requestStatistic() override;
//friends //friends
friend class CClient; friend class CClient;

View File

@@ -76,6 +76,7 @@ public:
virtual void sendMessage(const std::string &mess, const CGObjectInstance * currentObject = nullptr) = 0; virtual void sendMessage(const std::string &mess, const CGObjectInstance * currentObject = nullptr) = 0;
virtual void gamePause(bool pause) = 0; virtual void gamePause(bool pause) = 0;
virtual void buildBoat(const IShipyard *obj) = 0; virtual void buildBoat(const IShipyard *obj) = 0;
virtual void requestStatistic() = 0;
// To implement high-level army management bulk actions // To implement high-level army management bulk actions
virtual int bulkMoveArmy(ObjectInstanceID srcArmy, ObjectInstanceID destArmy, SlotID srcSlot) = 0; virtual int bulkMoveArmy(ObjectInstanceID srcArmy, ObjectInstanceID destArmy, SlotID srcSlot) = 0;

View File

@@ -10,6 +10,7 @@
#pragma once #pragma once
#include "../constants/EntityIdentifiers.h" #include "../constants/EntityIdentifiers.h"
#include "../gameState/GameStatistics.h"
#include "../int3.h" #include "../int3.h"
VCMI_LIB_NAMESPACE_BEGIN VCMI_LIB_NAMESPACE_BEGIN
@@ -97,6 +98,8 @@ public:
virtual void playerStartsTurn(PlayerColor player){}; virtual void playerStartsTurn(PlayerColor player){};
virtual void playerEndsTurn(PlayerColor player){}; virtual void playerEndsTurn(PlayerColor player){};
virtual void responseStatistic(StatisticDataSet & statistic){};
//TODO shouldn't be moved down the tree? //TODO shouldn't be moved down the tree?
virtual void heroExchangeStarted(ObjectInstanceID hero1, ObjectInstanceID hero2, QueryID queryID){}; virtual void heroExchangeStarted(ObjectInstanceID hero1, ObjectInstanceID hero2, QueryID queryID){};
}; };

View File

@@ -153,6 +153,7 @@ public:
virtual void visitMakeAction(MakeAction & pack) {} virtual void visitMakeAction(MakeAction & pack) {}
virtual void visitDigWithHero(DigWithHero & pack) {} virtual void visitDigWithHero(DigWithHero & pack) {}
virtual void visitCastAdvSpell(CastAdvSpell & pack) {} virtual void visitCastAdvSpell(CastAdvSpell & pack) {}
virtual void visitRequestStatistic(RequestStatistic & pack) {}
virtual void visitSaveGame(SaveGame & pack) {} virtual void visitSaveGame(SaveGame & pack) {}
virtual void visitPlayerMessage(PlayerMessage & pack) {} virtual void visitPlayerMessage(PlayerMessage & pack) {}
virtual void visitPlayerMessageClient(PlayerMessageClient & pack) {} virtual void visitPlayerMessageClient(PlayerMessageClient & pack) {}
@@ -188,6 +189,7 @@ public:
virtual void visitBattleCancelled(BattleCancelled & pack) {} virtual void visitBattleCancelled(BattleCancelled & pack) {}
virtual void visitBattleResultAccepted(BattleResultAccepted & pack) {} virtual void visitBattleResultAccepted(BattleResultAccepted & pack) {}
virtual void visitBattleStackMoved(BattleLogMessage & pack) {} virtual void visitBattleStackMoved(BattleLogMessage & pack) {}
virtual void visitResponseStatistic(ResponseStatistic & pack) {}
}; };
VCMI_LIB_NAMESPACE_END VCMI_LIB_NAMESPACE_END

View File

@@ -688,6 +688,11 @@ void CastAdvSpell::visitTyped(ICPackVisitor & visitor)
visitor.visitCastAdvSpell(*this); visitor.visitCastAdvSpell(*this);
} }
void RequestStatistic::visitTyped(ICPackVisitor & visitor)
{
visitor.visitRequestStatistic(*this);
}
void SaveGame::visitTyped(ICPackVisitor & visitor) void SaveGame::visitTyped(ICPackVisitor & visitor)
{ {
visitor.visitSaveGame(*this); visitor.visitSaveGame(*this);
@@ -863,4 +868,9 @@ void TurnTimeUpdate::visitTyped(ICPackVisitor & visitor)
visitor.visitTurnTimeUpdate(*this); visitor.visitTurnTimeUpdate(*this);
} }
void ResponseStatistic::visitTyped(ICPackVisitor & visitor)
{
visitor.visitResponseStatistic(*this);
}
VCMI_LIB_NAMESPACE_END VCMI_LIB_NAMESPACE_END

View File

@@ -1523,4 +1523,18 @@ struct DLL_LINKAGE CenterView : public CPackForClient
} }
}; };
struct DLL_LINKAGE ResponseStatistic : public CPackForClient
{
PlayerColor player;
StatisticDataSet statistic;
void visitTyped(ICPackVisitor & visitor) override;
template <typename Handler> void serialize(Handler & h)
{
h & player;
h & statistic;
}
};
VCMI_LIB_NAMESPACE_END VCMI_LIB_NAMESPACE_END

View File

@@ -741,6 +741,16 @@ struct DLL_LINKAGE CastAdvSpell : public CPackForServer
} }
}; };
struct DLL_LINKAGE RequestStatistic : public CPackForServer
{
void visitTyped(ICPackVisitor & visitor) override;
template <typename Handler> void serialize(Handler & h)
{
h & static_cast<CPackForServer &>(*this);
}
};
/***********************************************************************************************************/ /***********************************************************************************************************/
struct DLL_LINKAGE SaveGame : public CPackForServer struct DLL_LINKAGE SaveGame : public CPackForServer

View File

@@ -295,6 +295,8 @@ void registerTypes(Serializer &s)
s.template registerType<SetTownName>(253); s.template registerType<SetTownName>(253);
s.template registerType<LobbySetBattleOnlyModeStartInfo>(254); s.template registerType<LobbySetBattleOnlyModeStartInfo>(254);
s.template registerType<BattleEnded>(255); s.template registerType<BattleEnded>(255);
s.template registerType<RequestStatistic>(256);
s.template registerType<ResponseStatistic>(257);
} }
VCMI_LIB_NAMESPACE_END VCMI_LIB_NAMESPACE_END

View File

@@ -1582,6 +1582,30 @@ void CGameHandler::throwAndComplain(GameConnectionID connectionID, const std::st
throwNotAllowedAction(connectionID); throwNotAllowedAction(connectionID);
} }
bool CGameHandler::responseStatistic(PlayerColor player)
{
ResponseStatistic rs;
rs.statistic = *statistics;
rs.player = player;
// Keep only team statistics, no enemy
const TeamState * team = gameState().getPlayerTeam(player);
for(auto it = rs.statistic.accumulatedValues.begin(); it != rs.statistic.accumulatedValues.end();) {
if (std::find(team->players.begin(), team->players.end(), it->first) == team->players.end())
it = rs.statistic.accumulatedValues.erase(it);
else
++it;
}
rs.statistic.data.erase(std::remove_if(rs.statistic.data.begin(), rs.statistic.data.end(), [&team](const StatisticDataSetEntry& entry) {
return std::find(team->players.begin(), team->players.end(), entry.player) == team->players.end();
}), rs.statistic.data.end());
sendAndApply(rs);
return true;
}
void CGameHandler::save(const std::string & filename) void CGameHandler::save(const std::string & filename)
{ {
logGlobal->info("Saving to %s", filename); logGlobal->info("Saving to %s", filename);

View File

@@ -237,6 +237,7 @@ public:
bool bulkSplitStack(SlotID src, ObjectInstanceID srcOwner, si32 howMany); bool bulkSplitStack(SlotID src, ObjectInstanceID srcOwner, si32 howMany);
bool bulkMergeStacks(SlotID slotSrc, ObjectInstanceID srcOwner); bool bulkMergeStacks(SlotID slotSrc, ObjectInstanceID srcOwner);
bool bulkSplitAndRebalanceStack(SlotID slotSrc, ObjectInstanceID srcOwner); bool bulkSplitAndRebalanceStack(SlotID slotSrc, ObjectInstanceID srcOwner);
bool responseStatistic(PlayerColor player);
void save(const std::string &fname); void save(const std::string &fname);
void load(const StartInfo &info); void load(const StartInfo &info);

View File

@@ -441,6 +441,13 @@ void ApplyGhNetPackVisitor::visitCastAdvSpell(CastAdvSpell & pack)
result = s->adventureCast(gh.spellEnv.get(), p); result = s->adventureCast(gh.spellEnv.get(), p);
} }
void ApplyGhNetPackVisitor::visitRequestStatistic(RequestStatistic & pack)
{
gh.throwIfPlayerNotActive(connection, &pack);
result = gh.responseStatistic(pack.player);
}
void ApplyGhNetPackVisitor::visitPlayerMessage(PlayerMessage & pack) void ApplyGhNetPackVisitor::visitPlayerMessage(PlayerMessage & pack)
{ {
if(!pack.player.isSpectator()) // TODO: clearly not a great way to verify permissions if(!pack.player.isSpectator()) // TODO: clearly not a great way to verify permissions

View File

@@ -65,6 +65,7 @@ public:
void visitMakeAction(MakeAction & pack) override; void visitMakeAction(MakeAction & pack) override;
void visitDigWithHero(DigWithHero & pack) override; void visitDigWithHero(DigWithHero & pack) override;
void visitCastAdvSpell(CastAdvSpell & pack) override; void visitCastAdvSpell(CastAdvSpell & pack) override;
void visitRequestStatistic(RequestStatistic & pack) override;
void visitPlayerMessage(PlayerMessage & pack) override; void visitPlayerMessage(PlayerMessage & pack) override;
void visitSaveLocalState(SaveLocalState & pack) override; void visitSaveLocalState(SaveLocalState & pack) override;
}; };