Browse Source

show statistics ingame

Laserlicht 1 week ago
parent
commit
afb045ef14

+ 1 - 0
Mods/vcmi/Content/config/english.json

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

+ 1 - 0
Mods/vcmi/Content/config/german.json

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

+ 6 - 0
client/CPlayerInterface.cpp

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

+ 2 - 0
client/CPlayerInterface.h

@@ -12,6 +12,7 @@
 #include "ArtifactsUIController.h"
 
 #include "../lib/callback/CGameInterface.h"
+#include "../lib/gameState/GameStatistics.h"
 #include "../lib/FunctionList.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 showWorldViewEx(const std::vector<ObjectPosInfo> & objectPositions, bool showTerrain) override;
 	void setColorScheme(ColorScheme scheme) override;
+	void responseStatistic(StatisticDataSet & statistic) override;
 
 	//for battles
 	void actionFinished(const BattleID & battleID, const BattleAction& action) override;//occurs AFTER action taken by active stack or by the hero

+ 1 - 0
client/ClientNetPackVisitors.h

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

+ 5 - 0
client/NetPacksClient.cpp

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

+ 14 - 0
client/adventureMap/AdventureMapShortcuts.cpp

@@ -73,6 +73,7 @@ std::vector<AdventureMapShortcutState> AdventureMapShortcuts::getShortcuts()
 		{ EShortcut::ADVENTURE_VIEW_WORLD_X1,    optionInWorldView(),    [this]() { this->worldViewScale1x(); } },
 		{ EShortcut::ADVENTURE_VIEW_WORLD_X2,    optionInWorldView(),    [this]() { this->worldViewScale2x(); } },
 		{ 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_QUEST_LOG,        optionCanViewQuests(),  [this]() { this->showQuestlog(); } },
 		{ EShortcut::ADVENTURE_TOGGLE_SLEEP,     optionHeroSelected(),   [this]() { this->toggleSleepWake(); } },
@@ -153,6 +154,11 @@ void AdventureMapShortcuts::worldViewScale4x()
 	owner.openWorldView(16);
 }
 
+void AdventureMapShortcuts::viewStatistic()
+{
+	GAME->interface()->cb->requestStatistic();
+}
+
 void AdventureMapShortcuts::switchMapLevel()
 {
 	owner.hotkeySwitchMapLevel();
@@ -677,3 +683,11 @@ bool AdventureMapShortcuts::optionHeroDig()
 	auto hero = GAME->interface()->localState->getCurrentHero();
 	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;
+}

+ 2 - 0
client/adventureMap/AdventureMapShortcuts.h

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

+ 1 - 0
client/gui/Shortcut.h

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

+ 1 - 0
client/gui/ShortcutHandler.cpp

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

+ 1 - 0
client/netlag/NetworkLagPredictionTestVisitor.h

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

+ 1 - 0
client/netlag/PackRollbackGeneratorVisitor.h

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

+ 1 - 0
config/keyBindingsConfig.json

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

+ 6 - 0
lib/callback/CCallback.cpp

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

+ 1 - 0
lib/callback/CCallback.h

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

+ 1 - 0
lib/callback/IGameActionCallback.h

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

+ 3 - 0
lib/callback/IGameEventsReceiver.h

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

+ 2 - 0
lib/networkPacks/NetPackVisitor.h

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

+ 10 - 0
lib/networkPacks/NetPacksLib.cpp

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

+ 14 - 0
lib/networkPacks/PacksForClient.h

@@ -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

+ 10 - 0
lib/networkPacks/PacksForServer.h

@@ -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

+ 2 - 0
lib/serializer/RegisterTypes.h

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

+ 24 - 0
server/CGameHandler.cpp

@@ -1582,6 +1582,30 @@ void CGameHandler::throwAndComplain(GameConnectionID connectionID, const std::st
 	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)
 {
 	logGlobal->info("Saving to %s", filename);

+ 1 - 0
server/CGameHandler.h

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

+ 7 - 0
server/NetPacksServer.cpp

@@ -441,6 +441,13 @@ void ApplyGhNetPackVisitor::visitCastAdvSpell(CastAdvSpell & pack)
 	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)
 {
 	if(!pack.player.isSpectator()) // TODO: clearly not a great way to verify permissions

+ 1 - 0
server/ServerNetPackVisitors.h

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