浏览代码

Rework CCallback <-> CClient interaction

- callback is now part of lib instead of weird class that is shared by
client and AI while being part of client
- callback interacts with client class via minimal interface class
- removed no longer used unlockGsWhileWaiting field
Ivan Savenko 5 月之前
父节点
当前提交
2c17c2d5b7

+ 1 - 5
AI/BattleAI/BattleAI.cpp

@@ -37,8 +37,7 @@
 
 CBattleAI::CBattleAI()
 	: side(BattleSide::NONE),
-	wasWaitingForRealize(false),
-	wasUnlockingGs(false)
+	wasWaitingForRealize(false)
 {
 }
 
@@ -48,7 +47,6 @@ CBattleAI::~CBattleAI()
 	{
 		//Restore previous state of CB - it may be shared with the main AI (like VCAI)
 		cb->waitTillRealize = wasWaitingForRealize;
-		cb->unlockGsWhenWaiting = wasUnlockingGs;
 	}
 }
 
@@ -69,9 +67,7 @@ void CBattleAI::initBattleInterface(std::shared_ptr<Environment> ENV, std::share
 	cb = CB;
 	playerID = *CB->getPlayerID();
 	wasWaitingForRealize = CB->waitTillRealize;
-	wasUnlockingGs = CB->unlockGsWhenWaiting;
 	CB->waitTillRealize = false;
-	CB->unlockGsWhenWaiting = false;
 	movesSkippedByDefense = 0;
 
 	logHexNumbers();

+ 0 - 1
AI/BattleAI/BattleAI.h

@@ -60,7 +60,6 @@ class CBattleAI : public CBattleGameInterface
 
 	//Previous setting of cb
 	bool wasWaitingForRealize;
-	bool wasUnlockingGs;
 	int movesSkippedByDefense;
 
 public:

+ 0 - 1
AI/Nullkiller/AIGateway.cpp

@@ -577,7 +577,6 @@ void AIGateway::initGameInterface(std::shared_ptr<Environment> env, std::shared_
 	NET_EVENT_HANDLER;
 	playerID = *myCb->getPlayerID();
 	myCb->waitTillRealize = true;
-	myCb->unlockGsWhenWaiting = true;
 
 	nullkiller->init(CB, this);
 	

+ 0 - 4
AI/StupidAI/StupidAI.cpp

@@ -20,7 +20,6 @@
 CStupidAI::CStupidAI()
 	: side(BattleSide::NONE)
 	, wasWaitingForRealize(false)
-	, wasUnlockingGs(false)
 {
 	print("created");
 }
@@ -32,7 +31,6 @@ CStupidAI::~CStupidAI()
 	{
 		//Restore previous state of CB - it may be shared with the main AI (like VCAI)
 		cb->waitTillRealize = wasWaitingForRealize;
-		cb->unlockGsWhenWaiting = wasUnlockingGs;
 	}
 }
 
@@ -43,9 +41,7 @@ void CStupidAI::initBattleInterface(std::shared_ptr<Environment> ENV, std::share
 	cb = CB;
 
 	wasWaitingForRealize = CB->waitTillRealize;
-	wasUnlockingGs = CB->unlockGsWhenWaiting;
 	CB->waitTillRealize = false;
-	CB->unlockGsWhenWaiting = false;
 }
 
 void CStupidAI::initBattleInterface(std::shared_ptr<Environment> ENV, std::shared_ptr<CBattleCallback> CB, AutocombatPreferences autocombatPreferences)

+ 0 - 1
AI/StupidAI/StupidAI.h

@@ -22,7 +22,6 @@ class CStupidAI : public CBattleGameInterface
 	std::shared_ptr<Environment> env;
 
 	bool wasWaitingForRealize;
-	bool wasUnlockingGs;
 
 	void print(const std::string &text) const;
 public:

+ 0 - 1
AI/VCAI/VCAI.cpp

@@ -628,7 +628,6 @@ void VCAI::initGameInterface(std::shared_ptr<Environment> ENV, std::shared_ptr<C
 	NET_EVENT_HANDLER; //sets ah->rm->cb
 	playerID = *myCb->getPlayerID();
 	myCb->waitTillRealize = true;
-	myCb->unlockGsWhenWaiting = true;
 	pathfinderCache = std::make_unique<PathfinderCache>(myCb.get(), PathfinderOptions(*myCb));
 
 	if(!fh)

+ 18 - 6
client/CPlayerInterface.cpp

@@ -12,6 +12,7 @@
 
 #include <vcmi/Artifact.h>
 
+#include "Client.h"
 #include "CServerHandler.h"
 #include "HeroMovementController.h"
 #include "PlayerLocalState.h"
@@ -668,7 +669,7 @@ void CPlayerInterface::battleStart(const BattleID & battleID, const CCreatureSet
 		autofightingAI->initBattleInterface(env, cb, autocombatPreferences);
 		autofightingAI->battleStart(battleID, army1, army2, tile, hero1, hero2, side, false);
 		isAutoFightOn = true;
-		cb->registerBattleInterface(autofightingAI);
+		registerBattleInterface(autofightingAI);
 	}
 
 	waitForAllDialogs();
@@ -805,9 +806,7 @@ void CPlayerInterface::activeStack(const BattleID & battleID, const CStack * sta
 			autofightingAI->activeStack(battleID, stack);
 			return;
 		}
-
-		cb->unregisterBattleInterface(autofightingAI);
-		autofightingAI.reset();
+		unregisterBattleInterface(autofightingAI);
 	}
 
 	assert(battleInt);
@@ -826,8 +825,7 @@ void CPlayerInterface::battleEnd(const BattleID & battleID, const BattleResult *
 	if(isAutoFightOn || autofightingAI)
 	{
 		isAutoFightOn = false;
-		cb->unregisterBattleInterface(autofightingAI);
-		autofightingAI.reset();
+		unregisterBattleInterface(autofightingAI);
 
 		if(!battleInt)
 		{
@@ -1831,3 +1829,17 @@ std::optional<BattleAction> CPlayerInterface::makeSurrenderRetreatDecision(const
 {
 	return std::nullopt;
 }
+
+void CPlayerInterface::registerBattleInterface(std::shared_ptr<CBattleGameInterface> battleEvents)
+{
+	autofightingAI = battleEvents;
+	GAME->server().client->registerBattleInterface(battleEvents, playerID);
+}
+
+void CPlayerInterface::unregisterBattleInterface(std::shared_ptr<CBattleGameInterface> battleEvents)
+{
+	assert(battleEvents == autofightingAI);
+	GAME->server().client->unregisterBattleInterface(autofightingAI, playerID);
+	autofightingAI.reset();
+}
+

+ 3 - 0
client/CPlayerInterface.h

@@ -206,6 +206,9 @@ public: // public interface for use by client via GAME->interface() access
 	///returns true if all events are processed internally
 	bool capturedAllEvents();
 
+	void registerBattleInterface(std::shared_ptr<CBattleGameInterface> battleEvents);
+	void unregisterBattleInterface(std::shared_ptr<CBattleGameInterface> battleEvents);
+
 	CPlayerInterface(PlayerColor Player);
 	~CPlayerInterface();
 

+ 23 - 13
client/Client.cpp

@@ -149,18 +149,6 @@ void CClient::loadGame(std::shared_ptr<CGameState> initializedGameState)
 	initPlayerInterfaces();
 }
 
-void CClient::save(const std::string & fname)
-{
-	if(!gameState().currentBattles.empty())
-	{
-		logNetwork->error("Game cannot be saved during battle!");
-		return;
-	}
-
-	SaveGame save_game(fname);
-	sendRequest(save_game, PlayerColor::NEUTRAL);
-}
-
 void CClient::endNetwork()
 {
 	GAME->map().endNetwork();
@@ -362,7 +350,12 @@ void CClient::handlePack(CPackForClient & pack)
 	logNetwork->trace("\tMade second apply on cl: %s", typeid(pack).name());
 }
 
-int CClient::sendRequest(const CPackForServer & request, PlayerColor player)
+std::optional<BattleAction> CClient::makeSurrenderRetreatDecision(PlayerColor player, const BattleID & battleID, const BattleStateInfoForRetreat & battleState)
+{
+	return playerint[player]->makeSurrenderRetreatDecision(battleID, battleState);
+}
+
+int CClient::sendRequest(const CPackForServer & request, PlayerColor player, bool waitTillRealize)
 {
 	static ui32 requestCounter = 1;
 
@@ -376,6 +369,13 @@ int CClient::sendRequest(const CPackForServer & request, PlayerColor player)
 	if(vstd::contains(playerint, player))
 		playerint[player]->requestSent(&request, requestID);
 
+	if(waitTillRealize)
+	{
+		logGlobal->trace("We'll wait till request %d is answered.\n", requestID);
+		auto gsUnlocker = vstd::makeUnlockSharedGuard(CGameState::mutex);
+		waitingRequest.waitWhileContains(requestID);
+	}
+
 	return requestID;
 }
 
@@ -550,3 +550,13 @@ extern "C" JNIEXPORT jboolean JNICALL Java_eu_vcmi_vcmi_NativeMethods_tryToSaveT
 	return true;
 }
 #endif
+
+void CClient::registerBattleInterface(std::shared_ptr<IBattleEventsReceiver> battleEvents, PlayerColor color)
+{
+	additionalBattleInts[color].push_back(battleEvents);
+}
+
+void CClient::unregisterBattleInterface(std::shared_ptr<IBattleEventsReceiver> battleEvents, PlayerColor color)
+{
+	additionalBattleInts[color] -= battleEvents;
+}

+ 8 - 3
client/Client.h

@@ -12,6 +12,7 @@
 #include <memory>
 #include <vcmi/Environment.h>
 
+#include "../lib/callback/IClient.h"
 #include "../lib/callback/IGameCallback.h"
 #include "../lib/ConditionalWait.h"
 #include "../lib/ResourceSet.h"
@@ -120,7 +121,7 @@ public:
 };
 
 /// Class which handles client - server logic
-class CClient : public IGameCallback, public Environment
+class CClient : public IGameCallback, public Environment, public IClient
 {
 	std::shared_ptr<CGameState> gamestate;
 public:
@@ -146,7 +147,6 @@ public:
 	void newGame(std::shared_ptr<CGameState> gameState);
 	void loadGame(std::shared_ptr<CGameState> gameState);
 
-	void save(const std::string & fname);
 	void endNetwork();
 	void finishGameplay();
 	void endGame();
@@ -159,10 +159,15 @@ public:
 	void installNewPlayerInterface(std::shared_ptr<CGameInterface> gameInterface, PlayerColor color, bool battlecb = false);
 	void installNewBattleInterface(std::shared_ptr<CBattleGameInterface> battleInterface, PlayerColor color, bool needCallback = true);
 
+	//Set of metrhods that allows adding more interfaces for this player that'll receive game event call-ins.
+	void registerBattleInterface(std::shared_ptr<IBattleEventsReceiver> battleEvents, PlayerColor color);
+	void unregisterBattleInterface(std::shared_ptr<IBattleEventsReceiver> battleEvents, PlayerColor color);
+
 	ThreadSafeVector<int> waitingRequest;
 
 	void handlePack(CPackForClient & pack); //applies the given pack and deletes it
-	int sendRequest(const CPackForServer & request, PlayerColor player); //returns ID given to that request
+	int sendRequest(const CPackForServer & request, PlayerColor player, bool waitTillRealize) override; //returns ID given to that request
+	std::optional<BattleAction> makeSurrenderRetreatDecision(PlayerColor player, const BattleID & battleID, const BattleStateInfoForRetreat & battleState) override;
 
 	void battleStarted(const BattleID & battle);
 	void battleFinished(const BattleID & battleID);

+ 1 - 1
client/ClientCommandManager.cpp

@@ -61,7 +61,7 @@ void ClientCommandManager::handleSaveCommand(std::istringstream & singleWordBuff
 
 	std::string saveFilename;
 	singleWordBuffer >> saveFilename;
-	GAME->server().client->save(saveFilename);
+	GAME->interface()->cb->save(saveFilename);
 	printCommandMessage("Game saved as: " + saveFilename);
 }
 

+ 2 - 5
client/battle/BattleWindow.cpp

@@ -707,8 +707,7 @@ void BattleWindow::bAutofightf()
 
 		ai->initBattleInterface(owner.curInt->env, owner.curInt->cb, autocombatPreferences);
 		ai->battleStart(owner.getBattleID(), owner.army1, owner.army2, int3(0,0,0), owner.attackingHeroInstance, owner.defendingHeroInstance, owner.getBattle()->battleGetMySide(), false);
-		owner.curInt->autofightingAI = ai;
-		owner.curInt->cb->registerBattleInterface(ai);
+		owner.curInt->registerBattleInterface(ai);
 
 		owner.requestAutofightingAIToTakeAction();
 	}
@@ -910,9 +909,7 @@ void BattleWindow::endWithAutocombat()
 			ai->battleStart(owner.getBattleID(), owner.army1, owner.army2, int3(0,0,0), owner.attackingHeroInstance, owner.defendingHeroInstance, owner.getBattle()->battleGetMySide(), false);
 
 			owner.curInt->isAutoFightOn = true;
-			owner.curInt->cb->registerBattleInterface(ai);
-			owner.curInt->autofightingAI = ai;
-
+			owner.curInt->registerBattleInterface(ai);
 			owner.requestAutofightingAIToTakeAction();
 
 			close();

+ 1 - 0
lib/CMakeLists.txt

@@ -472,6 +472,7 @@ set(lib_MAIN_HEADERS
 	callback/GameCallbackHolder.h
 	callback/IBattleCallback.h
 	callback/IBattleEventsReceiver.h
+	callback/IClient.h
 	callback/IGameActionCallback.h
 	callback/IGameCallback.h
 	callback/IGameEventCallback.h

+ 0 - 19
lib/UnlockGuard.h

@@ -90,29 +90,10 @@ namespace vstd
 		return unlock_guard<Mutex, detail::unlock_policy<Mutex> >(m_);
 	}
 	template<typename Mutex>
-	unlock_guard<Mutex, detail::unlock_policy<Mutex> > makeEmptyGuard(Mutex &)
-	{
-		return unlock_guard<Mutex, detail::unlock_policy<Mutex> >();
-	}
-	template<typename Mutex>
-	unlock_guard<Mutex, detail::unlock_policy<Mutex> > makeUnlockGuardIf(Mutex &m_, bool shallUnlock)
-	{
-		return shallUnlock 
-			? makeUnlockGuard(m_)
-			: unlock_guard<Mutex, detail::unlock_policy<Mutex> >();
-	}
-	template<typename Mutex>
 	unlock_guard<Mutex, detail::unlock_shared_policy<Mutex> > makeUnlockSharedGuard(Mutex &m_)
 	{
 		return unlock_guard<Mutex, detail::unlock_shared_policy<Mutex> >(m_);
 	}
-	template<typename Mutex>
-	unlock_guard<Mutex, detail::unlock_shared_policy<Mutex> > makeUnlockSharedGuardIf(Mutex &m_, bool shallUnlock)
-	{
-		return shallUnlock 
-			? makeUnlockSharedGuard(m_)
-			: unlock_guard<Mutex, detail::unlock_shared_policy<Mutex> >();
-	}
 
 	using unlock_shared_guard = unlock_guard<std::shared_mutex, detail::unlock_shared_policy<std::shared_mutex>>;
 }

+ 18 - 2
lib/callback/CBattleCallback.cpp

@@ -11,14 +11,17 @@
 #include "CBattleCallback.h"
 
 #include "CGameInterface.h"
+#include "IClient.h"
 
+#include "../UnlockGuard.h"
 #include "../battle/CPlayerBattleCallback.h"
 #include "../battle/IBattleState.h"
+#include "../gameState/CGameState.h"
 #include "../networkPacks/PacksForServer.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 
-CBattleCallback::CBattleCallback(std::optional<PlayerColor> player, CClient * C):
+CBattleCallback::CBattleCallback(std::optional<PlayerColor> player, IClient * C):
 	cl(C),
 	player(player)
 {
@@ -42,7 +45,7 @@ void CBattleCallback::battleMakeTacticAction(const BattleID & battleID, const Ba
 
 std::optional<BattleAction> CBattleCallback::makeSurrenderRetreatDecision(const BattleID & battleID, const BattleStateInfoForRetreat & battleState)
 {
-	return cl->playerint[getPlayerID().value()]->makeSurrenderRetreatDecision(battleID, battleState);
+	return cl->makeSurrenderRetreatDecision(*getPlayerID(), battleID, battleState);
 }
 
 std::shared_ptr<CPlayerBattleCallback> CBattleCallback::getBattle(const BattleID & battleID)
@@ -76,4 +79,17 @@ void CBattleCallback::onBattleEnded(const BattleID & battleID)
 	activeBattles.erase(battleID);
 }
 
+void CBattleCallback::battleMakeSpellAction(const BattleID & battleID, const BattleAction & action)
+{
+	assert(action.actionType == EActionType::HERO_SPELL);
+	MakeAction mca(action);
+	mca.battleID = battleID;
+	sendRequest(mca);
+}
+
+int CBattleCallback::sendRequest(const CPackForServer & request)
+{
+	return cl->sendRequest(request, *getPlayerID(), waitTillRealize);
+}
+
 VCMI_LIB_NAMESPACE_END

+ 3 - 7
lib/callback/CBattleCallback.h

@@ -16,20 +16,19 @@ VCMI_LIB_NAMESPACE_BEGIN
 struct CPackForServer;
 
 class IBattleInfo;
-class CClient;
+class IClient;
 
 class DLL_LINKAGE CBattleCallback : public IBattleCallback
 {
 	std::map<BattleID, std::shared_ptr<CPlayerBattleCallback>> activeBattles;
-
 	std::optional<PlayerColor> player;
+	IClient *cl;
 
 protected:
 	int sendRequest(const CPackForServer & request); //returns requestID (that'll be matched to requestID in PackageApplied)
-	CClient *cl;
 
 public:
-	CBattleCallback(std::optional<PlayerColor> player, CClient * C);
+	CBattleCallback(std::optional<PlayerColor> player, IClient * C);
 	void battleMakeSpellAction(const BattleID & battleID, const BattleAction & action) override;//for casting spells by hero - DO NOT use it for moving active stack
 	void battleMakeUnitAction(const BattleID & battleID, const BattleAction & action) override;
 	void battleMakeTacticAction(const BattleID & battleID, const BattleAction & action) override; // performs tactic phase actions
@@ -40,9 +39,6 @@ public:
 
 	void onBattleStarted(const IBattleInfo * info);
 	void onBattleEnded(const BattleID & battleID);
-
-	friend class CCallback;
-	friend class CClient;
 };
 
 VCMI_LIB_NAMESPACE_END

+ 17 - 47
lib/callback/CCallback.cpp

@@ -10,7 +10,6 @@
 #include "StdInc.h"
 #include "CCallback.h"
 
-#include "../UnlockGuard.h"
 #include "../gameState/CGameState.h"
 #include "../mapObjects/CGHeroInstance.h"
 #include "../mapObjects/CGTownInstance.h"
@@ -56,14 +55,14 @@ int CCallback::sendQueryReply(std::optional<int32_t> reply, QueryID queryID)
 	}
 
 	QueryReply pack(queryID, reply);
-	pack.player = *player;
+	pack.player = *getPlayerID();
 	return sendRequest(pack);
 }
 
 void CCallback::recruitCreatures(const CGDwelling * obj, const CArmedInstance * dst, CreatureID ID, ui32 amount, si32 level)
 {
 	// TODO exception for neutral dwellings shouldn't be hardcoded
-	if(player != obj->tempOwner && obj->ID != Obj::WAR_MACHINE_FACTORY && obj->ID != Obj::REFUGEE_CAMP)
+	if(getPlayerID() != obj->tempOwner && obj->ID != Obj::WAR_MACHINE_FACTORY && obj->ID != Obj::REFUGEE_CAMP)
 		return;
 
 	RecruitCreatures pack(obj->id, dst->id, ID, amount, level);
@@ -72,7 +71,7 @@ void CCallback::recruitCreatures(const CGDwelling * obj, const CArmedInstance *
 
 bool CCallback::dismissCreature(const CArmedInstance *obj, SlotID stackPos)
 {
-	if((player && obj->tempOwner != player) || (obj->stacksCount()<2  && obj->needsLastStack()))
+	if((getPlayerID() && obj->tempOwner != getPlayerID()) || (obj->stacksCount()<2  && obj->needsLastStack()))
 		return false;
 
 	DisbandCreature pack(stackPos,obj->id);
@@ -89,7 +88,7 @@ bool CCallback::upgradeCreature(const CArmedInstance *obj, SlotID stackPos, Crea
 
 void CCallback::endTurn()
 {
-	logGlobal->trace("Player %d ended his turn.", player->getNum());
+	logGlobal->trace("Player %d ended his turn.", getPlayerID()->getNum());
 	EndTurn pack;
 	sendRequest(pack);
 }
@@ -144,7 +143,7 @@ int CCallback::bulkMergeStacks(ObjectInstanceID armyId, SlotID srcSlot)
 
 bool CCallback::dismissHero(const CGHeroInstance *hero)
 {
-	if(player!=hero->tempOwner) return false;
+	if(getPlayerID()!=hero->tempOwner) return false;
 
 	DismissHero pack(hero->id);
 	sendRequest(pack);
@@ -220,7 +219,7 @@ void CCallback::eraseArtifactByClient(const ArtifactLocation & al)
 
 bool CCallback::buildBuilding(const CGTownInstance *town, BuildingID buildingID)
 {
-	if(town->tempOwner!=player)
+	if(town->tempOwner!=getPlayerID())
 		return false;
 
 	if(canBuildStructure(town, buildingID) != EBuildingState::ALLOWED)
@@ -233,7 +232,7 @@ bool CCallback::buildBuilding(const CGTownInstance *town, BuildingID buildingID)
 
 bool CCallback::visitTownBuilding(const CGTownInstance *town, BuildingID buildingID)
 {
-	if(town->tempOwner!=player)
+	if(town->tempOwner!=getPlayerID())
 		return false;
 
 	VisitTownBuilding pack(town->id, buildingID);
@@ -241,26 +240,6 @@ bool CCallback::visitTownBuilding(const CGTownInstance *town, BuildingID buildin
 	return true;
 }
 
-void CBattleCallback::battleMakeSpellAction(const BattleID & battleID, const BattleAction & action)
-{
-	assert(action.actionType == EActionType::HERO_SPELL);
-	MakeAction mca(action);
-	mca.battleID = battleID;
-	sendRequest(mca);
-}
-
-int CBattleCallback::sendRequest(const CPackForServer & request)
-{
-	int requestID = cl->sendRequest(request, *getPlayerID());
-	if(waitTillRealize)
-	{
-		logGlobal->trace("We'll wait till request %d is answered.\n", requestID);
-		auto gsUnlocker = vstd::makeUnlockSharedGuardIf(CGameState::mutex, unlockGsWhenWaiting);
-		cl->waitingRequest.waitWhileContains(requestID);
-	}
-	return requestID;
-}
-
 void CCallback::spellResearch( const CGTownInstance *town, SpellID spellAtSlot, bool accepted )
 {
 	SpellResearch pack(town->id, spellAtSlot, accepted);
@@ -269,7 +248,7 @@ void CCallback::spellResearch( const CGTownInstance *town, SpellID spellAtSlot,
 
 void CCallback::swapGarrisonHero( const CGTownInstance *town )
 {
-	if(town->tempOwner == *player || (town->getGarrisonHero() && town->getGarrisonHero()->tempOwner == *player ))
+	if(town->tempOwner == getPlayerID() || (town->getGarrisonHero() && town->getGarrisonHero()->tempOwner == getPlayerID() ))
 	{
 		GarrisonHeroSwap pack(town->id);
 		sendRequest(pack);
@@ -278,7 +257,7 @@ void CCallback::swapGarrisonHero( const CGTownInstance *town )
 
 void CCallback::buyArtifact(const CGHeroInstance *hero, ArtifactID aid)
 {
-	if(hero->tempOwner != *player) return;
+	if(hero->tempOwner != getPlayerID()) return;
 
 	BuyArtifact pack(hero->id,aid);
 	sendRequest(pack);
@@ -313,7 +292,7 @@ void CCallback::recruitHero(const CGObjectInstance *townOrTavern, const CGHeroIn
 	assert(hero);
 
 	HireHero pack(hero->getHeroTypeID(), townOrTavern->id, nextHero);
-	pack.player = *player;
+	pack.player = *getPlayerID();
 	sendRequest(pack);
 }
 
@@ -321,14 +300,15 @@ void CCallback::saveLocalState(const JsonNode & data)
 {
 	SaveLocalState state;
 	state.data = data;
-	state.player = *player;
+	state.player = *getPlayerID();
 
 	sendRequest(state);
 }
 
 void CCallback::save( const std::string &fname )
 {
-	cl->save(fname);
+	SaveGame save_game(fname);
+	sendRequest(save_game);
 }
 
 void CCallback::gamePause(bool pause)
@@ -336,7 +316,7 @@ void CCallback::gamePause(bool pause)
 	if(pause)
 	{
 		GamePause pack;
-		pack.player = *player;
+		pack.player = *getPlayerID();
 		sendRequest(pack);
 	}
 	else
@@ -349,8 +329,8 @@ void CCallback::sendMessage(const std::string &mess, const CGObjectInstance * cu
 {
 	ASSERT_IF_CALLED_WITH_PLAYER
 	PlayerMessage pm(mess, currentObject? currentObject->id : ObjectInstanceID(-1));
-	if(player)
-		pm.player = *player;
+	if(getPlayerID())
+		pm.player = *getPlayerID();
 	sendRequest(pm);
 }
 
@@ -361,7 +341,7 @@ void CCallback::buildBoat( const IShipyard *obj )
 	sendRequest(bb);
 }
 
-CCallback::CCallback(std::shared_ptr<CGameState> gamestate, std::optional<PlayerColor> Player, CClient * C)
+CCallback::CCallback(std::shared_ptr<CGameState> gamestate, std::optional<PlayerColor> Player, IClient * C)
 	: CBattleCallback(Player, C)
 	, gamestate(gamestate)
 {
@@ -414,14 +394,4 @@ int CCallback::mergeOrSwapStacks(const CArmedInstance *s1, const CArmedInstance
 		return swapCreatures(s1, s2, p1, p2);
 }
 
-void CCallback::registerBattleInterface(std::shared_ptr<IBattleEventsReceiver> battleEvents)
-{
-	cl->additionalBattleInts[*player].push_back(battleEvents);
-}
-
-void CCallback::unregisterBattleInterface(std::shared_ptr<IBattleEventsReceiver> battleEvents)
-{
-	cl->additionalBattleInts[*player] -= battleEvents;
-}
-
 VCMI_LIB_NAMESPACE_END

+ 1 - 5
lib/callback/CCallback.h

@@ -30,7 +30,7 @@ class DLL_LINKAGE CCallback : public CPlayerSpecificInfoCallback, public CBattle
 	const CGameState & gameState() const final { return *gamestate; }
 
 public:
-	CCallback(std::shared_ptr<CGameState> gamestate, std::optional<PlayerColor> Player, CClient * C);
+	CCallback(std::shared_ptr<CGameState> gamestate, std::optional<PlayerColor> Player, IClient * C);
 	virtual ~CCallback();
 
 	//client-specific functionalities (pathfinding)
@@ -39,10 +39,6 @@ public:
 
 	std::optional<PlayerColor> getPlayerID() const override;
 
-	//Set of metrhods that allows adding more interfaces for this player that'll receive game event call-ins.
-	void registerBattleInterface(std::shared_ptr<IBattleEventsReceiver> battleEvents);
-	void unregisterBattleInterface(std::shared_ptr<IBattleEventsReceiver> battleEvents);
-
 //commands
 	void moveHero(const CGHeroInstance *h, const std::vector<int3> & path, bool transit) override;
 	void moveHero(const CGHeroInstance *h, const int3 & destination, bool transit) override;

+ 0 - 2
lib/callback/CGameInfoCallback.h

@@ -36,8 +36,6 @@ class CGTeleport;
 class CGTownInstance;
 class IMarket;
 
-VCMI_LIB_NAMESPACE_BEGIN
-
 class DLL_LINKAGE CGameInfoCallback : public IGameInfoCallback
 {
 protected:

+ 28 - 0
lib/callback/IClient.h

@@ -0,0 +1,28 @@
+/*
+ * IClient.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
+
+VCMI_LIB_NAMESPACE_BEGIN
+
+class BattleID;
+class BattleAction;
+class BattleStateInfoForRetreat;
+class PlayerColor;
+struct CPackForServer;
+
+class DLL_LINKAGE IClient
+{
+public:
+	virtual std::optional<BattleAction> makeSurrenderRetreatDecision(PlayerColor player, const BattleID & battleID, const BattleStateInfoForRetreat & battleState) = 0;
+	virtual int sendRequest(const CPackForServer & request, PlayerColor player, bool waitTillRealize) = 0;
+	virtual ~IClient() = default;
+};
+
+VCMI_LIB_NAMESPACE_END

+ 2 - 0
lib/callback/IGameCallback.h

@@ -12,6 +12,8 @@
 #include "CPrivilegedInfoCallback.h"
 #include "IGameEventCallback.h"
 
+VCMI_LIB_NAMESPACE_BEGIN
+
 #if SCRIPTING_ENABLED
 namespace scripting
 {