Browse Source

Add MapInfoCallback and EditorCallback

Michał Zaremba 4 months ago
parent
commit
b2e51a5fb1

+ 5 - 1
lib/CMakeLists.txt

@@ -85,6 +85,8 @@ set(lib_MAIN_SRCS
 	callback/CNonConstInfoCallback.cpp
 	callback/CPlayerSpecificInfoCallback.cpp
 	callback/GameRandomizer.cpp
+	callback/MapInfoCallback.cpp
+	callback/EditorCallback.cpp
 
 	campaign/CampaignBonus.cpp
 	campaign/CampaignHandler.cpp
@@ -482,7 +484,9 @@ set(lib_MAIN_HEADERS
 	callback/IGameInfoCallback.h
 	callback/IGameRandomizer.h
 	callback/GameRandomizer.h
-
+	callback/MapInfoCallback.h
+	callback/EditorCallback.h
+	
 	campaign/CampaignBonus.h
 	campaign/CampaignConstants.h
 	campaign/CampaignHandler.h

+ 6 - 83
lib/callback/CGameInfoCallback.cpp

@@ -34,11 +34,10 @@ VCMI_LIB_NAMESPACE_BEGIN
 #define ERROR_RET_IF(cond, txt) do {if(cond){logGlobal->error("%s: %s", BOOST_CURRENT_FUNCTION, txt); return;}} while(0)
 #define ERROR_RET_VAL_IF(cond, txt, retVal) do {if(cond){logGlobal->error("%s: %s", BOOST_CURRENT_FUNCTION, txt); return retVal;}} while(0)
 
-PlayerColor CGameInfoCallback::getOwner(ObjectInstanceID heroID) const
+const IMarket * CGameInfoCallback::getMarket(ObjectInstanceID objid) const
 {
-	const CGObjectInstance *obj = getObj(heroID);
-	ERROR_RET_VAL_IF(!obj, "No such object!", PlayerColor::CANNOT_DETERMINE);
-	return obj->tempOwner;
+	const CGObjectInstance * obj = getObj(objid, false);
+	return dynamic_cast<const IMarket*>(obj);
 }
 
 int CGameInfoCallback::getResource(PlayerColor Player, GameResID which) const
@@ -54,21 +53,6 @@ const PlayerSettings * CGameInfoCallback::getPlayerSettings(PlayerColor color) c
 	return &gameState().getStartInfo()->getIthPlayersSettings(color);
 }
 
-bool CGameInfoCallback::isAllowed(SpellID id) const
-{
-	return gameState().getMap().allowedSpells.count(id) != 0;
-}
-
-bool CGameInfoCallback::isAllowed(ArtifactID id) const
-{
-	return gameState().getMap().allowedArtifact.count(id) != 0;
-}
-
-bool CGameInfoCallback::isAllowed(SecondarySkill id) const
-{
-	return gameState().getMap().allowedAbilities.count(id) != 0;
-}
-
 std::optional<PlayerColor> CGameInfoCallback::getPlayerID() const
 {
 	return std::nullopt;
@@ -129,20 +113,10 @@ TurnTimerInfo CGameInfoCallback::getPlayerTurnTime(PlayerColor color) const
 
 const CGObjectInstance* CGameInfoCallback::getObj(ObjectInstanceID objid, bool verbose) const
 {
-	if (!objid.hasValue())
-	{
-		if(verbose)
-			logGlobal->error("Cannot get object with id %d. No such object", objid.getNum());
-		return nullptr;
-	}
+	const CGObjectInstance * ret = MapInfoCallback::getObj(objid, verbose);
 
-	const CGObjectInstance *ret = gameState().getMap().getObject(objid);
 	if(!ret)
-	{
-		if(verbose)
-			logGlobal->error("Cannot get object with id %d. Object was removed", objid.getNum());
 		return nullptr;
-	}
 
 	if(getPlayerID().has_value() && !isVisibleFor(ret, *getPlayerID()) && ret->tempOwner != getPlayerID())
 	{
@@ -154,32 +128,6 @@ const CGObjectInstance* CGameInfoCallback::getObj(ObjectInstanceID objid, bool v
 	return ret;
 }
 
-const CGHeroInstance* CGameInfoCallback::getHero(ObjectInstanceID objid) const
-{
-	const CGObjectInstance *obj = getObj(objid, false);
-	if(obj)
-		return dynamic_cast<const CGHeroInstance*>(obj);
-	else
-		return nullptr;
-}
-const CGTownInstance* CGameInfoCallback::getTown(ObjectInstanceID objid) const
-{
-	const CGObjectInstance *obj = getObj(objid, false);
-	if(obj)
-		return dynamic_cast<const CGTownInstance*>(obj);
-	else
-		return nullptr;
-}
-
-const IMarket * CGameInfoCallback::getMarket(ObjectInstanceID objid) const
-{
-	const CGObjectInstance * obj = getObj(objid, false);
-	if(obj)
-		return dynamic_cast<const IMarket*>(obj);
-	else
-		return nullptr;
-}
-
 void CGameInfoCallback::fillUpgradeInfo(const CArmedInstance *obj, SlotID stackPos, UpgradeInfo & out) const
 {
 	ERROR_RET_IF(!canGetFullInfo(obj), "Cannot get info about not owned object!");
@@ -295,11 +243,6 @@ bool CGameInfoCallback::getTownInfo(const CGObjectInstance * town, InfoAboutTown
 	return true;
 }
 
-const IGameSettings & CGameInfoCallback::getSettings() const
-{
-	return gameState().getSettings();
-}
-
 int3 CGameInfoCallback::guardingCreaturePosition (int3 pos) const
 {
 	ERROR_RET_VAL_IF(!isVisible(pos), "Tile is not visible!", int3(-1,-1,-1));
@@ -506,7 +449,7 @@ std::vector<const CGObjectInstance *> CGameInfoCallback::getAllVisitableObjs() c
 	return ret;
 }
 
-const CGObjectInstance * CGameInfoCallback::getTopObj (int3 pos) const
+const CGObjectInstance * CGameInfoCallback::getTopObj(int3 pos) const
 {
 	return vstd::backOrNull(getVisitableObjs(pos));
 }
@@ -525,11 +468,6 @@ std::vector <const CGObjectInstance *> CGameInfoCallback::getFlaggableObjects(in
 	return ret;
 }
 
-int3 CGameInfoCallback::getMapSize() const
-{
-	return int3(gameState().getMap().width, gameState().getMap().height, gameState().getMap().twoLevel ? 2 : 1);
-}
-
 std::vector<const CGHeroInstance *> CGameInfoCallback::getAvailableHeroes(const CGObjectInstance * townOrTavern) const
 {
 	ASSERT_IF_CALLED_WITH_PLAYER
@@ -643,7 +581,7 @@ EBuildingState CGameInfoCallback::canBuildStructure( const CGTownInstance *t, Bu
 	return EBuildingState::ALLOWED;
 }
 
-const CMapHeader * CGameInfoCallback::getMapHeader() const
+const CMap * CGameInfoCallback::getMapConstPtr() const
 {
 	return &gameState().getMap();
 }
@@ -778,11 +716,6 @@ const TeamState * CGameInfoCallback::getPlayerTeam( PlayerColor color ) const
 	}
 }
 
-bool CGameInfoCallback::isInTheMap(const int3 &pos) const
-{
-	return gameState().getMap().isInTheMap(pos);
-}
-
 void CGameInfoCallback::getVisibleTilesInRange(std::unordered_set<int3> &tiles, int3 pos, int radious, int3::EDistanceFormula distanceFormula) const
 {
 	gameState().getTilesInRange(tiles, pos, radious, ETileVisibility::REVEALED, *getPlayerID(),  distanceFormula);
@@ -793,16 +726,6 @@ void CGameInfoCallback::calculatePaths(const std::shared_ptr<PathfinderConfig> &
 	gameState().calculatePaths(config);
 }
 
-const CArtifactInstance * CGameInfoCallback::getArtInstance( ArtifactInstanceID aid ) const
-{
-	return gameState().getMap().getArtifactInstance(aid);
-}
-
-const CGObjectInstance * CGameInfoCallback::getObjInstance( ObjectInstanceID oid ) const
-{
-	return gameState().getMap().getObject((oid));
-}
-
 const CArtifactSet * CGameInfoCallback::getArtSet(const ArtifactLocation & loc) const
 {
 	auto & gs = const_cast<CGameState&>(gameState());

+ 4 - 14
lib/callback/CGameInfoCallback.h

@@ -9,16 +9,18 @@
  */
 #pragma once
 
-#include "IGameInfoCallback.h"
+#include "MapInfoCallback.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 
 struct SThievesGuildInfo;
 class Player;
 
-class DLL_LINKAGE CGameInfoCallback : public IGameInfoCallback
+class DLL_LINKAGE CGameInfoCallback : public MapInfoCallback
 {
 protected:
+	const CMap * getMapConstPtr() const override;
+
 	bool hasAccess(std::optional<PlayerColor> playerId) const;
 
 	bool canGetFullInfo(const CGObjectInstance *obj) const; //true we player owns obj or ally owns obj or privileged mode
@@ -28,10 +30,6 @@ public:
 	int getDate(Date mode=Date::DAY)const override; //mode=0 - total days in game, mode=1 - day of week, mode=2 - current week, mode=3 - current month
 	const StartInfo * getStartInfo() const override;
 	const StartInfo * getInitialStartInfo() const;
-	bool isAllowed(SpellID id) const override;
-	bool isAllowed(ArtifactID id) const override;
-	bool isAllowed(SecondarySkill id) const override;
-	const IGameSettings & getSettings() const override;
 
 	//player
 	virtual std::optional<PlayerColor> getPlayerID() const;
@@ -55,14 +53,11 @@ public:
 	void fillUpgradeInfo(const CArmedInstance *obj, SlotID stackPos, UpgradeInfo &out) const;
 
 	//hero
-	const CGHeroInstance * getHero(ObjectInstanceID objid) const override;
 	int getHeroCount(PlayerColor player, bool includeGarrisoned) const override;
 	std::vector<const CGHeroInstance*> getHeroes(PlayerColor player) const;
 	bool getHeroInfo(const CGObjectInstance * hero, InfoAboutHero & dest, const CGObjectInstance * selectedObject = nullptr) const;
 	int32_t getSpellCost(const spells::Spell * sp, const CGHeroInstance * caster) const;
 	int64_t estimateSpellDamage(const CSpell * sp, const CGHeroInstance * hero) const;
-	const CArtifactInstance * getArtInstance(ArtifactInstanceID aid) const override;
-	const CGObjectInstance * getObjInstance(ObjectInstanceID oid) const override;
 	const CArtifactSet * getArtSet(const ArtifactLocation & loc) const;
 
 	//objects
@@ -72,25 +67,20 @@ public:
 	std::vector<const CGObjectInstance *> getAllVisitableObjs() const;
 	std::vector<const CGObjectInstance *> getFlaggableObjects(int3 pos) const;
 	const CGObjectInstance * getTopObj(int3 pos) const override;
-	PlayerColor getOwner(ObjectInstanceID heroID) const;
 	const IMarket * getMarket(ObjectInstanceID objid) const;
 
 	//map
 	int3 guardingCreaturePosition (int3 pos) const override;
 	std::vector<const CGObjectInstance*> getGuardingCreatures (int3 pos) const override;
 	bool isTileGuardedUnchecked(int3 tile) const;
-	const CMapHeader * getMapHeader()const override;
-	int3 getMapSize() const override;
 	const TerrainTile * getTile(int3 tile, bool verbose = true) const override;
 	const TerrainTile * getTileUnchecked(int3 tile) const override;
-	bool isInTheMap(const int3 &pos) const override;
 	void getVisibleTilesInRange(std::unordered_set<int3> &tiles, int3 pos, int radious, int3::EDistanceFormula distanceFormula = int3::DIST_2D) const;
 	void calculatePaths(const std::shared_ptr<PathfinderConfig> & config) const override;
 	EDiggingStatus getTileDigStatus(int3 tile, bool verbose = true) const override;
 	bool checkForVisitableDir(const int3 & src, const int3 & dst) const override;
 
 	//town
-	const CGTownInstance* getTown(ObjectInstanceID objid) const override;
 	int howManyTowns(PlayerColor Player) const;
 	std::vector<const CGHeroInstance *> getAvailableHeroes(const CGObjectInstance * townOrTavern) const;
 	std::string getTavernRumor(const CGObjectInstance * townOrTavern) const;

+ 6 - 6
lib/callback/IGameInfoCallback.h

@@ -73,10 +73,10 @@ public:
 	/// WEEK - number of week within month (1..4)
 	/// MONTH - current month (1..inf)
 	/// DAY_OF_MONTH - number of day within current month, (1..28)
-	virtual int getDate(Date mode=Date::DAY)const = 0;
+	virtual int getDate(Date mode=Date::DAY) const = 0;
 
 	/// Return pointer to static map header for current map
-	virtual const CMapHeader * getMapHeader()const = 0;
+	virtual const CMapHeader * getMapHeader() const = 0;
 
 	/// Returns post-randomized startin information on current game
 	virtual const StartInfo * getStartInfo() const = 0;
@@ -103,9 +103,9 @@ public:
 	virtual bool isInTheMap(const int3 &pos) const = 0;
 
 	/// Returns pointer to specified team. Team must be valid
-	virtual const TeamState *getTeam(TeamID teamID) const = 0;
+	virtual const TeamState * getTeam(TeamID teamID) const = 0;
 	/// Returns pointer to specified team. Player must be valid. Players without belong to a team with single member
-	virtual const TeamState *getPlayerTeam(PlayerColor color) const = 0;
+	virtual const TeamState * getPlayerTeam(PlayerColor color) const = 0;
 	/// Returns current state of a specific player. Player must be valid
 	virtual const PlayerState * getPlayerState(PlayerColor color, bool verbose = true) const = 0;
 	/// Returns starting settings of a specified player. Player must be valid
@@ -122,7 +122,7 @@ public:
 	/// Returns pointer to hero using provided object ID. Returns null on failure
 	virtual const CGHeroInstance * getHero(ObjectInstanceID objid) const = 0;
 	/// Returns pointer to town using provided object ID. Returns null on failure
-	virtual const CGTownInstance* getTown(ObjectInstanceID objid) const = 0;
+	virtual const CGTownInstance * getTown(ObjectInstanceID objid) const = 0;
 	/// Returns pointer to object using provided object ID. Returns null on failure
 	virtual const CGObjectInstance * getObj(ObjectInstanceID objid, bool verbose = true) const = 0;
 	/// Returns pointer to object using provided object ID. Returns null on failure
@@ -146,7 +146,7 @@ public:
 	/// Return true if src tile is visitable from dst tile
 	virtual bool checkForVisitableDir(const int3 & src, const int3 & dst) const = 0;
 	/// Returns all wandering monsters that guard specified tile
-	virtual std::vector<const CGObjectInstance*> getGuardingCreatures (int3 pos) const = 0;
+	virtual std::vector<const CGObjectInstance *> getGuardingCreatures (int3 pos) const = 0;
 
 	/// Returns all tiles within specified range with specific tile visibility mode
 	virtual void getTilesInRange(std::unordered_set<int3> & tiles, const int3 & pos, int radius, ETileVisibility mode, std::optional<PlayerColor> player = std::optional<PlayerColor>(), int3::EDistanceFormula formula = int3::DIST_2D) const = 0;

+ 120 - 0
lib/callback/MapInfoCallback.cpp

@@ -0,0 +1,120 @@
+#include "StdInc.h"
+#include "MapInfoCallback.h"
+#include "../constants/EntityIdentifiers.h"
+#include "../mapObjects/CGObjectInstance.h"
+#include "../mapObjects/CGHeroInstance.h"
+#include "../mapObjects/CGTownInstance.h"
+#include "../mapObjects/MiscObjects.h"
+#include "../StartInfo.h"
+#include "../mapping/CMap.h"
+#include "../spells/CSpellHandler.h"
+
+VCMI_LIB_NAMESPACE_BEGIN
+
+MapInfoCallback::~MapInfoCallback() = default;
+
+const CGObjectInstance * MapInfoCallback::getObj(ObjectInstanceID objid, bool verbose) const
+{
+	if(!objid.hasValue())
+	{
+		if(verbose)
+			logGlobal->error("Cannot get object with id %d. No such object", objid.getNum());
+		return nullptr;
+	}
+
+	const CGObjectInstance * ret = getMapConstPtr()->getObject(objid);
+	if(!ret && verbose)
+	{
+		logGlobal->error("Cannot get object with id %d. Object was removed", objid.getNum());
+		return nullptr;
+	}
+
+	return ret;
+}
+
+const CGHeroInstance * MapInfoCallback::getHero(ObjectInstanceID objid) const
+{
+	const CGObjectInstance * obj = getObj(objid, false);
+	return dynamic_cast<const CGHeroInstance *>(obj);
+}
+
+const CGTownInstance * MapInfoCallback::getTown(ObjectInstanceID objid) const
+{
+	const CGObjectInstance * obj = getObj(objid, false);
+	return dynamic_cast<const CGTownInstance*>(obj);
+}
+
+PlayerColor MapInfoCallback::getOwner(ObjectInstanceID heroID) const
+{
+	const CGObjectInstance * obj = getObj(heroID);
+	if(!obj)
+	{
+		logGlobal->error("MapInfoCallback::getOwner(heroID): No such object for heroID: %d", heroID.num);
+		return PlayerColor::CANNOT_DETERMINE;
+	}
+
+	return obj->tempOwner;
+}
+
+const CArtifactInstance * MapInfoCallback::getArtInstance(ArtifactInstanceID aid) const
+{
+	return getMapConstPtr()->getArtifactInstance(aid);
+}
+
+const CGObjectInstance * MapInfoCallback::getObjInstance(ObjectInstanceID oid) const
+{
+	return getMapConstPtr()->getObject((oid));
+}
+
+bool MapInfoCallback::isInTheMap(const int3 & pos) const
+{
+	return getMapConstPtr()->isInTheMap(pos);
+}
+
+bool MapInfoCallback::isAllowed(SpellID id) const
+{
+	return getMapConstPtr()->allowedSpells.count(id) != 0;
+}
+
+bool MapInfoCallback::isAllowed(ArtifactID id) const
+{
+	return getMapConstPtr()->allowedArtifact.count(id) != 0;
+}
+
+bool MapInfoCallback::isAllowed(SecondarySkill id) const
+{
+	return getMapConstPtr()->allowedAbilities.count(id) != 0;
+}
+
+int3 MapInfoCallback::getMapSize() const
+{
+	return int3(getMapConstPtr()->width, getMapConstPtr()->height, getMapConstPtr()->twoLevel ? 2 : 1);
+}
+
+void MapInfoCallback::getAllowedSpells(std::vector<SpellID> & out, std::optional<ui16> level)
+{
+	for (auto const & spellID : getMapConstPtr()->allowedSpells)
+	{
+		const auto * spell = spellID.toEntity(LIBRARY);
+
+		if (!isAllowed(spellID))
+			continue;
+
+		if (level.has_value() && spell->getLevel() != level)
+			continue;
+
+		out.push_back(spellID);
+	}
+}
+
+const IGameSettings & MapInfoCallback::getSettings() const
+{
+	return getMapConstPtr()->getSettings();
+}
+
+const CMapHeader * MapInfoCallback::getMapHeader() const
+{
+	return getMapConstPtr();
+}
+
+VCMI_LIB_NAMESPACE_END

+ 43 - 0
lib/callback/MapInfoCallback.h

@@ -0,0 +1,43 @@
+/*
+ * MapInfoCallback.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 "IGameInfoCallback.h"
+
+VCMI_LIB_NAMESPACE_BEGIN
+
+class CMap;
+
+class DLL_LINKAGE MapInfoCallback : public IGameInfoCallback
+{
+public:
+	virtual ~MapInfoCallback();
+	virtual const CMap * getMapConstPtr() const = 0;
+
+	const CGObjectInstance * getObj(ObjectInstanceID objid, bool verbose = true) const override;
+	const CGObjectInstance * getObjInstance(ObjectInstanceID oid) const override;
+	const CArtifactInstance * getArtInstance(ArtifactInstanceID aid) const override;
+	const CGHeroInstance * getHero(ObjectInstanceID objid) const override;
+	const CGTownInstance * getTown(ObjectInstanceID objid) const override;
+	PlayerColor getOwner(ObjectInstanceID heroID) const;
+
+	bool isInTheMap(const int3 & pos) const override;
+	bool isAllowed(SpellID id) const override;
+	bool isAllowed(ArtifactID id) const override;
+	bool isAllowed(SecondarySkill id) const override;
+	int3 getMapSize() const override;
+	void getAllowedSpells(std::vector<SpellID> & out, std::optional<ui16> level);
+
+	const IGameSettings & getSettings() const override;
+	const CMapHeader * getMapHeader() const override;
+
+};
+
+VCMI_LIB_NAMESPACE_END

+ 2 - 0
mapeditor/CMakeLists.txt

@@ -48,6 +48,7 @@ set(editor_SRCS
 		campaigneditor/scenarioproperties.cpp
 		campaigneditor/startingbonus.cpp
 		campaigneditor/campaignview.cpp
+		EditorCallback.cpp
 )
 
 set(editor_HEADERS
@@ -101,6 +102,7 @@ set(editor_HEADERS
 		campaigneditor/scenarioproperties.h
 		campaigneditor/startingbonus.h
 		campaigneditor/campaignview.h
+		EditorCallback.h
 )
 
 set(editor_FORMS

+ 189 - 0
mapeditor/EditorCallback.cpp

@@ -0,0 +1,189 @@
+#include "StdInc.h"
+#include "EditorCallback.h"
+#include "../lib/mapping/CMap.h"
+
+#define THROW_EDITOR_UNSUPPORTED \
+	throw std::runtime_error(std::string("EditorCallback: ") + __func__ + " is not available in map editor")
+
+const CMap * EditorCallback::getMapConstPtr() const
+{
+	if(!map)
+		throw std::runtime_error("EditorCallback: map pointer is null");
+	return map;
+}
+
+EditorCallback::EditorCallback(const CMap * map)
+	: map(map)
+{}
+
+void EditorCallback::setMap(const CMap * map)
+{
+	this->map = map;
+}
+
+CGameState & EditorCallback::gameState()
+{
+	THROW_EDITOR_UNSUPPORTED;
+}
+
+const CGameState & EditorCallback::gameState() const
+{
+	THROW_EDITOR_UNSUPPORTED;
+}
+
+const StartInfo * EditorCallback::getStartInfo() const
+{
+	THROW_EDITOR_UNSUPPORTED;
+}
+
+int EditorCallback::getDate(Date mode) const
+{
+	THROW_EDITOR_UNSUPPORTED;
+}
+
+const TerrainTile * EditorCallback::getTile(int3, bool) const
+{
+	THROW_EDITOR_UNSUPPORTED;
+}
+
+const TerrainTile * EditorCallback::getTileUnchecked(int3) const
+{
+	THROW_EDITOR_UNSUPPORTED;
+}
+
+const CGObjectInstance * EditorCallback::getTopObj(int3) const
+{
+	THROW_EDITOR_UNSUPPORTED;
+}
+
+EDiggingStatus EditorCallback::getTileDigStatus(int3, bool) const
+{
+	THROW_EDITOR_UNSUPPORTED;
+}
+
+void EditorCallback::calculatePaths(const std::shared_ptr<PathfinderConfig> &) const
+{
+	THROW_EDITOR_UNSUPPORTED;
+}
+
+int3 EditorCallback::guardingCreaturePosition(int3) const
+{
+	THROW_EDITOR_UNSUPPORTED;
+}
+
+bool EditorCallback::checkForVisitableDir(const int3 &, const int3 &) const
+{
+	THROW_EDITOR_UNSUPPORTED;
+}
+
+std::vector<const CGObjectInstance*> EditorCallback::getGuardingCreatures(int3) const
+{
+	THROW_EDITOR_UNSUPPORTED;
+}
+
+void EditorCallback::getTilesInRange(std::unordered_set<int3> &, const int3 &, int, ETileVisibility, std::optional<PlayerColor>, int3::EDistanceFormula) const
+{
+	THROW_EDITOR_UNSUPPORTED;
+}
+
+void EditorCallback::getAllTiles(std::unordered_set<int3> &, std::optional<PlayerColor>, int, std::function<bool(const TerrainTile *)>) const
+{
+	THROW_EDITOR_UNSUPPORTED;
+}
+
+std::vector<ObjectInstanceID> EditorCallback::getVisibleTeleportObjects(std::vector<ObjectInstanceID>, PlayerColor) const
+{
+	THROW_EDITOR_UNSUPPORTED;
+}
+
+std::vector<ObjectInstanceID> EditorCallback::getTeleportChannelEntrances(TeleportChannelID, PlayerColor) const
+{
+	THROW_EDITOR_UNSUPPORTED;
+}
+
+std::vector<ObjectInstanceID> EditorCallback::getTeleportChannelExits(TeleportChannelID, PlayerColor) const
+{
+	THROW_EDITOR_UNSUPPORTED;
+}
+
+bool EditorCallback::isTeleportChannelImpassable(TeleportChannelID, PlayerColor) const
+{
+	THROW_EDITOR_UNSUPPORTED;
+}
+
+bool EditorCallback::isTeleportChannelBidirectional(TeleportChannelID, PlayerColor) const
+{
+	THROW_EDITOR_UNSUPPORTED;
+}
+
+bool EditorCallback::isTeleportChannelUnidirectional(TeleportChannelID, PlayerColor) const
+{
+	THROW_EDITOR_UNSUPPORTED;
+}
+
+bool EditorCallback::isTeleportEntrancePassable(const CGTeleport *, PlayerColor) const
+{
+	THROW_EDITOR_UNSUPPORTED;
+}
+
+bool EditorCallback::isVisibleFor(int3 pos, PlayerColor player) const
+{
+	THROW_EDITOR_UNSUPPORTED;
+}
+
+bool EditorCallback::isVisibleFor(const CGObjectInstance *obj, PlayerColor player) const
+{
+	THROW_EDITOR_UNSUPPORTED;
+}
+
+void EditorCallback::pickAllowedArtsSet(std::vector<ArtifactID> &, vstd::RNG &)
+{
+	THROW_EDITOR_UNSUPPORTED;
+}
+
+#if SCRIPTING_ENABLED
+scripting::Pool * EditorCallback::getGlobalContextPool() const
+{
+	THROW_EDITOR_UNSUPPORTED;
+}
+#endif
+
+const TeamState * EditorCallback::getTeam(TeamID) const
+{
+	THROW_EDITOR_UNSUPPORTED;
+}
+
+const TeamState * EditorCallback::getPlayerTeam(PlayerColor) const
+{
+	THROW_EDITOR_UNSUPPORTED;
+}
+
+const PlayerState * EditorCallback::getPlayerState(PlayerColor, bool) const
+{
+	THROW_EDITOR_UNSUPPORTED;
+}
+
+const PlayerSettings * EditorCallback::getPlayerSettings(PlayerColor) const
+{
+	THROW_EDITOR_UNSUPPORTED;
+}
+
+PlayerRelations EditorCallback::getPlayerRelations(PlayerColor, PlayerColor) const
+{
+	THROW_EDITOR_UNSUPPORTED;
+}
+
+int EditorCallback::getHeroCount(PlayerColor, bool) const
+{
+	THROW_EDITOR_UNSUPPORTED;
+}
+
+EPlayerStatus EditorCallback::getPlayerStatus(PlayerColor, bool) const
+{
+	THROW_EDITOR_UNSUPPORTED;
+}
+
+int EditorCallback::getResource(PlayerColor, GameResID) const
+{
+	THROW_EDITOR_UNSUPPORTED;
+}

+ 74 - 0
mapeditor/EditorCallback.h

@@ -0,0 +1,74 @@
+/*
+ * EditorCallback.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 "../lib/callback/MapInfoCallback.h"
+
+class EditorCallback : public MapInfoCallback
+{
+protected:
+	const CMap * getMapConstPtr() const override;
+
+public:
+	explicit EditorCallback(const CMap * map);
+
+	void setMap(const CMap * map);
+
+	// Access to full game state — not available in editor
+	CGameState & gameState() override;
+	const CGameState & gameState() const override;
+
+	// Unused in editor — return null or dummy
+	const StartInfo * getStartInfo() const override;
+	int getDate(Date mode) const override;
+
+	const TerrainTile * getTile(int3 tile, bool verbose) const override;
+	const TerrainTile * getTileUnchecked(int3 tile) const override;
+	const CGObjectInstance * getTopObj(int3 pos) const override;
+	EDiggingStatus getTileDigStatus(int3 tile, bool verbose) const override;
+	void calculatePaths(const std::shared_ptr<PathfinderConfig> & config) const override;
+	int3 guardingCreaturePosition(int3 pos) const override;
+	bool checkForVisitableDir(const int3 & src, const int3 & dst) const override;
+	std::vector<const CGObjectInstance*> getGuardingCreatures(int3 pos) const override;
+
+	void getTilesInRange(std::unordered_set<int3> & tiles, const int3 & pos, int radius, ETileVisibility mode, std::optional<PlayerColor> player, int3::EDistanceFormula formula) const override;
+	void getAllTiles(std::unordered_set<int3> &tiles, std::optional<PlayerColor> player, int level, std::function<bool(const TerrainTile *)> filter) const override;
+
+	std::vector<ObjectInstanceID> getVisibleTeleportObjects(std::vector<ObjectInstanceID> ids, PlayerColor player) const override;
+	std::vector<ObjectInstanceID> getTeleportChannelEntrances(TeleportChannelID id, PlayerColor player) const override;
+	std::vector<ObjectInstanceID> getTeleportChannelExits(TeleportChannelID id, PlayerColor player) const override;
+	bool isTeleportChannelImpassable(TeleportChannelID id, PlayerColor player) const override;
+	bool isTeleportChannelBidirectional(TeleportChannelID id, PlayerColor player) const override;
+	bool isTeleportChannelUnidirectional(TeleportChannelID id, PlayerColor player) const override;
+	bool isTeleportEntrancePassable(const CGTeleport * obj, PlayerColor player) const override;
+
+	bool isVisibleFor(int3 pos, PlayerColor player) const;
+	bool isVisibleFor(const CGObjectInstance * obj, PlayerColor player) const;
+
+	void pickAllowedArtsSet(std::vector<ArtifactID> & out, vstd::RNG & rand) override;
+
+// Optional scripting
+#if SCRIPTING_ENABLED
+	scripting::Pool * getGlobalContextPool() const override;
+#endif
+
+	// Player-related (stub or throw)
+	const TeamState * getTeam(TeamID teamID) const override;
+	const TeamState * getPlayerTeam(PlayerColor color) const override;
+	const PlayerState * getPlayerState(PlayerColor color, bool verbose) const override;
+	const PlayerSettings * getPlayerSettings(PlayerColor color) const override;
+	PlayerRelations getPlayerRelations(PlayerColor color1, PlayerColor color2) const override;
+	int getHeroCount(PlayerColor player, bool includeGarrisoned) const override;
+	EPlayerStatus getPlayerStatus(PlayerColor player, bool verbose) const override;
+	int getResource(PlayerColor player, GameResID which) const override;
+
+private:
+	const CMap * map;
+};

+ 7 - 2
mapeditor/helper.cpp

@@ -11,6 +11,7 @@
 #include "StdInc.h"
 #include "helper.h"
 #include "mapcontroller.h"
+#include "EditorCallback.h"
 
 #include "../lib/filesystem/Filesystem.h"
 #include "../lib/filesystem/CMemoryBuffer.h"
@@ -49,8 +50,12 @@ std::unique_ptr<CMap> Helper::openMapInternal(const QString & filenameSelect)
 		
 		if(!modList.empty())
 			throw ModIncompatibility(modList);
-		
-		return mapService.loadMap(resId, nullptr);
+
+		auto cb = std::make_shared<EditorCallback>(nullptr);
+
+		std::unique_ptr<CMap> map = mapService.loadMap(resId, cb.get());
+		cb->setMap(map.get());
+		return map;
 	}
 	else
 		throw std::runtime_error("Corrupted map");