瀏覽代碼

Merge pull request #364 from vcmi/newLogApi

Finished conversion to new logging API
* removed logger streams
* (float3|int3)::operator() -> (float3|int3)::toString(), it was too ugly and confusing.
Alexander Shishkin 8 年之前
父節點
當前提交
5067e73c30
共有 87 個文件被更改,包括 547 次插入667 次删除
  1. 1 8
      AI/VCAI/AIUtility.cpp
  2. 0 1
      AI/VCAI/AIUtility.h
  3. 7 7
      AI/VCAI/Goals.cpp
  4. 13 13
      AI/VCAI/VCAI.cpp
  5. 0 23
      Global.h
  6. 4 4
      client/CPlayerInterface.cpp
  7. 4 1
      client/Client.cpp
  8. 1 1
      client/Graphics.cpp
  9. 1 1
      client/NetPacksClient.cpp
  10. 3 3
      client/mapHandler.cpp
  11. 121 68
      include/vstd/CLoggerBase.h
  12. 1 1
      launcher/jsonutils.cpp
  13. 7 8
      lib/CArtHandler.cpp
  14. 4 4
      lib/CBonusTypeHandler.cpp
  15. 6 8
      lib/CConsoleHandler.cpp
  16. 5 5
      lib/CCreatureHandler.cpp
  17. 2 16
      lib/CCreatureSet.cpp
  18. 0 2
      lib/CCreatureSet.h
  19. 11 13
      lib/CGameInfoCallback.cpp
  20. 4 6
      lib/CGameInterface.cpp
  21. 19 24
      lib/CGameState.cpp
  22. 1 1
      lib/CHeroHandler.cpp
  23. 48 48
      lib/CModHandler.cpp
  24. 1 1
      lib/CStack.h
  25. 1 1
      lib/GameConstants.cpp
  26. 5 8
      lib/HeroBonus.cpp
  27. 2 2
      lib/IHandlerBase.h
  28. 2 2
      lib/JsonDetail.cpp
  29. 16 14
      lib/JsonNode.cpp
  30. 1 3
      lib/NetPacks.h
  31. 1 1
      lib/NetPacksBase.h
  32. 26 22
      lib/NetPacksLib.cpp
  33. 13 0
      lib/ResourceSet.cpp
  34. 4 2
      lib/ResourceSet.h
  35. 3 3
      lib/StartInfo.h
  36. 1 0
      lib/VCMI_Lib.h
  37. 3 3
      lib/battle/BattleInfo.cpp
  38. 1 1
      lib/battle/CBattleInfoCallback.cpp
  39. 7 7
      lib/battle/CBattleInfoEssentials.cpp
  40. 1 1
      lib/battle/CCallbackBase.h
  41. 1 1
      lib/filesystem/AdapterLoaders.cpp
  42. 2 2
      lib/filesystem/CFilesystemLoader.cpp
  43. 2 2
      lib/filesystem/CZipLoader.cpp
  44. 2 2
      lib/filesystem/CZipSaver.cpp
  45. 2 2
      lib/filesystem/Filesystem.cpp
  46. 2 2
      lib/filesystem/MinizipExtensions.cpp
  47. 2 11
      lib/int3.h
  48. 2 1
      lib/logging/CBasicLogConfigurator.cpp
  49. 25 31
      lib/logging/CLogger.cpp
  50. 2 68
      lib/logging/CLogger.h
  51. 13 26
      lib/mapObjects/CGHeroInstance.cpp
  52. 1 1
      lib/mapObjects/CGMarket.cpp
  53. 5 5
      lib/mapObjects/CGPandoraBox.cpp
  54. 6 6
      lib/mapObjects/CGTownInstance.cpp
  55. 1 2
      lib/mapObjects/CGTownInstance.h
  56. 10 10
      lib/mapObjects/CObjectClassesHandler.cpp
  57. 2 3
      lib/mapObjects/CObjectHandler.cpp
  58. 1 1
      lib/mapObjects/CObjectHandler.h
  59. 1 1
      lib/mapObjects/CQuest.cpp
  60. 4 4
      lib/mapObjects/CRewardableObject.cpp
  61. 0 3
      lib/mapObjects/CommonConstructors.cpp
  62. 12 12
      lib/mapObjects/MiscObjects.cpp
  63. 1 1
      lib/mapObjects/ObjectTemplate.cpp
  64. 3 3
      lib/mapping/CMap.cpp
  65. 3 8
      lib/mapping/CMapEditManager.cpp
  66. 1 1
      lib/mapping/CMapService.cpp
  67. 9 12
      lib/mapping/MapFormatH3M.cpp
  68. 4 4
      lib/mapping/MapFormatJson.cpp
  69. 3 2
      lib/rmg/CMapGenOptions.cpp
  70. 2 8
      lib/rmg/CMapGenerator.cpp
  71. 14 22
      lib/rmg/CRmgTemplateZone.cpp
  72. 5 7
      lib/rmg/CZonePlacer.cpp
  73. 7 16
      lib/rmg/float3.h
  74. 5 6
      lib/serializer/BinaryDeserializer.cpp
  75. 6 6
      lib/serializer/BinaryDeserializer.h
  76. 4 3
      lib/serializer/BinarySerializer.cpp
  77. 3 1
      lib/serializer/BinarySerializer.h
  78. 2 1
      lib/serializer/CLoadIntegrityValidator.cpp
  79. 1 1
      lib/serializer/CSerializer.h
  80. 11 11
      lib/serializer/Connection.cpp
  81. 1 1
      lib/serializer/Connection.h
  82. 1 1
      lib/serializer/JsonDeserializer.cpp
  83. 0 7
      lib/spells/CDefaultSpellMechanics.cpp
  84. 6 6
      lib/spells/CSpellHandler.cpp
  85. 4 4
      server/CGameHandler.cpp
  86. 1 1
      server/CQuery.cpp
  87. 1 1
      test/map/MapComparer.cpp

+ 1 - 8
AI/VCAI/AIUtility.cpp

@@ -171,13 +171,6 @@ void foreach_neighbour(CCallback * cbp, const int3 &pos, std::function<void(CCal
 	}
 }
 
-std::string strFromInt3(int3 pos)
-{
-	std::ostringstream oss;
-	oss << pos;
-	return oss.str();
-}
-
 bool CDistanceSorter::operator ()(const CGObjectInstance *lhs, const CGObjectInstance *rhs)
 {
 	const CGPathNode *ln = ai->myCb->getPathsInfo(hero)->getPathInfo(lhs->visitablePos()),
@@ -339,7 +332,7 @@ bool isSafeToVisit(HeroPtr h, crint3 tile)
 	{
 		if(heroStrength / SAFE_ATTACK_CONSTANT > dangerStrength)
 		{
-			logAi->trace("It's safe for %s to visit tile %s", h->name, tile());
+			logAi->trace("It's safe for %s to visit tile %s", h->name, tile.toString());
 			return true;
 		}
 		else

+ 0 - 1
AI/VCAI/AIUtility.h

@@ -135,7 +135,6 @@ bool objWithID(const CGObjectInstance *obj)
 	return obj->ID == id;
 }
 
-std::string strFromInt3(int3 pos);//todo: remove
 void foreach_tile_pos(std::function<void(const int3& pos)> foo);
 void foreach_tile_pos(CCallback * cbp, std::function<void(CCallback * cbp, const int3& pos)> foo); // avoid costly retrieval of thread-specific pointer
 void foreach_neighbour(const int3 &pos, std::function<void(const int3& pos)> foo);

+ 7 - 7
AI/VCAI/Goals.cpp

@@ -83,13 +83,13 @@ std::string Goals::AbstractGoal::name() const //TODO: virtualize
 		case ISSUE_COMMAND:
 			return "ISSUE COMMAND (unsupported)";
 		case VISIT_TILE:
-			desc = "VISIT TILE " + tile();
+			desc = "VISIT TILE " + tile.toString();
 			break;
 		case CLEAR_WAY_TO:
-			desc = "CLEAR WAY TO " + tile();
+			desc = "CLEAR WAY TO " + tile.toString();
 			break;
 		case DIG_AT_TILE:
-			desc = "DIG AT TILE " + tile();
+			desc = "DIG AT TILE " + tile.toString();
 			break;
 		default:
 			return boost::lexical_cast<std::string>(goalType);
@@ -447,7 +447,7 @@ bool VisitHero::fulfillsMe (TSubgoal goal)
 	auto obj = cb->getObj(ObjectInstanceID(objid));
 	if (!obj)
 	{
-		logAi->error("Hero %s: VisitHero::fulfillsMe at %s: object %d not found", hero.name, goal->tile, objid);
+		logAi->error("Hero %s: VisitHero::fulfillsMe at %s: object %d not found", hero.name, goal->tile.toString(), objid);
 		return false;
 	}
 	return obj->visitablePos() == goal->tile;
@@ -529,7 +529,7 @@ TGoalVec ClearWayTo::getAllPossibleSubgoals()
 				else
 				{
 					//TODO: we should be able to return apriopriate quest here (VCAI::striveToQuest)
-					logAi->debug("Quest guard blocks the way to %s", tile());
+					logAi->debug("Quest guard blocks the way to %s", tile.toString());
 					continue; //do not access quets guard if we can't complete the quest
 				}
 			}
@@ -549,7 +549,7 @@ TGoalVec ClearWayTo::getAllPossibleSubgoals()
 
 	if (ret.empty())
 	{
-		logAi->warn("There is no known way to clear the way to tile %s",tile());
+		logAi->warn("There is no known way to clear the way to tile %s", tile.toString());
 		throw goalFulfilledException (sptr(Goals::ClearWayTo(tile))); //make sure asigned hero gets unlocked
 	}
 
@@ -712,7 +712,7 @@ TSubgoal RecruitHero::whatToDoToAchieve()
 
 std::string VisitTile::completeMessage() const
 {
-	return "Hero " + hero.get()->name + " visited tile " + tile();
+	return "Hero " + hero.get()->name + " visited tile " + tile.toString();
 }
 
 TSubgoal VisitTile::whatToDoToAchieve()

+ 13 - 13
AI/VCAI/VCAI.cpp

@@ -127,7 +127,7 @@ void VCAI::heroMoved(const TryMoveHero & details)
 				{
 					knownSubterraneanGates[o1] = o2;
 					knownSubterraneanGates[o2] = o1;
-					logAi->debug("Found a pair of subterranean gates between %s and %s!", from(), to());
+					logAi->debug("Found a pair of subterranean gates between %s and %s!", from.toString(), to.toString());
 				}
 			}
 		}
@@ -889,7 +889,7 @@ bool VCAI::goVisitObj(const CGObjectInstance * obj, HeroPtr h)
 {
 	int3 dst = obj->visitablePos();
 	auto sm = getCachedSectorMap(h);
-	logAi->debug("%s will try to visit %s at (%s)",h->name, obj->getObjectName(), dst());
+	logAi->debug("%s will try to visit %s at (%s)",h->name, obj->getObjectName(), dst.toString());
 	int3 pos = sm->firstTileToGet(h, dst);
 	if (!pos.valid()) //rare case when we are already standing on one of potential objects
 		return false;
@@ -898,7 +898,7 @@ bool VCAI::goVisitObj(const CGObjectInstance * obj, HeroPtr h)
 
 void VCAI::performObjectInteraction(const CGObjectInstance * obj, HeroPtr h)
 {
-	LOG_TRACE_PARAMS(logAi, "Hero %s and object %s at %s", h->name % obj->getObjectName() % obj->pos);
+	LOG_TRACE_PARAMS(logAi, "Hero %s and object %s at %s", h->name % obj->getObjectName() % obj->pos.toString());
 	switch (obj->ID)
 	{
 		case Obj::CREATURE_GENERATOR1:
@@ -1202,7 +1202,7 @@ bool VCAI::tryBuildStructure(const CGTownInstance * t, BuildingID building, unsi
 		{
 			if(!containsSavedRes(b->resources))
 			{
-				logAi->debug("Player %d will build %s in town of %s at %s", playerID, b->Name(), t->name, t->pos());
+				logAi->debug("Player %d will build %s in town of %s at %s", playerID, b->Name(), t->name, t->pos.toString());
 				cb->buildBuilding(t, buildID);
 				return true;
 			}
@@ -1283,7 +1283,7 @@ bool VCAI::tryBuildStructure(const CGTownInstance * t, BuildingID building, unsi
 //		{
 //			if(!containsSavedRes(b->resources))
 //			{
-//				logAi->debug("Player %d will build %s in town of %s at %s", playerID, b->Name(), t->name, t->pos());
+//				logAi->debug("Player %d will build %s in town of %s at %s", playerID, b->Name(), t->name, t->pos.toString());
 //				return true;
 //			}
 //			continue;
@@ -1573,7 +1573,7 @@ void VCAI::wander(HeroPtr h)
 				boost::sort(townsNotReachable, compareReinforcements);
 				//TODO pick the truly best
 				const CGTownInstance *t = townsNotReachable.back();
-				logAi->debug("%s can't reach any town, we'll try to make our way to %s at %s",h->name,t->name, t->visitablePos()());
+				logAi->debug("%s can't reach any town, we'll try to make our way to %s at %s",h->name,t->name, t->visitablePos().toString());
 				int3 pos1 = h->pos;
 				striveToGoal(sptr(Goals::ClearWayTo(t->visitablePos()).sethero(h)));
 				//if out hero is stuck, we may need to request another hero to clear the way we see
@@ -1687,7 +1687,7 @@ void VCAI::battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int
 	assert(playerID > PlayerColor::PLAYER_LIMIT || status.getBattle() == UPCOMING_BATTLE);
 	status.setBattle(ONGOING_BATTLE);
 	const CGObjectInstance *presumedEnemy = vstd::backOrNull(cb->getVisitableObjs(tile)); //may be nullptr in some very are cases -> eg. visited monolith and fighting with an enemy at the FoW covered exit
-	battlename = boost::str(boost::format("Starting battle of %s attacking %s at %s") % (hero1 ? hero1->name : "a army") % (presumedEnemy ? presumedEnemy->getObjectName() : "unknown enemy") % tile);
+	battlename = boost::str(boost::format("Starting battle of %s attacking %s at %s") % (hero1 ? hero1->name : "a army") % (presumedEnemy ? presumedEnemy->getObjectName() : "unknown enemy") % tile.toString());
 	CAdventureAI::battleStart(army1, army2, tile, hero1, hero2, side);
 }
 
@@ -1907,7 +1907,7 @@ bool VCAI::moveHeroToTile(int3 dst, HeroPtr h)
 		}
 	};
 
-	logAi->debug("Moving hero %s to tile %s", h->name, dst());
+	logAi->debug("Moving hero %s to tile %s", h->name, dst.toString());
 	int3 startHpos = h->visitablePos();
 	bool ret = false;
 	if(startHpos == dst)
@@ -1925,7 +1925,7 @@ bool VCAI::moveHeroToTile(int3 dst, HeroPtr h)
 		cb->getPathsInfo(h.get())->getPath(path, dst);
 		if(path.nodes.empty())
 		{
-			logAi->error("Hero %s cannot reach %s.", h->name, dst());
+			logAi->error("Hero %s cannot reach %s.", h->name, dst.toString());
 			throw goalFulfilledException (sptr(Goals::VisitTile(dst).sethero(h)));
 		}
 		int i = path.nodes.size()-1;
@@ -2068,7 +2068,7 @@ bool VCAI::moveHeroToTile(int3 dst, HeroPtr h)
 			throw cannotFulfillGoalException("Invalid path found!"); //FIXME: should never happen
 		}
 		evaluateGoal(h); //new hero position means new game situation
-		logAi->debug("Hero %s moved from %s to %s. Returning %d.", h->name, startHpos(), h->visitablePos()(), ret);
+		logAi->debug("Hero %s moved from %s to %s. Returning %d.", h->name, startHpos.toString(), h->visitablePos().toString(), ret);
 	}
 	return ret;
 }
@@ -2093,7 +2093,7 @@ void VCAI::tryRealize(Goals::VisitTile & g)
 		throw cannotFulfillGoalException("Cannot visit tile: hero is out of MPs!");
 	if(g.tile == g.hero->visitablePos()  &&  cb->getVisitableObjs(g.hero->visitablePos()).size() < 2)
 	{
-		logAi->warn("Why do I want to move hero %s to tile %s? Already standing on that tile! ", g.hero->name, g.tile());
+		logAi->warn("Why do I want to move hero %s to tile %s? Already standing on that tile! ", g.hero->name, g.tile.toString());
 		throw goalFulfilledException (sptr(g));
 	}
 	if (ai->moveHeroToTile(g.tile, g.hero.get()))
@@ -2290,7 +2290,7 @@ void VCAI::endTurn()
 	{
 		logAi->error("Not having turn at the end of turn???");
 	}
-	logAi->debugStream() << "Resources at the end of turn: " << cb->getResourceAmount();
+	logAi->debug("Resources at the end of turn: %s", cb->getResourceAmount().toString());
 
 	do
 	{
@@ -2771,7 +2771,7 @@ void VCAI::checkHeroArmy (HeroPtr h)
 
 void VCAI::recruitHero(const CGTownInstance * t, bool throwing)
 {
-	logAi->debug("Trying to recruit a hero in %s at %s", t->name, t->visitablePos());
+	logAi->debug("Trying to recruit a hero in %s at %s", t->name, t->visitablePos().toString());
 
 	auto heroes = cb->getAvailableHeroes(t);
 	if(heroes.size())

+ 0 - 23
Global.h

@@ -184,9 +184,6 @@ static_assert(sizeof(bool) == 1, "Bool needs to be 1 byte in size.");
 #include <boost/variant.hpp>
 #include <boost/math/special_functions/round.hpp>
 #include <boost/multi_array.hpp>
-#include <boost/uuid/uuid.hpp>
-#include <boost/uuid/uuid_io.hpp>
-#include <boost/uuid/uuid_generators.hpp>
 
 #ifndef M_PI
 #  define M_PI 3.14159265358979323846
@@ -255,7 +252,6 @@ template<typename T, size_t N> char (&_ArrayCountObj(const T (&)[N]))[N];
 /* VCMI standard library */
 /* ---------------------------------------------------------------------------- */
 #include <vstd/CLoggerBase.h>
-#include "lib/logging/CLogger.h" //todo: remove
 
 void inline handleException()
 {
@@ -277,25 +273,6 @@ void inline handleException()
 	}
 }
 
-template<typename T>
-std::ostream & operator<<(std::ostream & out, const boost::optional<T> & opt)
-{
-	if(opt) return out << *opt;
-	else return out << "empty";
-}
-
-template<typename T>
-std::ostream & operator<<(std::ostream & out, const std::vector<T> & container)
-{
-	out << "[";
-	for(auto it = container.begin(); it != container.end(); ++it)
-	{
-		out << *it;
-		if(std::prev(container.end()) != it) out << ", ";
-	}
-	return out << "]";
-}
-
 namespace vstd
 {
 

+ 4 - 4
client/CPlayerInterface.cpp

@@ -110,7 +110,7 @@ struct HeroObjectRetriever : boost::static_visitor<const CGHeroInstance *>
 
 CPlayerInterface::CPlayerInterface(PlayerColor Player)
 {
-	logGlobal->trace("\tHuman player interface for player %s being constructed", Player.getStr(false));
+	logGlobal->trace("\tHuman player interface for player %s being constructed", Player.getStr());
 	destinationTeleport = ObjectInstanceID();
 	destinationTeleportPos = int3(-1);
 	howManyPeople++;
@@ -136,7 +136,7 @@ CPlayerInterface::CPlayerInterface(PlayerColor Player)
 
 CPlayerInterface::~CPlayerInterface()
 {
-	logGlobal->trace("\tHuman player interface for player %s being destructed", playerID.getStr(false));
+	logGlobal->trace("\tHuman player interface for player %s being destructed", playerID.getStr());
 	//howManyPeople--;
 	delete showingDialog;
 	delete cingconsole;
@@ -1376,7 +1376,7 @@ template <typename Handler> void CPlayerInterface::serializeTempl( Handler &h, c
 				CGPath path;
 				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 , path.nodes.size());
+				logGlobal->trace("Restored path for hero %s leading to %s with %d nodes", p.first->nodeName(), p.second.toString(), path.nodes.size());
 			}
 	}
 
@@ -2857,7 +2857,7 @@ void CPlayerInterface::doMoveHero(const CGHeroInstance * h, CGPath path)
 
 			assert(h->pos.z == nextCoord.z); // Z should change only if it's movement via teleporter and in this case this code shouldn't be executed at all
 			int3 endpos(nextCoord.x, nextCoord.y, h->pos.z);
-			logGlobal->trace("Requesting hero movement to %s", endpos());
+			logGlobal->trace("Requesting hero movement to %s", endpos.toString());
 
 			bool useTransit = false;
 			if ((i-2 >= 0) // Check there is node after next one; otherwise transit is pointless

+ 4 - 1
client/Client.cpp

@@ -11,6 +11,9 @@
 #include "Client.h"
 
 #include <SDL.h>
+#include <boost/uuid/uuid.hpp>
+#include <boost/uuid/uuid_io.hpp>
+#include <boost/uuid/uuid_generators.hpp>
 
 #include "CMusicHandler.h"
 #include "../lib/mapping/CCampaignHandler.h"
@@ -454,7 +457,7 @@ void CClient::newGame( CConnection *con, StartInfo *si )
 		if(!vstd::contains(myPlayers, color))
 			continue;
 
-		logNetwork->trace("Preparing interface for player %s", color.getStr(false));
+		logNetwork->trace("Preparing interface for player %s", color.getStr());
 		if(elem.second.playerID == PlayerSettings::PLAYER_AI)
 		{
 			auto AiToGive = aiNameForPlayer(elem.second, false);

+ 1 - 1
client/Graphics.cpp

@@ -291,7 +291,7 @@ void Graphics::blueToPlayersAdv(SDL_Surface * sur, PlayerColor player)
 		}
 		else
 		{
-			logGlobal->error("Wrong player id in blueToPlayersAdv (%s)!", player.getStr(false));
+			logGlobal->error("Wrong player id in blueToPlayersAdv (%s)!", player.getStr());
 			return;
 		}
 		SDL_SetColors(sur, palette, 224, 32);

+ 1 - 1
client/NetPacksClient.cpp

@@ -819,7 +819,7 @@ void SaveGame::applyCl(CClient *cl)
 
 void PlayerMessage::applyCl(CClient *cl)
 {
-	logNetwork->debug("Player %s sends a message: %s", player.getStr(false), text);
+	logNetwork->debug("Player %s sends a message: %s", player.getStr(), text);
 
 	std::ostringstream str;
 	if(player.isSpectator())

+ 3 - 3
client/mapHandler.cpp

@@ -967,7 +967,7 @@ CMapHandler::AnimBitmapHolder CMapHandler::CMapBlitter::findHeroBitmap(const CGH
 	{
 		if(hero->tempOwner >= PlayerColor::PLAYER_LIMIT) //Neutral hero?
 		{
-			logGlobal->error("A neutral hero (%s) at %s. Should not happen!", hero->name, hero->pos());
+			logGlobal->error("A neutral hero (%s) at %s. Should not happen!", hero->name, hero->pos.toString());
 			return CMapHandler::AnimBitmapHolder();
 		}
 
@@ -1138,7 +1138,7 @@ bool CMapHandler::updateObjectsFade()
 			{
 				if ((*objIter).fadeAnimKey == (*iter).first)
 				{
-					logAnim->trace("Fade anim finished for obj at %s; remaining: %d", pos(), fadeAnims.size() - 1);
+					logAnim->trace("Fade anim finished for obj at %s; remaining: %d", pos.toString(), fadeAnims.size() - 1);
 					if (anim->fadingMode == CFadeAnimation::EMode::OUT)
 						objs.erase(objIter); // if this was fadeout, remove the object from the map
 					else
@@ -1185,7 +1185,7 @@ bool CMapHandler::startObjectFade(TerrainTileObject & obj, bool in, int3 pos)
 		fadeAnims[++fadeAnimCounter] = std::pair<int3, CFadeAnimation*>(pos, anim);
 		obj.fadeAnimKey = fadeAnimCounter;
 
-		logAnim->trace("Fade anim started for obj %d at %s; anim count: %d", obj.obj->ID, pos(), fadeAnims.size());
+		logAnim->trace("Fade anim started for obj %d at %s; anim count: %d", obj.obj->ID, pos.toString(), fadeAnims.size());
 		return true;
 	}
 

+ 121 - 68
include/vstd/CLoggerBase.h

@@ -49,91 +49,144 @@ namespace ELogLevel
 
 namespace vstd
 {
-	class DLL_LINKAGE CLoggerBase
-	{
-	public:
-		virtual ~CLoggerBase(){};
+class DLL_LINKAGE CLoggerBase
+{
+public:
+	virtual ~CLoggerBase();
 
-		virtual void log(ELogLevel::ELogLevel level, const std::string & message) const = 0;
-		virtual void log(ELogLevel::ELogLevel level, const boost::format & fmt) const = 0;
+	virtual void log(ELogLevel::ELogLevel level, const std::string & message) const = 0;
+	virtual void log(ELogLevel::ELogLevel level, const boost::format & fmt) const = 0;
 
-		template<typename T, typename ... Args>
-		void log(ELogLevel::ELogLevel level, const std::string & format, T t, Args ... args) const
+	/// Returns true if a debug/trace log message will be logged, false if not.
+	/// Useful if performance is important and concatenating the log message is a expensive task.
+	virtual bool isDebugEnabled() const = 0;
+	virtual bool isTraceEnabled() const = 0;
+
+	template<typename T, typename ... Args>
+	void log(ELogLevel::ELogLevel level, const std::string & format, T t, Args ... args) const
+	{
+		try
 		{
 			boost::format fmt(format);
 			makeFormat(fmt, t, args...);
 			log(level, fmt);
 		}
-
-		/// Log methods for various log levels
-		inline void error(const std::string & message) const
-		{
-			log(ELogLevel::ERROR, message);
-		};
-
-		template<typename T, typename ... Args>
-		void error(const std::string & format, T t, Args ... args) const
+		catch(...)
 		{
-			log(ELogLevel::ERROR, format, t, args...);
+			log(ELogLevel::ERROR, "Log formatting failed, format was:");
+			log(ELogLevel::ERROR, format);
 		}
+	}
 
-		inline void warn(const std::string & message) const
-		{
-			log(ELogLevel::WARN, message);
-		};
-
-		template<typename T, typename ... Args>
-		void warn(const std::string & format, T t, Args ... args) const
-		{
-			log(ELogLevel::WARN, format, t, args...);
-		}
+	/// Log methods for various log levels
+	inline void error(const std::string & message) const
+	{
+		log(ELogLevel::ERROR, message);
+	};
 
-		inline void info(const std::string & message) const
-		{
-			log(ELogLevel::INFO, message);
-		};
+	template<typename T, typename ... Args>
+	void error(const std::string & format, T t, Args ... args) const
+	{
+		log(ELogLevel::ERROR, format, t, args...);
+	}
 
-		template<typename T, typename ... Args>
-		void info(const std::string & format, T t, Args ... args) const
-		{
-			log(ELogLevel::INFO, format, t, args...);
-		}
+	inline void warn(const std::string & message) const
+	{
+		log(ELogLevel::WARN, message);
+	};
 
-		inline void debug(const std::string & message) const
-		{
-			log(ELogLevel::DEBUG, message);
-		};
+	template<typename T, typename ... Args>
+	void warn(const std::string & format, T t, Args ... args) const
+	{
+		log(ELogLevel::WARN, format, t, args...);
+	}
 
+	inline void info(const std::string & message) const
+	{
+		log(ELogLevel::INFO, message);
+	};
 
-		template<typename T, typename ... Args>
-		void debug(const std::string & format, T t, Args ... args) const
-		{
-			log(ELogLevel::DEBUG, format, t, args...);
-		}
+	template<typename T, typename ... Args>
+	void info(const std::string & format, T t, Args ... args) const
+	{
+		log(ELogLevel::INFO, format, t, args...);
+	}
 
-		inline void trace(const std::string & message) const
-		{
-			log(ELogLevel::TRACE, message);
-		};
+	inline void debug(const std::string & message) const
+	{
+		log(ELogLevel::DEBUG, message);
+	};
 
-		template<typename T, typename ... Args>
-		void trace(const std::string & format, T t, Args ... args) const
-		{
-			log(ELogLevel::TRACE, format, t, args...);
-		}
 
-	private:
-		template <typename T>
-		void makeFormat(boost::format & fmt, T t) const
-		{
-			fmt % t;
-		}
+	template<typename T, typename ... Args>
+	void debug(const std::string & format, T t, Args ... args) const
+	{
+		log(ELogLevel::DEBUG, format, t, args...);
+	}
 
-		template <typename T, typename ... Args>
-		void makeFormat(boost::format & fmt, T t, Args ... args) const
-		{
-			fmt % t;
-			makeFormat(fmt, args...);
-		}
+	inline void trace(const std::string & message) const
+	{
+		log(ELogLevel::TRACE, message);
 	};
-}
+
+	template<typename T, typename ... Args>
+	void trace(const std::string & format, T t, Args ... args) const
+	{
+		log(ELogLevel::TRACE, format, t, args...);
+	}
+
+private:
+	template <typename T>
+	void makeFormat(boost::format & fmt, T t) const
+	{
+		fmt % t;
+	}
+
+	template <typename T, typename ... Args>
+	void makeFormat(boost::format & fmt, T t, Args ... args) const
+	{
+		fmt % t;
+		makeFormat(fmt, args...);
+	}
+};
+
+/// RAII class for tracing the program execution.
+/// It prints "Leaving function XYZ" automatically when the object gets destructed.
+class DLL_LINKAGE CTraceLogger
+{
+public:
+	CTraceLogger(const CLoggerBase * logger, const std::string & beginMessage, const std::string & endMessage);
+	CTraceLogger(const CTraceLogger & other) = delete;
+	~CTraceLogger();
+
+private:
+	const CLoggerBase * logger;
+	std::string endMessage;
+};
+
+}//namespace vstd
+
+
+/// Macros for tracing the control flow of the application conveniently. If the LOG_TRACE macro is used it should be
+/// the first statement in the function. Logging traces via this macro have almost no impact when the trace is disabled.
+///
+#define RAII_TRACE(logger, onEntry, onLeave)			\
+	std::unique_ptr<vstd::CTraceLogger> ctl00;						\
+	if(logger->isTraceEnabled())						\
+		ctl00 = make_unique<vstd::CTraceLogger>(logger, onEntry, onLeave);
+
+#define LOG_TRACE(logger) RAII_TRACE(logger,								\
+		boost::str(boost::format("Entering %s.") % BOOST_CURRENT_FUNCTION),	\
+		boost::str(boost::format("Leaving %s.") % BOOST_CURRENT_FUNCTION))
+
+
+#define LOG_TRACE_PARAMS(logger, formatStr, params) RAII_TRACE(logger,		\
+		boost::str(boost::format("Entering %s: " + std::string(formatStr) + ".") % BOOST_CURRENT_FUNCTION % params), \
+		boost::str(boost::format("Leaving %s.") % BOOST_CURRENT_FUNCTION))
+
+
+extern DLL_LINKAGE vstd::CLoggerBase * logGlobal;
+extern DLL_LINKAGE vstd::CLoggerBase * logBonus;
+extern DLL_LINKAGE vstd::CLoggerBase * logNetwork;
+extern DLL_LINKAGE vstd::CLoggerBase * logAi;
+extern DLL_LINKAGE vstd::CLoggerBase * logAnim;

+ 1 - 1
launcher/jsonutils.cpp

@@ -76,7 +76,7 @@ QVariant JsonFromFile(QString filename)
 
 	if (data.size() == 0)
 	{
-		logGlobal->errorStream() << "Failed to open file " << filename.toUtf8().data();
+		logGlobal->error("Failed to open file %s", filename.toUtf8().data());
 		return QVariant();
 	}
 	else

+ 7 - 8
lib/CArtHandler.cpp

@@ -360,7 +360,7 @@ ArtifactPosition CArtHandler::stringToSlot(std::string slotName)
 	if (it != artifactPositionMap.end())
 		return it->second;
 
-	logGlobal->warnStream() << "Warning! Artifact slot " << slotName << " not recognized!";
+	logGlobal->warn("Warning! Artifact slot %s not recognized!", slotName);
 	return ArtifactPosition::PRE_FIRST;
 }
 
@@ -421,7 +421,7 @@ CArtifact::EartClass CArtHandler::stringToClass(std::string className)
 	if (it != artifactClassMap.end())
 		return it->second;
 
-	logGlobal->warnStream() << "Warning! Artifact rarity " << className << " not recognized!";
+	logGlobal->warn("Warning! Artifact rarity %s not recognized!", className);
 	return CArtifact::ART_SPECIAL;
 }
 
@@ -455,7 +455,7 @@ void CArtHandler::loadType(CArtifact * art, const JsonNode & node)
 			}
 		}
 		else
-			logGlobal->warnStream() << "Warning! Artifact type " << b.String() << " not recognized!";
+			logGlobal->warn("Warning! Artifact type %s not recognized!", b.String());
 	}
 }
 
@@ -679,11 +679,11 @@ void CArtHandler::erasePickedArt(ArtifactID id)
 			artifactList->erase(itr);
 		}
 		else
-			logGlobal->warnStream() << "Problem: cannot erase artifact " << art->Name() << " from list, it was not present";
+			logGlobal->warn("Problem: cannot erase artifact %s from list, it was not present", art->Name());
 
 	}
 	else
-		logGlobal->warnStream() << "Problem: cannot find list for artifact " << art->Name() << ", strange class. (special?)";
+		logGlobal->warn("Problem: cannot find list for artifact %s, strange class. (special?)", art->Name());
 }
 
 boost::optional<std::vector<CArtifact*>&> CArtHandler::listFromClass( CArtifact::EartClass artifactClass )
@@ -869,8 +869,7 @@ bool CArtifactInstance::canBePutAt(const CArtifactSet *artSet, ArtifactPosition
  	auto possibleSlots = artType->possibleSlots.find(artSet->bearerType());
  	if(possibleSlots == artType->possibleSlots.end())
  	{
-		logGlobal->warnStream() << "Warning: artifact " << artType->Name() << " doesn't have defined allowed slots for bearer of type "
-			<< artSet->bearerType();
+		logGlobal->warn("Warning: artifact %s doesn't have defined allowed slots for bearer of type %s", artType->Name(), artSet->bearerType());
 		return false;
 	}
 
@@ -1008,7 +1007,7 @@ SpellID CArtifactInstance::getGivenSpellID() const
 	const auto b = getBonusLocalFirst(Selector::type(Bonus::SPELL));
 	if(!b)
 	{
-		logGlobal->warnStream() << "Warning: " << nodeName() << " doesn't bear any spell!";
+		logGlobal->warn("Warning: %s doesn't bear any spell!", nodeName());
 		return SpellID::NONE;
 	}
 	return SpellID(b->subtype);

+ 4 - 4
lib/CBonusTypeHandler.cpp

@@ -47,7 +47,7 @@ MacroString::MacroString(const std::string & format)
 
 			if(end_pos == std::string::npos)
 			{
-				logBonus->warnStream() << "Format error in: " << format;
+				logBonus->warn("Format error in: %s", format);
 				end_pos = start_pos;
 				break;
 			}
@@ -154,7 +154,7 @@ std::string CBonusTypeHandler::bonusToString(const std::shared_ptr<Bonus> & bonu
 		}
 		else
 		{
-			 logBonus->warnStream() << "Unknown macro in bonus config: " << name;
+			 logBonus->warn("Unknown macro in bonus config: %s", name);
 			 return "[error]";
 		}
 	};
@@ -300,14 +300,14 @@ void CBonusTypeHandler::load(const JsonNode & config)
 //
 //			bonusTypes.push_back(bt);
 
-			logBonus->warnStream() << "Adding new bonuses not implemented (" << node.first << ")";
+			logBonus->warn("Adding new bonuses not implemented (%s)", node.first);
 		}
 		else
 		{
 			CBonusType & bt = bonusTypes[it->second];
 
 			loadItem(node.second, bt);
-			logBonus->traceStream() << "Loaded bonus type " << node.first;
+			logBonus->trace("Loaded bonus type %s", node.first);
 		}
 	}
 }

+ 6 - 8
lib/CConsoleHandler.cpp

@@ -59,13 +59,13 @@ void printWinError()
 		logGlobal->error("No Win error information set.");
 		return;
 	}
-	logGlobal->errorStream() << "Error " << error << " encountered:";
+	logGlobal->error("Error %d encountered:", error);
 
 	//Get error description
 	char* pTemp = nullptr;
 	FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
 		nullptr, error,  MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), (LPSTR)&pTemp, 1, nullptr);
-	logGlobal->errorStream() << pTemp;
+	logGlobal->error(pTemp);
 	LocalFree( pTemp );
 }
 
@@ -109,16 +109,14 @@ LONG WINAPI onUnhandledException(EXCEPTION_POINTERS* exception)
 	logGlobal->error("Disaster happened.");
 
 	PEXCEPTION_RECORD einfo = exception->ExceptionRecord;
-	logGlobal->errorStream() << "Reason: 0x" << std::hex << einfo->ExceptionCode << " - " << exceptionName(einfo->ExceptionCode)
-		<< " at " << std::setfill('0') << std::setw(4) << exception->ContextRecord->SegCs << ":" << (void*)einfo->ExceptionAddress;
+	logGlobal->error("Reason: 0x%x - %s at %04x:%x", einfo->ExceptionCode, exceptionName(einfo->ExceptionCode), exception->ContextRecord->SegCs, (void*)einfo->ExceptionAddress);
 
 	if (einfo->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
 	{
-		logGlobal->errorStream() << "Attempt to " << (einfo->ExceptionInformation[0] == 1 ? "write to " : "read from ")
-			<< "0x" <<  std::setw(8) << (void*)einfo->ExceptionInformation[1];
+		logGlobal->error("Attempt to %s 0x%8x", (einfo->ExceptionInformation[0] == 1 ? "write to" : "read from"), (void*)einfo->ExceptionInformation[1]);
 	}
 	const DWORD threadId = ::GetCurrentThreadId();
-	logGlobal->errorStream() << "Thread ID: " << threadId << " [" << std::dec << std::setw(0) << threadId << "]";
+	logGlobal->error("Thread ID: %d", threadId);
 
 	//exception info to be placed in the dump
 	MINIDUMP_EXCEPTION_INFORMATION meinfo = {threadId, exception, TRUE};
@@ -136,7 +134,7 @@ LONG WINAPI onUnhandledException(EXCEPTION_POINTERS* exception)
 
 	strcat(mname, "_crashinfo.dmp");
 	HANDLE dfile = CreateFileA(mname, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_WRITE|FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0);
-	logGlobal->errorStream() << "Crash info will be put in " << mname;
+	logGlobal->error("Crash info will be put in %s", mname);
 	MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), dfile, MiniDumpWithDataSegs, &meinfo, 0, 0);
 	MessageBoxA(0, "VCMI has crashed. We are sorry. File with information about encountered problem has been created.", "VCMI Crashhandler", MB_OK | MB_ICONERROR);
 	return EXCEPTION_EXECUTE_HANDLER;

+ 5 - 5
lib/CCreatureHandler.cpp

@@ -189,7 +189,7 @@ static void AddAbility(CCreature *cre, const JsonVector &ability_vec)
 			cre->addBonus(-1, Bonus::LUCK);
 			cre->getBonusList().back()->effectRange = Bonus::ONLY_ENEMY_ARMY;
 		} else
-			logGlobal->errorStream() << "Error: invalid ability type " << type << " in creatures config";
+			logGlobal->error("Error: invalid ability type %s in creatures config", type);
 
 		return;
 	}
@@ -937,7 +937,7 @@ void CCreatureHandler::loadStackExp(Bonus & b, BonusList & bl, CLegacyConfigPars
 			case 'U':
 				b.type = Bonus::UNDEAD; break;
 			default:
-				logGlobal->traceStream() << "Not parsed bonus " << buf << mod;
+				logGlobal->trace("Not parsed bonus %s %s", buf, mod);
 				return;
 				break;
 		}
@@ -1047,7 +1047,7 @@ void CCreatureHandler::loadStackExp(Bonus & b, BonusList & bl, CLegacyConfigPars
 				b.type = Bonus::MIND_IMMUNITY;
 				break;
 			default:
-				logGlobal->traceStream() << "Not parsed bonus " << buf << mod;
+				logGlobal->trace("Not parsed bonus %s %s", buf, mod);
 				return;
 		}
 		break;
@@ -1088,7 +1088,7 @@ void CCreatureHandler::loadStackExp(Bonus & b, BonusList & bl, CLegacyConfigPars
 		b.valType = Bonus::INDEPENDENT_MAX;
 		break;
 	default:
-		logGlobal->traceStream() << "Not parsed bonus " << buf << mod;
+		logGlobal->trace("Not parsed bonus %s %s", buf, mod);
 		return;
 		break;
 	}
@@ -1186,7 +1186,7 @@ CreatureID CCreatureHandler::pickRandomMonster(CRandomGenerator & rand, int tier
 
 		if(!allowed.size())
 		{
-			logGlobal->warnStream() << "Cannot pick a random creature of tier " << tier << "!";
+			logGlobal->warn("Cannot pick a random creature of tier %d!", tier);
 			return CreatureID::NONE;
 		}
 

+ 2 - 16
lib/CCreatureSet.cpp

@@ -45,7 +45,7 @@ bool CCreatureSet::setCreature(SlotID slot, CreatureID type, TQuantity quantity)
 {
 	if(!slot.validSlot())
 	{
-		logGlobal->errorStream() << "Cannot set slot " << slot;
+		logGlobal->error("Cannot set slot %d", slot.getNum());
 		return false;
 	}
 	if(!quantity)
@@ -189,7 +189,7 @@ void CCreatureSet::addToSlot(SlotID slot, CStackInstance *stack, bool allowMergi
 	}
 	else
 	{
-		logGlobal->errorStream() << "Cannot add to slot " << slot << " stack " << *stack;
+		logGlobal->error("Cannot add to slot %d stack %s", slot.getNum(), stack->nodeName());
 	}
 }
 
@@ -906,20 +906,6 @@ void CStackBasicDescriptor::serializeJson(JsonSerializeFormat & handler)
 	}
 }
 
-DLL_LINKAGE std::ostream & operator<<(std::ostream & str, const CStackInstance & sth)
-{
-	if(!sth.valid(true))
-		str << "an invalid stack!";
-
-	str << "stack with " << sth.count << " of ";
-	if(sth.type)
-		str << sth.type->namePl;
-	else
-		str << sth.idRand;
-
-	return str;
-}
-
 void CSimpleArmy::clear()
 {
 	army.clear();

+ 0 - 2
lib/CCreatureSet.h

@@ -134,8 +134,6 @@ public:
 	}
 };
 
-DLL_LINKAGE std::ostream & operator<<(std::ostream & str, const CStackInstance & sth);
-
 typedef std::map<SlotID, CStackInstance*> TSlots;
 typedef std::map<SlotID, CStackBasicDescriptor> TSimpleSlots;
 

+ 11 - 13
lib/CGameInfoCallback.cpp

@@ -22,9 +22,9 @@
 #include "CPlayerState.h"
 
 //TODO make clean
-#define ERROR_VERBOSE_OR_NOT_RET_VAL_IF(cond, verbose, txt, retVal) do {if(cond){if(verbose)logGlobal->errorStream() << BOOST_CURRENT_FUNCTION << ": " << txt; return retVal;}} while(0)
-#define ERROR_RET_IF(cond, txt) do {if(cond){logGlobal->errorStream() << BOOST_CURRENT_FUNCTION << ": " << txt; return;}} while(0)
-#define ERROR_RET_VAL_IF(cond, txt, retVal) do {if(cond){logGlobal->errorStream() << BOOST_CURRENT_FUNCTION << ": " << txt; return retVal;}} while(0)
+#define ERROR_VERBOSE_OR_NOT_RET_VAL_IF(cond, verbose, txt, retVal) do {if(cond){if(verbose)logGlobal->error("%s: %s",BOOST_CURRENT_FUNCTION, txt); return retVal;}} while(0)
+#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
 {
@@ -120,7 +120,7 @@ const CGObjectInstance* CGameInfoCallback::getObj(ObjectInstanceID objid, bool v
 	if(oid < 0  ||  oid >= gs->map->objects.size())
 	{
 		if(verbose)
-			logGlobal->errorStream() << "Cannot get object with id " << oid;
+			logGlobal->error("Cannot get object with id %d", oid);
 		return nullptr;
 	}
 
@@ -128,14 +128,14 @@ const CGObjectInstance* CGameInfoCallback::getObj(ObjectInstanceID objid, bool v
 	if(!ret)
 	{
 		if(verbose)
-			logGlobal->errorStream() << "Cannot get object with id " << oid << ". Object was removed.";
+			logGlobal->error("Cannot get object with id %d. Object was removed", oid);
 		return nullptr;
 	}
 
 	if(!isVisible(ret, player) && ret->tempOwner != player)
 	{
 		if(verbose)
-			logGlobal->errorStream() << "Cannot get object with id " << oid << ". Object is not visible.";
+			logGlobal->error("Cannot get object with id %d. Object is not visible.", oid);
 		return nullptr;
 	}
 
@@ -288,7 +288,7 @@ bool CGameInfoCallback::getHeroInfo(const CGObjectInstance * hero, InfoAboutHero
 			infoLevel = InfoAboutHero::EInfoLevel::INBATTLE;
 		else
 			ERROR_RET_VAL_IF(!isVisible(h->getPosition(false)), "That hero is not visible!", false);
-	}	
+	}
 
 	if( (infoLevel == InfoAboutHero::EInfoLevel::BASIC) && nullptr != selectedObject)
 	{
@@ -324,7 +324,7 @@ bool CGameInfoCallback::getHeroInfo(const CGObjectInstance * hero, InfoAboutHero
 			}
 
 			if(nullptr == mostStrong)//just in case
-				logGlobal->errorStream() << "CGameInfoCallback::getHeroInfo: Unable to select most strong stack" << disguiseLevel;
+				logGlobal->error("CGameInfoCallback::getHeroInfo: Unable to select most strong stack");
 			else
 				for(auto & elem : info.army)
 				{
@@ -381,12 +381,10 @@ bool CGameInfoCallback::getHeroInfo(const CGObjectInstance * hero, InfoAboutHero
 			break;
 		default:
 			//invalid value
-			logGlobal->errorStream() << "CGameInfoCallback::getHeroInfo: Invalid DISGUISED bonus value " << disguiseLevel;
+			logGlobal->error("CGameInfoCallback::getHeroInfo: Invalid DISGUISED bonus value %d", disguiseLevel);
 			break;
 		}
-
 	}
-
 	return true;
 }
 
@@ -442,7 +440,7 @@ std::vector <const CGObjectInstance * > CGameInfoCallback::getVisitableObjs(int3
 {
 	std::vector<const CGObjectInstance *> ret;
 	const TerrainTile *t = getTile(pos, verbose);
-	ERROR_VERBOSE_OR_NOT_RET_VAL_IF(!t, verbose, pos << " is not visible!", ret);
+	ERROR_VERBOSE_OR_NOT_RET_VAL_IF(!t, verbose, pos.toString() + " is not visible!", ret);
 
 	for(const CGObjectInstance * obj : t->visitableObjects)
 	{
@@ -486,7 +484,7 @@ std::vector<const CGHeroInstance *> CGameInfoCallback::getAvailableHeroes(const
 
 const TerrainTile * CGameInfoCallback::getTile( int3 tile, bool verbose) const
 {
-	ERROR_VERBOSE_OR_NOT_RET_VAL_IF(!isVisible(tile), verbose, tile << " is not visible!", nullptr);
+	ERROR_VERBOSE_OR_NOT_RET_VAL_IF(!isVisible(tile), verbose, tile.toString() + " is not visible!", nullptr);
 
 	//boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
 	return &gs->map->getTile(tile);

+ 4 - 6
lib/CGameInterface.cpp

@@ -59,18 +59,16 @@ std::shared_ptr<rett> createAny(const boost::filesystem::path & libpath, const s
 		getName = (TGetNameFun)dlsym(dll, "GetAiName");
 		getAI = (TGetAIFun)dlsym(dll, methodName.c_str());
 	}
-	else
-		logGlobal->errorStream() << "Error: " << dlerror();
 #endif // VCMI_WINDOWS
 
 	if (!dll)
 	{
-		logGlobal->errorStream() << "Cannot open dynamic library ("<<libpath<<"). Throwing...";
+		logGlobal->error("Cannot open dynamic library (%s). Throwing...", libpath.string());
 		throw std::runtime_error("Cannot open dynamic library");
 	}
 	else if(!getName || !getAI)
 	{
-		logGlobal->errorStream() << libpath << " does not export method " << methodName;
+		logGlobal->error("%s does not export method %s", libpath.string(), methodName);
 #ifdef VCMI_WINDOWS
 		FreeLibrary(dll);
 #else
@@ -80,7 +78,7 @@ std::shared_ptr<rett> createAny(const boost::filesystem::path & libpath, const s
 	}
 
 	getName(temp);
-	logGlobal->infoStream() << "Loaded " << temp;
+	logGlobal->info("Loaded %s", temp);
 
 	std::shared_ptr<rett> ret;
 	getAI(ret);
@@ -110,7 +108,7 @@ std::shared_ptr<CBattleGameInterface> createAny(const boost::filesystem::path &
 template<typename rett>
 std::shared_ptr<rett> createAnyAI(std::string dllname, const std::string & methodName)
 {
-	logGlobal->infoStream() << "Opening " << dllname;
+	logGlobal->info("Opening %s", dllname);
 
 	const boost::filesystem::path filePath = VCMIDirs::get().fullLibraryPath("AI", dllname);
 	auto ret = createAny<rett>(filePath, methodName);

+ 19 - 24
lib/CGameState.cpp

@@ -149,13 +149,13 @@ void MetaString::getLocalString(const std::pair<ui8,ui32> &txt, std::string &dst
 			vec = &VLC->generaltexth->jktexts;
 			break;
 		default:
-			logGlobal->errorStream() << "Failed string substitution because type is " << type;
+			logGlobal->error("Failed string substitution because type is %d", type);
 			dst = "#@#";
 			return;
 		}
 		if(vec->size() <= ser)
 		{
-			logGlobal->errorStream() << "Failed string substitution with type " << type << " because index " << ser << " is out of bounds!";
+			logGlobal->error("Failed string substitution with type %d because index %d is out of bounds!", type, ser);
 			dst = "#!#";
 		}
 		else
@@ -202,7 +202,7 @@ DLL_LINKAGE void MetaString::toString(std::string &dst) const
 			boost::replace_first(dst, "%+d", '+' + boost::lexical_cast<std::string>(numbers[nums++]));
 			break;
 		default:
-			logGlobal->errorStream() << "MetaString processing error! Received message of type " << int(elem);
+			logGlobal->error("MetaString processing error! Received message of type %d", int(elem));
 			break;
 		}
 	}
@@ -259,7 +259,7 @@ DLL_LINKAGE std::string MetaString::buildList () const
 				lista.replace (lista.find("%d"), 2, boost::lexical_cast<std::string>(numbers[nums++]));
 				break;
 			default:
-				logGlobal->errorStream() << "MetaString processing error! Received message of type " << int(message[i]);
+				logGlobal->error("MetaString processing error! Received message of type %d",int(message[i]));
 		}
 
 	}
@@ -318,7 +318,7 @@ CGHeroInstance * CGameState::HeroesPool::pickHeroFor(bool native, PlayerColor pl
 
 	if(player>=PlayerColor::PLAYER_LIMIT)
 	{
-		logGlobal->errorStream() << "Cannot pick hero for " << town->faction->index << ". Wrong owner!";
+		logGlobal->error("Cannot pick hero for faction %d. Wrong owner!", town->faction->index);
 		return nullptr;
 	}
 
@@ -336,7 +336,7 @@ CGHeroInstance * CGameState::HeroesPool::pickHeroFor(bool native, PlayerColor pl
 		}
 		if(!pool.size())
 		{
-			logGlobal->errorStream() << "Cannot pick native hero for " << player << ". Picking any...";
+			logGlobal->error("Cannot pick native hero for %s. Picking any...", player.getStr());
 			return pickHeroFor(false, player, town, available, rand);
 		}
 		else
@@ -359,7 +359,7 @@ CGHeroInstance * CGameState::HeroesPool::pickHeroFor(bool native, PlayerColor pl
 		}
 		if(!pool.size() || sum == 0)
 		{
-			logGlobal->errorStream() << "There are no heroes available for player " << player<<"!";
+			logGlobal->error("There are no heroes available for player %s!", player.getStr());
 			return nullptr;
 		}
 
@@ -429,7 +429,7 @@ int CGameState::pickUnusedHeroTypeRandomly(PlayerColor owner)
 		return RandomGeneratorUtil::nextItem(factionHeroes, getRandomGenerator())->getNum();
 	}
 
-	logGlobal->warnStream() << "Cannot find free hero of appropriate faction for player " << owner << " - trying to get first available...";
+	logGlobal->warn("Cannot find free hero of appropriate faction for player %s - trying to get first available...", owner.getStr());
 	if(!otherHeroes.empty())
 	{
 		return RandomGeneratorUtil::nextItem(otherHeroes, getRandomGenerator())->getNum();
@@ -520,7 +520,7 @@ std::pair<Obj,int> CGameState::pickObject (CGObjectInstance *obj)
 					auto iter = map->instanceNames.find(info->instanceId);
 
 					if(iter == map->instanceNames.end())
-						logGlobal->errorStream() << "Map object not found: " << info->instanceId;
+						logGlobal->error("Map object not found: %s", info->instanceId);
 					else
 					{
 						auto elem = iter->second;
@@ -532,7 +532,7 @@ std::pair<Obj,int> CGameState::pickObject (CGObjectInstance *obj)
 						else if(elem->ID==Obj::TOWN)
 							faction = elem->subID;
 						else
-							logGlobal->errorStream() << "Map object must be town: " << info->instanceId;
+							logGlobal->error("Map object must be town: %s", info->instanceId);
 					}
 				}
 				else if(info->asCastle)
@@ -613,7 +613,7 @@ std::pair<Obj,int> CGameState::pickObject (CGObjectInstance *obj)
 
 			if (result.first == Obj::NO_OBJ)
 			{
-				logGlobal->errorStream() << "Error: failed to find dwelling for "<< VLC->townh->factions[faction]->name << " of level " << int(level);
+				logGlobal->error("Error: failed to find dwelling for %s of level %d", VLC->townh->factions[faction]->name, int(level));
 				result = std::make_pair(Obj::CREATURE_GENERATOR1, *RandomGeneratorUtil::nextItem(VLC->objtypeh->knownSubObjects(Obj::CREATURE_GENERATOR1), getRandomGenerator()));
 			}
 
@@ -703,7 +703,7 @@ CGameState::~CGameState()
 
 void CGameState::init(StartInfo * si, bool allowSavingRandomMap)
 {
-	logGlobal->infoStream() << "\tUsing random seed: "<< si->seedToBeUsed;
+	logGlobal->info("\tUsing random seed: %d", si->seedToBeUsed);
 	getRandomGenerator().setSeed(si->seedToBeUsed);
 	scenarioOps = CMemorySerializer::deepCopy(*si).release();
 	initialOpts = CMemorySerializer::deepCopy(*si).release();
@@ -718,7 +718,7 @@ void CGameState::init(StartInfo * si, bool allowSavingRandomMap)
 		initCampaign();
 		break;
 	default:
-		logGlobal->errorStream() << "Wrong mode: " << (int)scenarioOps->mode;
+		logGlobal->error("Wrong mode: %d", static_cast<int>(scenarioOps->mode));
 		return;
 	}
 	VLC->arth->initAllowedArtifactsList(map->allowedArtifact);
@@ -759,7 +759,7 @@ void CGameState::init(StartInfo * si, bool allowSavingRandomMap)
 	map->checkForObjectives(); //needs to be run when all objects are properly placed
 
 	auto seedAfterInit = getRandomGenerator().nextInt();
-	logGlobal->infoStream() << "Seed after init is " << seedAfterInit << " (before was " << scenarioOps->seedToBeUsed << ")";
+	logGlobal->info("Seed after init is %d (before was %d)", seedAfterInit, scenarioOps->seedToBeUsed);
 	if(scenarioOps->seedPostInit > 0)
 	{
 		//RNG must be in the same state on all machines when initialization is done (otherwise we have desync)
@@ -837,7 +837,7 @@ void CGameState::initNewGame(bool allowSavingRandomMap)
 	}
 	else
 	{
-		logGlobal->infoStream() << "Open map file: " << scenarioOps->mapname;
+		logGlobal->info("Open map file: %s", scenarioOps->mapname);
 		const ResourceID mapURI(scenarioOps->mapname, EResType::MAP);
 		map = CMapService::loadMap(mapURI).release();
 	}
@@ -845,7 +845,7 @@ void CGameState::initNewGame(bool allowSavingRandomMap)
 
 void CGameState::initCampaign()
 {
-	logGlobal->infoStream() << "Open campaign map file: " << scenarioOps->campState->currentMap;
+	logGlobal->info("Open campaign map file: %d", scenarioOps->campState->currentMap.get());
 	auto campaign = scenarioOps->campState;
 	assert(vstd::contains(campaign->camp->mapPieces, *scenarioOps->campState->currentMap));
 
@@ -860,10 +860,10 @@ void CGameState::initCampaign()
 
 void CGameState::checkMapChecksum()
 {
-	logGlobal->infoStream() << "\tOur checksum for the map: "<< map->checksum;
+	logGlobal->info("\tOur checksum for the map: %d", map->checksum);
 	if(scenarioOps->mapfileChecksum)
 	{
-		logGlobal->infoStream() << "\tServer checksum for " << scenarioOps->mapname <<": "<< scenarioOps->mapfileChecksum;
+		logGlobal->info("\tServer checksum for %s: %d", scenarioOps->mapname, scenarioOps->mapfileChecksum);
 		if(map->checksum != scenarioOps->mapfileChecksum)
 		{
 			logGlobal->error("Wrong map checksum!!!");
@@ -1747,7 +1747,7 @@ void CGameState::initMapObjects()
 	{
 		if(obj)
 		{
-			logGlobal->traceStream() << boost::format ("Calling Init for object %d, %s, %s") % obj->id.getNum() % obj->typeName % obj->subTypeName;
+			logGlobal->trace("Calling Init for object %d, %s, %s", obj->id.getNum(), obj->typeName, obj->subTypeName);
 			obj->initObj(getRandomGenerator());
 		}
 	}
@@ -3080,10 +3080,5 @@ TeamState::TeamState(TeamState && other):
 
 CRandomGenerator & CGameState::getRandomGenerator()
 {
-	//if(scenarioOps && scenarioOps->seedPostInit)
-	//{
-	//	logGlobal->trace("CGameState::getRandomGenerator used after initialization!");
-	//}
-	//logGlobal->traceStream() << "Fetching CGameState::rand with seed " << rand.nextInt();
 	return rand;
 }

+ 1 - 1
lib/CHeroHandler.cpp

@@ -362,7 +362,7 @@ void CHeroHandler::loadHeroSkills(CHero * hero, const JsonNode & node)
 		}
 		else
 		{
-			logGlobal->errorStream() << "Unknown skill level: " <<set["level"].String();
+			logGlobal->error("Unknown skill level: %s", set["level"].String());
 		}
 	}
 

+ 48 - 48
lib/CModHandler.cpp

@@ -36,7 +36,7 @@ CIdentifierStorage::~CIdentifierStorage()
 void CIdentifierStorage::checkIdentifier(std::string & ID)
 {
 	if (boost::algorithm::ends_with(ID, "."))
-		logGlobal->warnStream() << "BIG WARNING: identifier " << ID << " seems to be broken!";
+		logGlobal->warn("BIG WARNING: identifier %s seems to be broken!", ID);
 	else
 	{
 		size_t pos = 0;
@@ -44,7 +44,7 @@ void CIdentifierStorage::checkIdentifier(std::string & ID)
 		{
 			if (std::tolower(ID[pos]) != ID[pos] ) //Not in camelCase
 			{
-				logGlobal->warnStream() << "Warning: identifier " << ID << " is not in camelCase!";
+				logGlobal->warn("Warning: identifier %s is not in camelCase!", ID);
 				ID[pos] = std::tolower(ID[pos]);// Try to fix the ID
 			}
 			pos = ID.find('.', pos);
@@ -148,7 +148,7 @@ boost::optional<si32> CIdentifierStorage::getIdentifier(std::string scope, std::
 	if (idList.size() == 1)
 		return idList.front().id;
 	if (!silent)
-		logGlobal->errorStream() << "Failed to resolve identifier " << name << " of type " << type << " from mod " << scope;
+		logGlobal->error("Failed to resolve identifier %s of type %s from mod %s", name , type ,scope);
 
 	return boost::optional<si32>();
 }
@@ -161,7 +161,7 @@ boost::optional<si32> CIdentifierStorage::getIdentifier(std::string type, const
 	if (idList.size() == 1)
 		return idList.front().id;
 	if (!silent)
-		logGlobal->errorStream() << "Failed to resolve identifier " << name.String() << " of type " << type << " from mod " << name.meta;
+		logGlobal->error("Failed to resolve identifier %s of type %s from mod %s", name.String(), type, name.meta);
 
 	return boost::optional<si32>();
 }
@@ -175,7 +175,7 @@ boost::optional<si32> CIdentifierStorage::getIdentifier(const JsonNode & name, b
 	if (idList.size() == 1)
 		return idList.front().id;
 	if (!silent)
-		logGlobal->errorStream() << "Failed to resolve identifier " << name.String() << " of type " << pair2.first << " from mod " << name.meta;
+		logGlobal->error("Failed to resolve identifier %s of type %s from mod %s", name.String(), pair2.first, name.meta);
 
 	return boost::optional<si32>();
 }
@@ -189,7 +189,7 @@ boost::optional<si32> CIdentifierStorage::getIdentifier(std::string scope, std::
 	if (idList.size() == 1)
 		return idList.front().id;
 	if (!silent)
-		logGlobal->errorStream() << "Failed to resolve identifier " << fullName << " of type " << pair2.first << " from mod " << scope;
+		logGlobal->error("Failed to resolve identifier %s of type %s from mod %s", fullName, pair2.first, scope);
 
 	return boost::optional<si32>();
 }
@@ -278,11 +278,11 @@ bool CIdentifierStorage::resolveIdentifier(const ObjectCallback & request)
 	else
 		logGlobal->error("Ambiguous identifier request!");
 
-	 logGlobal->errorStream() << "Request for " << request.type << "." << request.name << " from mod " << request.localScope;
+	 logGlobal->error("Request for %s.%s from mod %s", request.type, request.name, request.localScope);
 
 	for (auto id : identifiers)
 	{
-		logGlobal->errorStream() << "\tID is available in mod " << id.scope;
+		logGlobal->error("\tID is available in mod %s", id.scope);
 	}
 	return false;
 }
@@ -302,7 +302,7 @@ void CIdentifierStorage::finalize()
 	{
 		for(auto object : registeredObjects)
 		{
-			logGlobal->traceStream() << object.second.scope << " : " << object.first << " -> " << object.second.id;
+			logGlobal->trace("%s : %s -> %d", object.second.scope, object.first, object.second.id);
 		}
 		logGlobal->error("All known identifiers were dumped into log file");
 	}
@@ -345,9 +345,9 @@ bool CContentHandler::ContentTypeHandler::preloadModData(std::string modName, st
 
 			// patching this mod? Send warning and continue - this situation can be handled normally
 			if (remoteName == modName)
-				logGlobal->warnStream() << "Redundant namespace definition for " << objectName;
+				logGlobal->warn("Redundant namespace definition for %s", objectName);
 
-			logGlobal->traceStream() << "Patching object " << objectName << " (" << remoteName << ") from " << modName;
+			logGlobal->trace("Patching object %s (%s) from %s", objectName, remoteName, modName);
 			JsonNode & remoteConf = modData[remoteName].patches[objectName];
 
 			JsonUtils::merge(remoteConf, entry.second);
@@ -466,8 +466,7 @@ void CContentHandler::preloadData(CModInfo & mod)
 	bool validate = (mod.validation != CModInfo::PASSED);
 
 	// print message in format [<8-symbols checksum>] <modname>
-	logGlobal->infoStream() << "\t\t[" << std::noshowbase << std::hex << std::setw(8) << std::setfill('0')
-							<< mod.checksum << "] " << mod.name;
+	logGlobal->info("\t\t[%08x]%s", mod.checksum, mod.name);
 
 	if (validate && mod.identifier != "core")
 	{
@@ -488,12 +487,12 @@ void CContentHandler::load(CModInfo & mod)
 	if (validate)
 	{
 		if (mod.validation != CModInfo::FAILED)
-			logGlobal->infoStream()  << "\t\t[DONE] " << mod.name;
+			logGlobal->info("\t\t[DONE] %s", mod.name);
 		else
-			logGlobal->errorStream() << "\t\t[FAIL] " << mod.name;
+			logGlobal->error("\t\t[FAIL] %s", mod.name);
 	}
 	else
-		logGlobal->infoStream()  << "\t\t[SKIP] " << mod.name;
+		logGlobal->info("\t\t[SKIP] %s", mod.name);
 }
 
 static JsonNode loadModSettings(std::string path)
@@ -619,38 +618,39 @@ void CModHandler::loadConfigFromFile (std::string name)
 		paths += p.string() + ", ";
 	}
 	paths = paths.substr(0, paths.size() - 2);
-	logGlobal->debugStream() << "Loading hardcoded features settings from [" << paths << "], result:";
+	logGlobal->debug("Loading hardcoded features settings from [%s], result:", paths);
 	settings.data = JsonUtils::assembleFromFiles("config/" + name);
 	const JsonNode & hardcodedFeatures = settings.data["hardcodedFeatures"];
-	settings.MAX_HEROES_AVAILABLE_PER_PLAYER = hardcodedFeatures["MAX_HEROES_AVAILABLE_PER_PLAYER"].Float();
-	logGlobal->debugStream() << "\tMAX_HEROES_AVAILABLE_PER_PLAYER\t" << settings.MAX_HEROES_AVAILABLE_PER_PLAYER;
-	settings.MAX_HEROES_ON_MAP_PER_PLAYER = hardcodedFeatures["MAX_HEROES_ON_MAP_PER_PLAYER"].Float();
-	logGlobal->debugStream() << "\tMAX_HEROES_ON_MAP_PER_PLAYER\t" << settings.MAX_HEROES_ON_MAP_PER_PLAYER;
-	settings.CREEP_SIZE = hardcodedFeatures["CREEP_SIZE"].Float();
-	logGlobal->debugStream() << "\tCREEP_SIZE\t" << settings.CREEP_SIZE;
-	settings.WEEKLY_GROWTH = hardcodedFeatures["WEEKLY_GROWTH_PERCENT"].Float();
-	logGlobal->debugStream() << "\tWEEKLY_GROWTH\t" << settings.WEEKLY_GROWTH;
-	settings.NEUTRAL_STACK_EXP = hardcodedFeatures["NEUTRAL_STACK_EXP_DAILY"].Float();
-	logGlobal->debugStream() << "\tNEUTRAL_STACK_EXP\t" << settings.NEUTRAL_STACK_EXP;
-	settings.MAX_BUILDING_PER_TURN = hardcodedFeatures["MAX_BUILDING_PER_TURN"].Float();
-	logGlobal->debugStream() << "\tMAX_BUILDING_PER_TURN\t" << settings.MAX_BUILDING_PER_TURN;
+	settings.MAX_HEROES_AVAILABLE_PER_PLAYER = hardcodedFeatures["MAX_HEROES_AVAILABLE_PER_PLAYER"].Integer();
+	logGlobal->debug("\tMAX_HEROES_AVAILABLE_PER_PLAYER\t%d", settings.MAX_HEROES_AVAILABLE_PER_PLAYER);
+	settings.MAX_HEROES_ON_MAP_PER_PLAYER = hardcodedFeatures["MAX_HEROES_ON_MAP_PER_PLAYER"].Integer();
+	logGlobal->debug("\tMAX_HEROES_ON_MAP_PER_PLAYER\t%d", settings.MAX_HEROES_ON_MAP_PER_PLAYER);
+	settings.CREEP_SIZE = hardcodedFeatures["CREEP_SIZE"].Integer();
+	logGlobal->debug("\tCREEP_SIZE\t%d", settings.CREEP_SIZE);
+	settings.WEEKLY_GROWTH = hardcodedFeatures["WEEKLY_GROWTH_PERCENT"].Integer();
+	logGlobal->debug("\tWEEKLY_GROWTH\t%d", settings.WEEKLY_GROWTH);
+	settings.NEUTRAL_STACK_EXP = hardcodedFeatures["NEUTRAL_STACK_EXP_DAILY"].Integer();
+	logGlobal->debug("\tNEUTRAL_STACK_EXP\t%d", settings.NEUTRAL_STACK_EXP);
+	settings.MAX_BUILDING_PER_TURN = hardcodedFeatures["MAX_BUILDING_PER_TURN"].Integer();
+	logGlobal->debug("\tMAX_BUILDING_PER_TURN\t%d", settings.MAX_BUILDING_PER_TURN);
 	settings.DWELLINGS_ACCUMULATE_CREATURES = hardcodedFeatures["DWELLINGS_ACCUMULATE_CREATURES"].Bool();
-	logGlobal->debugStream() << "\tDWELLINGS_ACCUMULATE_CREATURES\t" << settings.DWELLINGS_ACCUMULATE_CREATURES;
+	logGlobal->debug("\tDWELLINGS_ACCUMULATE_CREATURES\t%d", static_cast<int>(settings.DWELLINGS_ACCUMULATE_CREATURES));
 	settings.ALL_CREATURES_GET_DOUBLE_MONTHS = hardcodedFeatures["ALL_CREATURES_GET_DOUBLE_MONTHS"].Bool();
-	logGlobal->debugStream() << "\tALL_CREATURES_GET_DOUBLE_MONTHS\t" << settings.ALL_CREATURES_GET_DOUBLE_MONTHS;
+	logGlobal->debug("\tALL_CREATURES_GET_DOUBLE_MONTHS\t%d", static_cast<int>(settings.ALL_CREATURES_GET_DOUBLE_MONTHS));
 	settings.WINNING_HERO_WITH_NO_TROOPS_RETREATS = hardcodedFeatures["WINNING_HERO_WITH_NO_TROOPS_RETREATS"].Bool();
-	logGlobal->debugStream() << "\tWINNING_HERO_WITH_NO_TROOPS_RETREATS\t" << settings.WINNING_HERO_WITH_NO_TROOPS_RETREATS;
+	logGlobal->debug("\tWINNING_HERO_WITH_NO_TROOPS_RETREATS\t%d", static_cast<int>(settings.WINNING_HERO_WITH_NO_TROOPS_RETREATS));
 	settings.BLACK_MARKET_MONTHLY_ARTIFACTS_CHANGE = hardcodedFeatures["BLACK_MARKET_MONTHLY_ARTIFACTS_CHANGE"].Bool();
-	logGlobal->debugStream() << "\tBLACK_MARKET_MONTHLY_ARTIFACTS_CHANGE\t" << settings.BLACK_MARKET_MONTHLY_ARTIFACTS_CHANGE;
+	logGlobal->debug("\tBLACK_MARKET_MONTHLY_ARTIFACTS_CHANGE\t%d", static_cast<int>(settings.BLACK_MARKET_MONTHLY_ARTIFACTS_CHANGE));
+
 	const JsonNode & gameModules = settings.data["modules"];
 	modules.STACK_EXP = gameModules["STACK_EXPERIENCE"].Bool();
-  logGlobal->debugStream() << "\tSTACK_EXP\t" << modules.STACK_EXP;
+	logGlobal->debug("\tSTACK_EXP\t%d", static_cast<int>(modules.STACK_EXP));
 	modules.STACK_ARTIFACT = gameModules["STACK_ARTIFACTS"].Bool();
-	logGlobal->debugStream() << "\tSTACK_ARTIFACT\t" << modules.STACK_ARTIFACT;
+	logGlobal->debug("\tSTACK_ARTIFACT\t%d", static_cast<int>(modules.STACK_ARTIFACT));
 	modules.COMMANDERS = gameModules["COMMANDERS"].Bool();
-	logGlobal->debugStream() << "\tCOMMANDERS\t" << modules.COMMANDERS;
+	logGlobal->debug("\tCOMMANDERS\t%d", static_cast<int>(modules.COMMANDERS));
 	modules.MITHRIL = gameModules["MITHRIL"].Bool();
-	logGlobal->debugStream() << "\tMITHRIL\t" << modules.MITHRIL;
+	logGlobal->debug("\tMITHRIL\t%d", static_cast<int>(modules.MITHRIL));
 }
 
 // currentList is passed by value to get current list of depending mods
@@ -662,7 +662,7 @@ bool CModHandler::hasCircularDependency(TModID modID, std::set <TModID> currentL
 	if (vstd::contains(currentList, modID))
 	{
 		logGlobal->error("Error: Circular dependency detected! Printing dependency list:");
-		logGlobal->errorStream() << "\t" << mod.name << " -> ";
+		logGlobal->error("\t%s -> ", mod.name);
 		return true;
 	}
 
@@ -673,7 +673,7 @@ bool CModHandler::hasCircularDependency(TModID modID, std::set <TModID> currentL
 	{
 		if (hasCircularDependency(dependency, currentList))
 		{
-			logGlobal->errorStream() << "\t" << mod.name << " ->\n"; // conflict detected, print dependency list
+			logGlobal->error("\t%s ->\n", mod.name); // conflict detected, print dependency list
 			return true;
 		}
 	}
@@ -690,7 +690,7 @@ bool CModHandler::checkDependencies(const std::vector <TModID> & input) const
 		{
 			if (!vstd::contains(input, dep))
 			{
-				logGlobal->errorStream() << "Error: Mod " << mod.name << " requires missing " << dep << "!";
+				logGlobal->error("Error: Mod %s requires missing %s!", mod.name, dep);
 				return false;
 			}
 		}
@@ -699,7 +699,7 @@ bool CModHandler::checkDependencies(const std::vector <TModID> & input) const
 		{
 			if (vstd::contains(input, conflicting))
 			{
-				logGlobal->errorStream() << "Error: Mod " << mod.name << " conflicts with " << allMods.at(conflicting).name << "!";
+				logGlobal->error("Error: Mod %s conflicts with %s!", mod.name, allMods.at(conflicting).name);
 				return false;
 			}
 		}
@@ -930,11 +930,11 @@ void CModHandler::load()
 	CStopWatch totalTime, timer;
 
 	CContentHandler content;
-	logGlobal->infoStream() << "\tInitializing content handler: " << timer.getDiff() << " ms";
+	logGlobal->info("\tInitializing content handler: %d ms", timer.getDiff());
 
 	for(const TModID & modName : activeMods)
 	{
-		logGlobal->traceStream() << "Generating checksum for " << modName;
+		logGlobal->trace("Generating checksum for %s", modName);
 		allMods[modName].updateChecksum(calculateModChecksum(modName, CResourceHandler::get(modName)));
 	}
 
@@ -943,7 +943,7 @@ void CModHandler::load()
 	content.preloadData(coreMod);
 	for(const TModID & modName : activeMods)
 		content.preloadData(allMods[modName]);
-	logGlobal->infoStream() << "\tParsing mod data: " << timer.getDiff() << " ms";
+	logGlobal->info("\tParsing mod data: %d ms", timer.getDiff());
 
 	content.load(coreMod);
 	for(const TModID & modName : activeMods)
@@ -951,17 +951,17 @@ void CModHandler::load()
 
 	content.loadCustom();
 
-	logGlobal->infoStream() << "\tLoading mod data: " << timer.getDiff() << "ms";
+	logGlobal->info("\tLoading mod data: %d ms", timer.getDiff());
 
 	VLC->creh->loadCrExpBon();
 	VLC->creh->buildBonusTreeForTiers(); //do that after all new creatures are loaded
 
 	identifiers.finalize();
-	logGlobal->infoStream() << "\tResolving identifiers: " << timer.getDiff() << " ms";
+	logGlobal->info("\tResolving identifiers: %d ms", timer.getDiff());
 
 	content.afterLoadFinalization();
-	logGlobal->infoStream() << "\tHandlers post-load finalization: " << timer.getDiff() << " ms";
-	logGlobal->infoStream() << "\tAll game content loaded in " << totalTime.getDiff() << " ms";
+	logGlobal->info("\tHandlers post-load finalization: %d ms ", timer.getDiff());
+	logGlobal->info("\tAll game content loaded in %d ms", totalTime.getDiff());
 }
 
 void CModHandler::afterLoad()

+ 1 - 1
lib/CStack.h

@@ -293,7 +293,7 @@ public:
 			else if(!army || extSlot == SlotID() || !army->hasStackAtSlot(extSlot))
 			{
 				base = nullptr;
-				logGlobal->warnStream() << type->nameSing << " doesn't have a base stack!";
+				logGlobal->warn("%s doesn't have a base stack!", type->nameSing);
 			}
 			else
 			{

+ 1 - 1
lib/GameConstants.cpp

@@ -59,7 +59,7 @@ const CSpell * SpellID::toSpell() const
 {
 	if(num < 0 || num >= VLC->spellh->objects.size())
 	{
-		logGlobal->errorStream() << "Unable to get spell of invalid ID " << int(num);
+		logGlobal->error("Unable to get spell of invalid ID %d", int(num));
 		return nullptr;
 	}
 	return VLC->spellh->objects[*this];

+ 5 - 8
lib/HeroBonus.cpp

@@ -103,8 +103,6 @@ const BonusList * CBonusProxy::operator->() const
 	return get().get();
 }
 
-#define BONUS_LOG_LINE(x) logBonus->traceStream() << x
-
 int CBonusSystemNode::treeChanged = 1;
 const bool CBonusSystemNode::cachingEnabled = true;
 
@@ -808,7 +806,7 @@ void CBonusSystemNode::propagateBonus(std::shared_ptr<Bonus> b)
 	if(b->propagator->shouldBeAttached(this))
 	{
 		bonuses.push_back(b);
-		BONUS_LOG_LINE("#$# " << b->Description() << " #propagated to# " << nodeName());
+		logBonus->trace("#$# %s #propagated to# %s",  b->Description(), nodeName());
 	}
 
 	FOREACH_RED_CHILD(child)
@@ -822,10 +820,10 @@ void CBonusSystemNode::unpropagateBonus(std::shared_ptr<Bonus> b)
 		bonuses -= b;
 		while(vstd::contains(bonuses, b))
 		{
-			logBonus->errorStream() << "Bonus was duplicated (" << b->Description() << ") at " << nodeName();
+			logBonus->error("Bonus was duplicated (%s) at %s", b->Description(), nodeName());
 			bonuses -= b;
 		}
-		BONUS_LOG_LINE("#$#" << b->Description() << " #is no longer propagated to# " << nodeName());
+		logBonus->trace("#$# %s #is no longer propagated to# %s",  b->Description(), nodeName());
 	}
 
 	FOREACH_RED_CHILD(child)
@@ -836,7 +834,6 @@ void CBonusSystemNode::newChildAttached(CBonusSystemNode *child)
 {
 	assert(!vstd::contains(children, child));
 	children.push_back(child);
-	//BONUS_LOG_LINE(child->nodeName() << " #attached to# " << nodeName());
 }
 
 void CBonusSystemNode::childDetached(CBonusSystemNode *child)
@@ -845,8 +842,8 @@ void CBonusSystemNode::childDetached(CBonusSystemNode *child)
 		children -= child;
 	else
 	{
-		logBonus->errorStream() << std::string("Error!" + child->nodeName() + " #cannot be detached from# " + nodeName());
-		assert(0);
+		logBonus->error("Error! %s #cannot be detached from# %s", child->nodeName(), nodeName());
+		throw std::runtime_error("internal error");
 	}
 
 }

+ 2 - 2
lib/IHandlerBase.h

@@ -96,8 +96,8 @@ public:
 
 		if (raw_id < 0 || raw_id >= objects.size())
 		{
-			logGlobal->errorStream() << getTypeName() << " id " << static_cast<si64>(raw_id) << "is invalid";
-			throw std::runtime_error ("internal error");
+			logGlobal->error("%s id %d is invalid", getTypeName(), static_cast<si64>(raw_id));
+			throw std::runtime_error("internal error");
 		}
 
 		return objects[raw_id];

+ 2 - 2
lib/JsonDetail.cpp

@@ -163,8 +163,8 @@ JsonNode JsonParser::parse(std::string fileName)
 
 	if (!errors.empty())
 	{
-		logGlobal->warnStream()<<"File " << fileName << " is not a valid JSON file!";
-		logGlobal->warnStream()<<errors;
+		logGlobal->warn("File %s is not a valid JSON file!", fileName);
+		logGlobal->warn(errors);
 	}
 	return root;
 }

+ 16 - 14
lib/JsonNode.cpp

@@ -395,7 +395,7 @@ std::shared_ptr<Bonus> JsonUtils::parseBonus (const JsonVector &ability_vec) //T
 	auto it = bonusNameMap.find(type);
 	if (it == bonusNameMap.end())
 	{
-		logGlobal->errorStream() << "Error: invalid ability type " << type;
+		logGlobal->error("Error: invalid ability type %s", type);
 		return b;
 	}
 	b->type = it->second;
@@ -413,7 +413,7 @@ const T & parseByMap(const std::map<std::string, T> & map, const JsonNode * val,
 		auto it = map.find(type);
 		if (it == map.end())
 		{
-			logGlobal->errorStream() << "Error: invalid " << err << type;
+			logGlobal->error("Error: invalid %s%s", err, type);
 			return defaultValue;
 		}
 		else
@@ -445,7 +445,7 @@ void JsonUtils::resolveIdentifier(si32 &var, const JsonNode &node, std::string n
 				});
 				break;
 			default:
-				logGlobal->errorStream() << "Error! Wrong identifier used for value of " << name;
+				logGlobal->error("Error! Wrong identifier used for value of %s", name);
 		}
 	}
 }
@@ -489,7 +489,7 @@ bool JsonUtils::parseBonus(const JsonNode &ability, Bonus *b)
 	auto it = bonusNameMap.find(type);
 	if (it == bonusNameMap.end())
 	{
-		logGlobal->errorStream() << "Error: invalid ability type " << type;
+		logGlobal->error("Error: invalid ability type %s", type);
 		return false;
 	}
 	b->type = it->second;
@@ -580,7 +580,7 @@ bool JsonUtils::parseBonus(const JsonNode &ability, Bonus *b)
 							auto it = bonusNameMap.find(anotherBonusType);
 							if (it == bonusNameMap.end())
 							{
-								logGlobal->errorStream() << "Error: invalid ability type " << anotherBonusType;
+								logGlobal->error("Error: invalid ability type %s", anotherBonusType);
 								continue;
 							}
 							l2->type = it->second;
@@ -723,8 +723,8 @@ bool JsonUtils::validate(const JsonNode &node, std::string schemaName, std::stri
 	std::string log = Validation::check(schemaName, node);
 	if (!log.empty())
 	{
-		logGlobal->warnStream() << "Data in " << dataName << " is invalid!";
-		logGlobal->warnStream() << log;
+		logGlobal->warn("Data in %s is invalid!", dataName);
+		logGlobal->warn(log);
 	}
 	return log.empty();
 }
@@ -745,30 +745,32 @@ const JsonNode & getSchemaByName(std::string name)
 		return loadedSchemas[name];
 	}
 
-	logGlobal->errorStream() << "Error: missing schema with name " << name << "!";
+	logGlobal->error("Error: missing schema with name %s!", name);
 	assert(0);
 	return nullNode;
 }
 
 const JsonNode & JsonUtils::getSchema(std::string URI)
 {
-	std::vector<std::string> segments;
-
 	size_t posColon = URI.find(':');
 	size_t posHash  = URI.find('#');
-	assert(posColon != std::string::npos);
+	if(posColon == std::string::npos)
+	{
+		logGlobal->error("Invalid schema URI:%s", URI);
+		return nullNode;
+	}
 
 	std::string protocolName = URI.substr(0, posColon);
 	std::string filename =     URI.substr(posColon + 1, posHash - posColon - 1);
 
-	if (protocolName != "vcmi")
+	if(protocolName != "vcmi")
 	{
-		logGlobal->errorStream() << "Error: unsupported URI protocol for schema: " << segments[0];
+		logGlobal->error("Error: unsupported URI protocol for schema: %s", URI);
 		return nullNode;
 	}
 
 	// check if json pointer if present (section after hash in string)
-	if (posHash == std::string::npos || posHash == URI.size() - 1)
+	if(posHash == std::string::npos || posHash == URI.size() - 1)
 		return getSchemaByName(filename);
 	else
 		return getSchemaByName(filename).resolvePointer(URI.substr(posHash + 1));

+ 1 - 3
lib/NetPacks.h

@@ -62,7 +62,7 @@ struct CPackForServer : public CPack
 
 	bool applyGh(CGameHandler *gh) //called after applying to gs
 	{
-		logGlobal->errorStream() << "Should not happen... applying plain CPackForServer";
+		logGlobal->error("Should not happen... applying plain CPackForServer");
 		return false;
 	}
 };
@@ -1771,8 +1771,6 @@ struct ELF_VISIBILITY CatapultAttack : public CPackForClient
 	}
 };
 
-DLL_LINKAGE std::ostream & operator<<(std::ostream & out, const CatapultAttack::AttackInfo & attackInfo);
-
 struct BattleStacksRemoved : public CPackForClient
 {
 	BattleStacksRemoved(){}

+ 1 - 1
lib/NetPacksBase.h

@@ -28,7 +28,7 @@ struct DLL_LINKAGE CPack
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
-		logNetwork->errorStream() << "CPack serialized... this should not happen!";
+		logNetwork->error("CPack serialized... this should not happen!");
 		assert(false && "CPack serialized");
 	}
 	void applyGs(CGameState *gs) { }

+ 26 - 22
lib/NetPacksLib.cpp

@@ -306,7 +306,7 @@ DLL_LINKAGE void ChangeObjPos::applyGs(CGameState *gs)
 	CGObjectInstance *obj = gs->getObjInstance(objid);
 	if(!obj)
 	{
-		logNetwork->errorStream() << "Wrong ChangeObjPos: object " << objid.getNum() << " doesn't exist!";
+		logNetwork->error("Wrong ChangeObjPos: object %d doesn't exist!", objid.getNum());
 		return;
 	}
 	gs->map->removeBlockVisTiles(obj);
@@ -384,7 +384,7 @@ DLL_LINKAGE void RemoveObject::applyGs(CGameState *gs)
 {
 
 	CGObjectInstance *obj = gs->getObjInstance(id);
-	logGlobal->debugStream() << "removing object id=" << id << "; address=" << (intptr_t)obj << "; name=" << obj->getObjectName();
+	logGlobal->debug("removing object id=%d; address=%x; name=%s", id, (intptr_t)obj, obj->getObjectName());
 	//unblock tiles
 	gs->map->removeBlockVisTiles(obj);
 
@@ -513,7 +513,7 @@ void TryMoveHero::applyGs(CGameState *gs)
 	CGHeroInstance *h = gs->getHero(id);
 	if (!h)
 	{
-		logGlobal->errorStream() << "Attempt ot move unavailable hero " << id;
+		logGlobal->error("Attempt ot move unavailable hero %d", id.getNum());
 		return;
 	}
 
@@ -721,7 +721,7 @@ DLL_LINKAGE void NewObject::applyGs(CGameState *gs)
 	o->initObj(gs->getRandomGenerator());
 	gs->map->calculateGuardingGreaturePositions();
 
-	logGlobal->debugStream() << "added object id=" << id << "; address=" << (intptr_t)o << "; name=" << o->getObjectName();
+	logGlobal->debug("Added object id=%d; address=%x; name=%s", id, (intptr_t)o, o->getObjectName());
 }
 
 DLL_LINKAGE void NewArtifact::applyGs(CGameState *gs)
@@ -739,7 +739,7 @@ DLL_LINKAGE const CStackInstance * StackLocation::getStack()
 {
 	if(!army->hasStackAtSlot(slot))
 	{
-		logNetwork->warnStream() << "Warning: " << army->nodeName() << " don't have a stack at slot " << slot;
+		logNetwork->warn("%s don't have a stack at slot %d", army->nodeName(), slot.getNum());
 		return nullptr;
 	}
 	return &army->getStack(slot);
@@ -967,7 +967,7 @@ DLL_LINKAGE void EraseArtifact::applyGs(CGameState *gs)
 	auto slot = al.getSlot();
 	if(slot->locked)
 	{
-		logGlobal->debugStream() << "Erasing locked artifact: " << slot->artifact->artType->Name();
+		logGlobal->debug("Erasing locked artifact: %s", slot->artifact->artType->Name());
 		DisassembledArtifact dis;
 		dis.al.artHolder = al.artHolder;
 		auto aset = al.getHolderArtSet();
@@ -987,12 +987,12 @@ DLL_LINKAGE void EraseArtifact::applyGs(CGameState *gs)
 			}
 		}
 		assert(found && "Failed to determine the assembly this locked artifact belongs to");
-		logGlobal->debugStream() << "Found the corresponding assembly: " << dis.al.getSlot()->artifact->artType->Name();
+		logGlobal->debug("Found the corresponding assembly: %s", dis.al.getSlot()->artifact->artType->Name());
 		dis.applyGs(gs);
 	}
 	else
 	{
-		logGlobal->debugStream() << "Erasing artifact " << slot->artifact->artType->Name();
+		logGlobal->debug("Erasing artifact %s", slot->artifact->artType->Name());
 	}
 	al.removeArtifact();
 }
@@ -1114,7 +1114,7 @@ DLL_LINKAGE void NewTurn::applyGs(CGameState *gs)
 		}
 		if(!hero)
 		{
-			logGlobal->errorStream() << "Hero " << h.id << " not found in NewTurn::applyGs";
+			logGlobal->error("Hero %d not found in NewTurn::applyGs", h.id.getNum());
 			continue;
 		}
 		hero->movement = h.move;
@@ -1313,7 +1313,7 @@ DLL_LINKAGE void BattleTriggerEffect::applyGs(CGameState *gs)
 		st->state.insert(EBattleStackState::FEAR);
 		break;
 	default:
-		logNetwork->warnStream() << "Unrecognized trigger effect type "<< effect;
+		logNetwork->error("Unrecognized trigger effect type %d", effect);
 	}
 }
 
@@ -1571,12 +1571,12 @@ DLL_LINKAGE void SetStackEffect::applyGs(CGameState *gs)
 		if(cumulative || !sta->hasBonus(Selector::source(Bonus::SPELL_EFFECT, spellid).And(Selector::typeSubtype(effect.type, effect.subtype))))
 		{
 			//no such effect or cumulative - add new
-			logBonus->traceStream() << sta->nodeName() << " receives a new bonus: " << effect.Description();
+			logBonus->trace("%s receives a new bonus: %s", sta->nodeName(), effect.Description());
 			sta->addNewBonus(std::make_shared<Bonus>(effect));
 		}
 		else
 		{
-			logBonus->traceStream() << sta->nodeName() << " updated bonus: " << effect.Description();
+			logBonus->trace("%s updated bonus: %s", sta->nodeName(), effect.Description());
 			actualizeEffect(sta, effect);
 		}
 	};
@@ -1592,7 +1592,7 @@ DLL_LINKAGE void SetStackEffect::applyGs(CGameState *gs)
 				processEffect(s, fromEffect, true);
 		}
 		else
-			logNetwork->errorStream() << "Cannot find stack " << id;
+			logNetwork->error("Cannot find stack %d", id);
 	}
 
 	for(auto & para : uniqueBonuses)
@@ -1601,7 +1601,7 @@ DLL_LINKAGE void SetStackEffect::applyGs(CGameState *gs)
 		if(s)
 			processEffect(s, para.second, false);
 		else
-			logNetwork->errorStream() << "Cannot find stack " << para.first;
+			logNetwork->error("Cannot find stack %d", para.first);
 	}
 
 	for(auto & para : cumulativeUniqueBonuses)
@@ -1610,7 +1610,7 @@ DLL_LINKAGE void SetStackEffect::applyGs(CGameState *gs)
 		if(s)
 			processEffect(s, para.second, true);
 		else
-			logNetwork->errorStream() << "Cannot find stack " << para.first;
+			logNetwork->error("Cannot find stack %d", para.first);
 	}
 }
 
@@ -1632,7 +1632,7 @@ DLL_LINKAGE void StacksHealedOrResurrected::applyGs(CGameState *gs)
 
 		if(!changedStack->alive() && !accessibility.accessible(changedStack->position, changedStack))
 		{
-			logNetwork->errorStream() << "Cannot resurrect " << changedStack->nodeName() << " because hex " << changedStack->position << " is occupied!";
+			logNetwork->error("Cannot resurrect %s because hex %d is occupied!", changedStack->nodeName(), changedStack->position.hex);
 			return; //position is already occupied
 		}
 
@@ -1730,14 +1730,18 @@ DLL_LINKAGE std::string CatapultAttack::AttackInfo::toString() const
 					  % destinationTile % static_cast<int>(attackedPart) % static_cast<int>(damageDealt));
 }
 
-DLL_LINKAGE std::ostream & operator<<(std::ostream & out, const CatapultAttack::AttackInfo & attackInfo)
-{
-	return out << attackInfo.toString();
-}
-
 DLL_LINKAGE std::string CatapultAttack::toString() const
 {
-	return boost::str(boost::format("{CatapultAttack: attackedParts '%s', attacker '%d'}") % attackedParts % attacker);
+	std::ostringstream out;
+	out << "[";
+	for(auto it = attackedParts.begin(); it != attackedParts.end(); ++it)
+	{
+		out << it->toString();
+		if(std::prev(attackedParts.end()) != it) out << ", ";
+	}
+	out << "]";
+
+	return boost::str(boost::format("{CatapultAttack: attackedParts '%s', attacker '%d'}") % out.str() % attacker);
 }
 
 DLL_LINKAGE void BattleStacksRemoved::applyGs(CGameState *gs)

+ 13 - 0
lib/ResourceSet.cpp

@@ -86,6 +86,19 @@ bool Res::canAfford(const ResourceSet &res, const ResourceSet &price)
 	return true;
 }
 
+std::string Res::ResourceSet::toString() const
+{
+	std::ostringstream out;
+	out << "[";
+	for(auto it = begin(); it != end(); ++it)
+	{
+		out << *it;
+		if(std::prev(end()) != it) out << ", ";
+	}
+	out << "]";
+	return out.str();
+}
+
 bool Res::ResourceSet::nziterator::valid()
 {
 	return cur.resType < GameConstants::RESOURCE_QUANTITY && cur.resVal;

+ 4 - 2
lib/ResourceSet.h

@@ -134,6 +134,8 @@ namespace Res
 		DLL_LINKAGE bool canAfford(const ResourceSet &price) const;
 		DLL_LINKAGE bool canBeAfforded(const ResourceSet &res) const;
 
+		DLL_LINKAGE std::string toString() const;
+
 		//special iterator of iterating over non-zero resources in set
 		class DLL_LINKAGE nziterator
 		{
@@ -154,9 +156,9 @@ namespace Res
 			const ResEntry* operator->() const;
 
 		};
-	};
 
-	using ::operator<<;
+
+	};
 }
 
 typedef Res::ResourceSet TResources;

+ 3 - 3
lib/StartInfo.h

@@ -33,7 +33,7 @@ struct PlayerSettings
 		 heroPortrait; //-1 if default, else ID
 
 	std::string heroName;
-	PlayerColor color; //from 0 - 
+	PlayerColor color; //from 0 -
 	enum EHandicap {NO_HANDICAP, MILD, SEVERE};
 	EHandicap handicap;//0-no, 1-mild, 2-severe
 	TeamID team;
@@ -60,7 +60,7 @@ struct PlayerSettings
 	PlayerSettings() : bonus(RANDOM), castle(NONE), hero(RANDOM), heroPortrait(RANDOM),
 		color(0), handicap(NO_HANDICAP), team(0), playerID(PLAYER_AI), compOnly(false)
 	{
-		
+
 	}
 };
 
@@ -89,7 +89,7 @@ struct StartInfo
 	{
 		if(playerInfos.find(no) != playerInfos.end())
 			return playerInfos[no];
-		logGlobal->errorStream() << "Cannot find info about player " << no <<". Throwing...";
+		logGlobal->error("Cannot find info about player %s. Throwing...", no.getStr());
 		throw std::runtime_error("Cannot find info about player");
 	}
 	const PlayerSettings & getIthPlayersSettings(PlayerColor no) const

+ 1 - 0
lib/VCMI_Lib.h

@@ -9,6 +9,7 @@
  */
 #pragma once
 
+class CConsoleHandler;
 class CArtHandler;
 class CHeroHandler;
 class CCreatureHandler;

+ 3 - 3
lib/battle/BattleInfo.cpp

@@ -349,7 +349,7 @@ BattleInfo * BattleInfo::setupBattle(int3 tile, ETerrainType terrain, BFieldType
 		try
 		{
 			while(tilesToBlock > 0)
-			{				
+			{
 				auto tileAccessibility = curB->getAccesibility();
 				const int obid = obidgen.getSuchNumber(appropriateUsualObstacle);
 				const CObstacleInfo &obi = VLC->heroh->obstacles[obid];
@@ -644,7 +644,7 @@ const CGHeroInstance * BattleInfo::getHero(PlayerColor player) const
 		if(sides[i].color == player)
 			return sides[i].hero;
 
-	logGlobal->errorStream() << "Player " << player << " is not in battle!";
+	logGlobal->error("Player %s is not in battle!", player.getStr());
 	return nullptr;
 }
 
@@ -659,7 +659,7 @@ ui8 BattleInfo::whatSide(PlayerColor player) const
 		if(sides[i].color == player)
 			return i;
 
-	logGlobal->warnStream() << "BattleInfo::whatSide: Player " << player << " is not in battle!";
+	logGlobal->warn("BattleInfo::whatSide: Player %s is not in battle!", player.getStr());
 	return -1;
 }
 

+ 1 - 1
lib/battle/CBattleInfoCallback.cpp

@@ -218,7 +218,7 @@ SpellID CBattleInfoCallback::battleGetRandomStackSpell(CRandomGenerator & rand,
 		return getRandomCastedSpell(rand, stack); //caster
 		break;
 	default:
-		logGlobal->errorStream() << "Incorrect mode of battleGetRandomSpell (" << mode <<")";
+		logGlobal->error("Incorrect mode of battleGetRandomSpell (%d)", static_cast<int>(mode));
 		return SpellID::NONE;
 	}
 }

+ 7 - 7
lib/battle/CBattleInfoEssentials.cpp

@@ -133,7 +133,7 @@ BattlePerspective::BattlePerspective CBattleInfoEssentials::battleGetMySide() co
 	if(*player == getBattle()->sides[1].color)
 		return BattlePerspective::RIGHT_SIDE;
 
-	logGlobal->errorStream() << "Cannot find player " << *player << " in battle!";
+	logGlobal->error("Cannot find player %s in battle!", player->getStr());
 	return BattlePerspective::INVALID;
 }
 
@@ -182,13 +182,13 @@ const CGHeroInstance * CBattleInfoEssentials::battleGetFightingHero(ui8 side) co
 	RETURN_IF_NOT_BATTLE(nullptr);
 	if(side > 1)
 	{
-		logGlobal->errorStream() << "FIXME: " <<  __FUNCTION__ << " wrong argument!";
+		logGlobal->error("FIXME: %s wrong argument!", __FUNCTION__);
 		return nullptr;
 	}
 
 	if(!battleDoWeKnowAbout(side))
 	{
-		logGlobal->errorStream() << "FIXME: " <<  __FUNCTION__ << " access check ";
+		logGlobal->error("FIXME: %s access check ", __FUNCTION__);
 		return nullptr;
 	}
 
@@ -200,12 +200,12 @@ const CArmedInstance * CBattleInfoEssentials::battleGetArmyObject(ui8 side) cons
 	RETURN_IF_NOT_BATTLE(nullptr);
 	if(side > 1)
 	{
-		logGlobal->errorStream() << "FIXME: " <<  __FUNCTION__ << " wrong argument!";
+		logGlobal->error("FIXME: %s wrong argument!", __FUNCTION__);
 		return nullptr;
 	}
 	if(!battleDoWeKnowAbout(side))
 	{
-		logGlobal->errorStream() << "FIXME: " <<  __FUNCTION__ << " access check ";
+		logGlobal->error("FIXME: %s access check!", __FUNCTION__);
 		return nullptr;
 	}
 	return getBattle()->sides[side].armyObject;
@@ -216,7 +216,7 @@ InfoAboutHero CBattleInfoEssentials::battleGetHeroInfo(ui8 side) const
 	auto hero = getBattle()->sides[side].hero;
 	if(!hero)
 	{
-		logGlobal->warnStream() << __FUNCTION__ << ": side " << (int)side << " does not have hero!";
+		logGlobal->warn("%s: side %d does not have hero!", __FUNCTION__, static_cast<int>(side));
 		return InfoAboutHero();
 	}
 	InfoAboutHero::EInfoLevel infoLevel = battleDoWeKnowAbout(side) ? InfoAboutHero::EInfoLevel::DETAILED : InfoAboutHero::EInfoLevel::BASIC;
@@ -267,7 +267,7 @@ BattleSideOpt CBattleInfoEssentials::playerToSide(PlayerColor player) const
 	RETURN_IF_NOT_BATTLE(boost::none);
 	int ret = vstd::find_pos_if(getBattle()->sides, [=](const SideInBattle &side){ return side.color == player; });
 	if(ret < 0)
-		logGlobal->warnStream() << "Cannot find side for player " << player;
+		logGlobal->warn("Cannot find side for player %s", player.getStr());
 
 	return BattleSideOpt(ret);
 }

+ 1 - 1
lib/battle/CCallbackBase.h

@@ -10,7 +10,7 @@
 #pragma once
 #include "../GameConstants.h"
 
-#define RETURN_IF_NOT_BATTLE(X) if(!duringBattle()) {logGlobal->errorStream() << __FUNCTION__ << " called when no battle!"; return X; }
+#define RETURN_IF_NOT_BATTLE(X) if(!duringBattle()) {logGlobal->error("%s called when no battle!", __FUNCTION__); return X; }
 
 class CGameState;
 struct BattleInfo;

+ 1 - 1
lib/filesystem/AdapterLoaders.cpp

@@ -130,7 +130,7 @@ std::unordered_set<ResourceID> CFilesystemList::getFilteredFiles(std::function<b
 
 bool CFilesystemList::createResource(std::string filename, bool update)
 {
-	logGlobal->traceStream()<< "Creating " << filename;
+	logGlobal->trace("Creating %s", filename);
 	for (auto & loader : boost::adaptors::reverse(loaders))
 	{
 		if (writeableLoaders.count(loader.get()) != 0                       // writeable,

+ 2 - 2
lib/filesystem/CFilesystemLoader.cpp

@@ -20,7 +20,7 @@ CFilesystemLoader::CFilesystemLoader(std::string _mountPoint, bfs::path baseDire
     mountPoint(std::move(_mountPoint)),
     fileList(listFiles(mountPoint, depth, initial))
 {
-	logGlobal->traceStream() << "File system loaded, " << fileList.size() << " files found";
+	logGlobal->trace("File system loaded, %d files found", fileList.size());
 }
 
 std::unique_ptr<CInputStream> CFilesystemLoader::load(const ResourceID & resourceName) const
@@ -76,7 +76,7 @@ bool CFilesystemLoader::createResource(std::string filename, bool update)
 
 	if (!boost::iequals(mountPoint, filename.substr(0, mountPoint.size())))
 	{
-		logGlobal->traceStream() << "Can't create file: wrong mount point: " << mountPoint;
+		logGlobal->trace("Can't create file: wrong mount point: %s", mountPoint);
 		return false;
 	}
 

+ 2 - 2
lib/filesystem/CZipLoader.cpp

@@ -57,7 +57,7 @@ CZipLoader::CZipLoader(const std::string & mountPoint, const boost::filesystem::
     mountPoint(mountPoint),
     files(listFiles(mountPoint, archive))
 {
-	logGlobal->traceStream() << "Zip archive loaded, " << files.size() << " files found";
+	logGlobal->trace("Zip archive loaded, %d files found", files.size());
 }
 
 std::unordered_map<ResourceID, unz64_file_pos> CZipLoader::listFiles(const std::string & mountPoint, const boost::filesystem::path & archive)
@@ -67,7 +67,7 @@ std::unordered_map<ResourceID, unz64_file_pos> CZipLoader::listFiles(const std::
 	unzFile file = unzOpen2_64(archive.c_str(), &zlibApi);
 
 	if(file == nullptr)
-		logGlobal->errorStream() << archive << " failed to open";
+		logGlobal->error("%s failed to open", archive.string());
 
 	if (unzGoToFirstFile(file) == UNZ_OK)
 	{

+ 2 - 2
lib/filesystem/CZipSaver.cpp

@@ -64,7 +64,7 @@ CZipOutputStream::~CZipOutputStream()
 {
 	int status = zipCloseFileInZip(handle);
 	if (status != ZIP_OK)
-		logGlobal->errorStream() << "CZipOutputStream: stream finalize failed: "<<status;
+		logGlobal->error("CZipOutputStream: stream finalize failed: %d", static_cast<int>(status));
 	owner->activeStream = nullptr;
 }
 
@@ -104,7 +104,7 @@ CZipSaver::~CZipSaver()
 	{
 		int status = zipClose(handle, nullptr);
 		if (status != ZIP_OK)
-			logGlobal->errorStream() << "CZipSaver: archive finalize failed: "<<status;
+			logGlobal->error("CZipSaver: archive finalize failed: %d", static_cast<int>(status));
 	}
 
 }

+ 2 - 2
lib/filesystem/Filesystem.cpp

@@ -48,7 +48,7 @@ void CFilesystemGenerator::loadConfig(const JsonNode & config)
 		for(auto & entry : mountPoint.second.Vector())
 		{
 			CStopWatch timer;
-			logGlobal->debugStream() << "\t\tLoading resource at " << prefix + entry["path"].String();
+			logGlobal->trace("\t\tLoading resource at %s%s", prefix, entry["path"].String());
 
 			auto map = genFunctorMap();
 			auto typeName = entry["type"].String();
@@ -57,7 +57,7 @@ void CFilesystemGenerator::loadConfig(const JsonNode & config)
 			if (functor != map.end())
 			{
 				functor->second(mountPoint.first, entry);
-				logGlobal->debugStream() << "Resource loaded in " << timer.getDiff() << " ms.";
+				logGlobal->trace("Resource loaded in %d ms", timer.getDiff());
 			}
 			else
 			{

+ 2 - 2
lib/filesystem/MinizipExtensions.cpp

@@ -169,7 +169,7 @@ int ZCALLBACK CProxyIOApi::errorFileProxy(voidpf opaque, voidpf stream)
 
 CInputOutputStream * CProxyIOApi::openFile(const boost::filesystem::path & filename, int mode)
 {
-	logGlobal->traceStream() << "CProxyIOApi: stream opened for " <<filename.string() <<" with mode "<<mode;
+	logGlobal->trace("CProxyIOApi: stream opened for %s with mode %d", filename.string(), mode);
 
 	data->seek(0);
 	return data;
@@ -204,7 +204,7 @@ zlib_filefunc64_def CProxyROIOApi::getApiStructure()
 
 CInputStream * CProxyROIOApi::openFile(const boost::filesystem::path& filename, int mode)
 {
-	logGlobal->traceStream() << "CProxyROIOApi: stream opened for " <<filename.string() <<" with mode "<<mode;
+	logGlobal->trace("CProxyROIOApi: stream opened for %s with mode %d", filename.string(), mode);
 
 	data->seek(0);
 	return data;

+ 2 - 11
lib/int3.h

@@ -54,7 +54,7 @@ public:
 		z -= i.z;
 		return *this;
 	}
-	
+
 	//increases all coordinates by given number
 	int3 & operator+=(const si32 i)
 	{
@@ -116,7 +116,7 @@ public:
 	}
 
 	//returns "(x y z)" string
-	std::string operator ()() const //Change to int3::toString()?
+	std::string toString() const
 	{
 		std::string result("(");
 		result += boost::lexical_cast<std::string>(x); result += ' ';
@@ -145,15 +145,6 @@ public:
 	}
 };
 
-inline std::ostream & operator<<(std::ostream & str, const int3 & sth)
-{
-	return str << sth.x << ' ' << sth.y << ' ' << sth.z;
-}
-inline std::istream & operator>>(std::istream & str, int3 & dest)
-{
-	return str >> dest.x >> dest.y >> dest.z;
-}
-
 //Why not normal function?
 struct ShashInt3
 {

+ 2 - 1
lib/logging/CBasicLogConfigurator.cpp

@@ -9,6 +9,7 @@
  */
 #include "StdInc.h"
 #include "CBasicLogConfigurator.h"
+#include "CLogger.h"
 
 #include "../CConfigHandler.h"
 
@@ -111,7 +112,7 @@ ELogLevel::ELogLevel CBasicLogConfigurator::getLogLevel(const std::string & leve
 		{"warn", ELogLevel::WARN},
 		{"error", ELogLevel::ERROR},
 	};
-	
+
 	const auto & levelPair = levelMap.find(level);
 	if(levelPair != levelMap.end())
 		return levelPair->second;

+ 25 - 31
lib/logging/CLogger.cpp

@@ -32,6 +32,25 @@ namespace ELogLevel
 }
 #endif
 
+namespace vstd
+{
+
+CLoggerBase::~CLoggerBase() = default;
+
+
+CTraceLogger::CTraceLogger(const CLoggerBase * logger, const std::string & beginMessage, const std::string & endMessage)
+	: logger(logger), endMessage(endMessage)
+{
+	logger->trace(beginMessage);
+}
+
+CTraceLogger::~CTraceLogger()
+{
+	logger->trace(endMessage);
+}
+
+}//namespace vstd
+
 const std::string CLoggerDomain::DOMAIN_GLOBAL = "global";
 
 CLoggerDomain::CLoggerDomain(std::string name) : name(std::move(name))
@@ -55,27 +74,15 @@ bool CLoggerDomain::isGlobalDomain() const { return name == DOMAIN_GLOBAL; }
 
 const std::string& CLoggerDomain::getName() const { return name; }
 
-CLoggerStream::CLoggerStream(const CLogger & logger, ELogLevel::ELogLevel level) : logger(logger), level(level), sbuffer(nullptr) {}
-
-CLoggerStream::~CLoggerStream()
-{
-	if(sbuffer)
-	{
-		logger.log(level, sbuffer->str());
-		delete sbuffer;
-		sbuffer = nullptr;
-	}
-}
-
 boost::recursive_mutex CLogger::smx;
 boost::recursive_mutex CLogManager::smx;
 
-DLL_LINKAGE CLogger * logGlobal = CLogger::getGlobalLogger();
+DLL_LINKAGE vstd::CLoggerBase * logGlobal = CLogger::getGlobalLogger();
 
-DLL_LINKAGE CLogger * logBonus = CLogger::getLogger(CLoggerDomain("bonus"));
-DLL_LINKAGE CLogger * logNetwork = CLogger::getLogger(CLoggerDomain("network"));
-DLL_LINKAGE CLogger * logAi = CLogger::getLogger(CLoggerDomain("ai"));
-DLL_LINKAGE CLogger * logAnim = CLogger::getLogger(CLoggerDomain("animation"));
+DLL_LINKAGE vstd::CLoggerBase * logBonus = CLogger::getLogger(CLoggerDomain("bonus"));
+DLL_LINKAGE vstd::CLoggerBase * logNetwork = CLogger::getLogger(CLoggerDomain("network"));
+DLL_LINKAGE vstd::CLoggerBase * logAi = CLogger::getLogger(CLoggerDomain("ai"));
+DLL_LINKAGE vstd::CLoggerBase * logAnim = CLogger::getLogger(CLoggerDomain("animation"));
 
 CLogger * CLogger::getLogger(const CLoggerDomain & domain)
 {
@@ -117,12 +124,6 @@ CLogger::CLogger(const CLoggerDomain & domain) : domain(domain)
 	}
 }
 
-CLoggerStream CLogger::traceStream() const { return CLoggerStream(*this, ELogLevel::TRACE); }
-CLoggerStream CLogger::debugStream() const { return CLoggerStream(*this, ELogLevel::DEBUG); }
-CLoggerStream CLogger::infoStream() const { return CLoggerStream(*this, ELogLevel::INFO); }
-CLoggerStream CLogger::warnStream() const { return CLoggerStream(*this, ELogLevel::WARN); }
-CLoggerStream CLogger::errorStream() const { return CLoggerStream(*this, ELogLevel::ERROR); }
-
 void CLogger::log(ELogLevel::ELogLevel level, const std::string & message) const
 {
 	if(getEffectiveLevel() <= level)
@@ -189,13 +190,6 @@ void CLogger::clearTargets()
 bool CLogger::isDebugEnabled() const { return getEffectiveLevel() <= ELogLevel::DEBUG; }
 bool CLogger::isTraceEnabled() const { return getEffectiveLevel() <= ELogLevel::TRACE; }
 
-CTraceLogger::CTraceLogger(const CLogger * logger, const std::string & beginMessage, const std::string & endMessage)
-	: logger(logger), endMessage(endMessage)
-{
-	logger->trace(beginMessage);
-}
-CTraceLogger::~CTraceLogger() { logger->trace(std::move(endMessage)); }
-
 CLogManager & CLogManager::get()
 {
 	TLockGuardRec _(smx);
@@ -203,7 +197,7 @@ CLogManager & CLogManager::get()
 	return instance;
 }
 
-CLogManager::CLogManager() { }
+CLogManager::CLogManager() = default;
 CLogManager::~CLogManager()
 {
 	for(auto & i : loggers)

+ 2 - 68
lib/logging/CLogger.h

@@ -42,29 +42,6 @@ private:
 	std::string name;
 };
 
-/// The class CLoggerStream provides a stream-like way of logging messages.
-class DLL_LINKAGE CLoggerStream
-{
-public:
-	CLoggerStream(const CLogger & logger, ELogLevel::ELogLevel level);
-	~CLoggerStream();
-
-	template<typename T>
-	CLoggerStream & operator<<(const T & data)
-	{
-		if(!sbuffer)
-			sbuffer = new std::stringstream(std::ios_base::out);
-
-		(*sbuffer) << data;
-
-		return *this;
-	}
-
-private:
-	const CLogger & logger;
-	ELogLevel::ELogLevel level;
-	std::stringstream * sbuffer;
-};
 
 /// The logger is used to log messages to certain targets of a specific domain/name.
 /// It is thread-safe and can be used concurrently by several threads.
@@ -79,13 +56,6 @@ public:
 	static CLogger * getLogger(const CLoggerDomain & domain);
 	static CLogger * getGlobalLogger();
 
-	/// Log streams for various log levels
-	CLoggerStream traceStream() const;
-	CLoggerStream debugStream() const;
-	CLoggerStream infoStream() const;
-	CLoggerStream warnStream() const;
-	CLoggerStream errorStream() const;
-
 	void log(ELogLevel::ELogLevel level, const std::string & message) const override;
 	void log(ELogLevel::ELogLevel level, const boost::format & fmt) const override;
 
@@ -94,8 +64,8 @@ public:
 
 	/// Returns true if a debug/trace log message will be logged, false if not.
 	/// Useful if performance is important and concatenating the log message is a expensive task.
-	bool isDebugEnabled() const;
-	bool isTraceEnabled() const;
+	bool isDebugEnabled() const override;
+	bool isTraceEnabled() const override;
 
 private:
 	explicit CLogger(const CLoggerDomain & domain);
@@ -110,42 +80,6 @@ private:
 	static boost::recursive_mutex smx;
 };
 
-extern DLL_LINKAGE CLogger * logGlobal;
-extern DLL_LINKAGE CLogger * logBonus;
-extern DLL_LINKAGE CLogger * logNetwork;
-extern DLL_LINKAGE CLogger * logAi;
-extern DLL_LINKAGE CLogger * logAnim;
-
-/// RAII class for tracing the program execution.
-/// It prints "Leaving function XYZ" automatically when the object gets destructed.
-class DLL_LINKAGE CTraceLogger : boost::noncopyable
-{
-public:
-	CTraceLogger(const CLogger * logger, const std::string & beginMessage, const std::string & endMessage);
-	~CTraceLogger();
-
-private:
-	const CLogger * logger;
-	std::string endMessage;
-};
-
-/// Macros for tracing the control flow of the application conveniently. If the LOG_TRACE macro is used it should be
-/// the first statement in the function. Logging traces via this macro have almost no impact when the trace is disabled.
-///
-#define RAII_TRACE(logger, onEntry, onLeave)			\
-	std::unique_ptr<CTraceLogger> ctl00;						\
-	if(logger->isTraceEnabled())						\
-		ctl00 = make_unique<CTraceLogger>(logger, onEntry, onLeave);
-
-#define LOG_TRACE(logger) RAII_TRACE(logger,								\
-		boost::str(boost::format("Entering %s.") % BOOST_CURRENT_FUNCTION),	\
-		boost::str(boost::format("Leaving %s.") % BOOST_CURRENT_FUNCTION))
-
-
-#define LOG_TRACE_PARAMS(logger, formatStr, params) RAII_TRACE(logger,		\
-		boost::str(boost::format("Entering %s: " + std::string(formatStr) + ".") % BOOST_CURRENT_FUNCTION % params), \
-		boost::str(boost::format("Leaving %s.") % BOOST_CURRENT_FUNCTION))
-
 /* ---------------------------------------------------------------------------- */
 /* Implementation/Detail classes, Private API */
 /* ---------------------------------------------------------------------------- */

+ 13 - 26
lib/mapObjects/CGHeroInstance.cpp

@@ -48,16 +48,14 @@ static int lowestSpeed(const CGHeroInstance * chi)
 {
 	if(!chi->stacksCount())
 	{
-		logGlobal->errorStream() << "Error! Hero " << chi->id.getNum() << " ("<<chi->name<<") has no army!";
+		logGlobal->error("Hero %d (%s) has no army!", chi->id.getNum(), chi->name);
 		return 20;
 	}
 	auto i = chi->Slots().begin();
 	//TODO? should speed modifiers (eg from artifacts) affect hero movement?
 	int ret = (i++)->second->valOfBonuses(Bonus::STACKS_SPEED);
-	for (;i!=chi->Slots().end();i++)
-	{
+	for(; i != chi->Slots().end(); i++)
 		ret = std::min(ret, i->second->valOfBonuses(Bonus::STACKS_SPEED));
-	}
 	return ret;
 }
 
@@ -81,7 +79,7 @@ ui32 CGHeroInstance::getTileCost(const TerrainTile &dest, const TerrainTile &fro
 			ret = 50;
 			break;
 		default:
-			logGlobal->errorStream() << "Unknown road type: " << road << "... Something wrong!";
+			logGlobal->error("Unknown road type: %d", road);
 			break;
 		}
 	}
@@ -172,7 +170,7 @@ void CGHeroInstance::setSecSkillLevel(SecondarySkill which, int val, bool abs)
 
 				if(elem.second > 3) //workaround to avoid crashes when same sec skill is given more than once
 				{
-					logGlobal->warnStream() << "Warning: Skill " << which << " increased over limit! Decreasing to Expert.";
+					logGlobal->warn("Skill %d increased over limit! Decreasing to Expert.", static_cast<int>(which.toEnum()));
 					elem.second = 3;
 				}
 				updateSkill(which, elem.second); //when we know final value
@@ -377,7 +375,7 @@ void CGHeroInstance::initArmy(CRandomGenerator & rand, IArmyDescriptor * dst)
 				if(!getArt(slot))
 					putArtifact(slot, CArtifactInstance::createNewArtifactInstance(aid));
 				else
-					logGlobal->warnStream() << "Hero " << name << " already has artifact at " << slot << ", omitting giving " << aid;
+					logGlobal->warn("Hero %s already has artifact at %d, omitting giving artifact %d", name, slot.toEnum(), aid.toEnum());
 			}
 			else
 			{
@@ -529,18 +527,6 @@ void CGHeroInstance::initObj(CRandomGenerator & rand)
 
 					const CCreature &specCreature = *VLC->creh->creatures[spec.additionalinfo]; //creature in which we have specialty
 
-					//int creLevel = specCreature.level;
-					//if(!creLevel)
-					//{
-					//	if(spec.additionalinfo == 146)
-					//		creLevel = 5; //treat ballista as 5-level
-					//	else
-					//	{
-					//        logGlobal->warnStream() << "Warning: unknown level of " << specCreature.namePl;
-					//		continue;
-					//	}
-					//}
-
 					//bonus->additionalInfo = spec.additionalinfo; //creature id, should not be used again - this works only with limiter
 					bonus->limiter.reset(new CCreatureTypeLimiter (specCreature, true)); //with upgrades
 					bonus->type = Bonus::PRIMARY_SKILL;
@@ -683,7 +669,8 @@ void CGHeroInstance::initObj(CRandomGenerator & rand)
 				hs->addNewBonus(bonus);
 				break;
 			default:
-				logGlobal->warnStream() << "Unexpected hero specialty " << type;
+				logGlobal->warn("Unexpected hero %s specialty %d", type->name, spec.type);
+				break;
 		}
 	}
 	specialty.push_back(hs); //will it work?
@@ -1417,7 +1404,7 @@ PrimarySkill::PrimarySkill CGHeroInstance::nextPrimarySkill(CRandomGenerator & r
 		}
 	}
 
-	logGlobal->traceStream() << "The hero gets the primary skill " << primarySkill << " with a probability of " << randomValue << "%.";
+	logGlobal->trace("The hero gets the primary skill %d with a probability of %d %%.", primarySkill, randomValue);
 	return static_cast<PrimarySkill::PrimarySkill>(primarySkill);
 }
 
@@ -1683,7 +1670,7 @@ void CGHeroInstance::serializeCommonOptions(JsonSerializeFormat & handler)
 				const si32 rawId = p.first.num;
 
 				if(rawId < 0 || rawId >= GameConstants::SKILL_QUANTITY)
-					logGlobal->errorStream() << "Invalid secondary skill " << rawId;
+					logGlobal->error("Invalid secondary skill %d", rawId);
 
 				handler.serializeEnum(NSecondarySkill::names[rawId], p.second, 0, NSecondarySkill::levels);
 			}
@@ -1703,20 +1690,20 @@ void CGHeroInstance::serializeCommonOptions(JsonSerializeFormat & handler)
 		{
 			for(const auto & p : skillMap.Struct())
 			{
-				const std::string id = p.first;
+				const std::string skillId = p.first;
 				const std::string levelId =  p.second.String();
 
-				const int rawId = vstd::find_pos(NSecondarySkill::names, id);
+				const int rawId = vstd::find_pos(NSecondarySkill::names, skillId);
 				if(rawId < 0)
 				{
-					logGlobal->errorStream() << "Invalid secondary skill " << id;
+					logGlobal->error("Invalid secondary skill %s", skillId);
 					continue;
 				}
 
 				const int level = vstd::find_pos(NSecondarySkill::levels, levelId);
 				if(level < 0)
 				{
-					logGlobal->errorStream() << "Invalid secondary skill level" << levelId;
+					logGlobal->error("Invalid secondary skill level%s", levelId);
 					continue;
 				}
 

+ 1 - 1
lib/mapObjects/CGMarket.cpp

@@ -179,7 +179,7 @@ const IMarket * IMarket::castFrom(const CGObjectInstance *obj, bool verbose)
 		return static_cast<const CGUniversity*>(obj);
 	default:
 		if(verbose)
-			logGlobal->errorStream() << "Cannot cast to IMarket object with ID " << obj->ID;
+			logGlobal->error("Cannot cast to IMarket object with ID %d", obj->ID);
 		return nullptr;
 	}
 }

+ 5 - 5
lib/mapObjects/CGPandoraBox.cpp

@@ -427,20 +427,20 @@ void CGPandoraBox::serializeJsonOptions(JsonSerializeFormat & handler)
 
 		for(const auto & p : skillMap.Struct())
 		{
-			const std::string id = p.first;
-			const std::string levelId =  p.second.String();
+			const std::string skillName = p.first;
+			const std::string levelId = p.second.String();
 
-			const int rawId = vstd::find_pos(NSecondarySkill::names, id);
+			const int rawId = vstd::find_pos(NSecondarySkill::names, skillName);
 			if(rawId < 0)
 			{
-				logGlobal->errorStream() << "Invalid secondary skill " << id;
+				logGlobal->error("Invalid secondary skill %s", skillName);
 				continue;
 			}
 
 			const int level = vstd::find_pos(NSecondarySkill::levels, levelId);
 			if(level < 0)
 			{
-				logGlobal->errorStream() << "Invalid secondary skill level" << levelId;
+				logGlobal->error("Invalid secondary skill level %s", levelId);
 				continue;
 			}
 

+ 6 - 6
lib/mapObjects/CGTownInstance.cpp

@@ -693,20 +693,20 @@ void CGTownInstance::onHeroVisit(const CGHeroInstance * h) const
 	}
 	else
 	{
-		logGlobal->errorStream() << h->name << " visits allied town of " << name << " from different pos?";
+		logGlobal->error("%s visits allied town of %s from different pos?", h->name, name);
 	}
 }
 
 void CGTownInstance::onHeroLeave(const CGHeroInstance * h) const
 {
 	//FIXME: find out why this issue appears on random maps
-	if (visitingHero == h)
+	if(visitingHero == h)
 	{
 		cb->stopHeroVisitCastle(this, h);
-		//logGlobal->warnStream() << h->name << " correctly left town " << name;
+		logGlobal->trace("%s correctly left town %s", h->name, name);
 	}
 	else
-		logGlobal->warnStream() << "Warning, " << h->name << " tries to leave the town " << name << " but hero is not inside.";
+		logGlobal->warn("Warning, %s tries to leave the town %s but hero is not inside.", h->name, name);
 }
 
 std::string CGTownInstance::getObjectName() const
@@ -1315,8 +1315,8 @@ void CGTownInstance::addHeroToStructureVisitors( const CGHeroInstance *h, si32 s
 	else
 	{
 		//should never ever happen
-		logGlobal->errorStream() << "Cannot add hero " << h->name << " to visitors of structure #" << structureInstanceID;
-		assert(0);
+		logGlobal->error("Cannot add hero %s to visitors of structure # %d", h->name, structureInstanceID);
+		throw std::runtime_error("internal error");
 	}
 }
 

+ 1 - 2
lib/mapObjects/CGTownInstance.h

@@ -218,8 +218,7 @@ public:
 		{
 			if(!town->buildings.count(building) ||  !town->buildings.at(building))
 			{
-				logGlobal->errorStream() << boost::format("#1444-like issue in CGTownInstance::serialize. From town %s at %s removing the bogus builtBuildings item %s")
-					% name % pos % building;
+				logGlobal->error("#1444-like issue in CGTownInstance::serialize. From town %s at %s removing the bogus builtBuildings item %s", name, pos.toString(), building);
 				return true;
 			}
 			return false;

+ 10 - 10
lib/mapObjects/CObjectClassesHandler.cpp

@@ -156,7 +156,7 @@ void CObjectClassesHandler::loadObjectEntry(const std::string & identifier, cons
 {
 	if (!handlerConstructors.count(obj->handlerName))
 	{
-		logGlobal->errorStream() << "Handler with name " << obj->handlerName << " was not found!";
+		logGlobal->error("Handler with name %s was not found!", obj->handlerName);
 		return;
 	}
 
@@ -183,7 +183,7 @@ void CObjectClassesHandler::loadObjectEntry(const std::string & identifier, cons
 		legacyTemplates.erase(range.first, range.second);
 	}
 
-	logGlobal->debugStream() << "Loaded object " << obj->identifier << "(" << obj->id << ")" << ":" << convertedId << "(" << id << ")" ;
+	logGlobal->debug("Loaded object %s(%d):%s(%d)", obj->identifier, obj->id, convertedId, id);
 	assert(!obj->subObjects.count(id)); // DO NOT override
 	obj->subObjects[id] = handler;
 	obj->subIds[convertedId] = id;
@@ -256,7 +256,7 @@ TObjectTypeHandler CObjectClassesHandler::getHandlerFor(si32 type, si32 subtype)
 		if (objects.at(type)->subObjects.count(subtype))
 			return objects.at(type)->subObjects.at(subtype);
 	}
-	logGlobal->errorStream() << "Failed to find object of type " << type << ":" << subtype;
+	logGlobal->error("Failed to find object of type %d:%d", type, subtype);
 	throw std::runtime_error("Object type handler not found");
 }
 
@@ -268,7 +268,7 @@ TObjectTypeHandler CObjectClassesHandler::getHandlerFor(std::string type, std::s
 		si32 subId = objects.at(id.get())->subIds.at(subtype);
 		return objects.at(id.get())->subObjects.at(subId);
 	}
-	logGlobal->errorStream() << "Failed to find object of type " << type << ":" << subtype;
+	logGlobal->error("Failed to find object of type %s:%s", type, subtype);
 	throw std::runtime_error("Object type handler not found");
 }
 
@@ -308,13 +308,13 @@ void CObjectClassesHandler::beforeValidate(JsonNode & object)
 
 void CObjectClassesHandler::afterLoadFinalization()
 {
-	for (auto entry : objects)
+	for(auto entry : objects)
 	{
-		for (auto obj : entry.second->subObjects)
+		for(auto obj : entry.second->subObjects)
 		{
 			obj.second->afterLoadFinalization();
-			if (obj.second->getTemplates().empty())
-				logGlobal->warnStream() << "No templates found for " << entry.first << ":" << obj.first;
+			if(obj.second->getTemplates().empty())
+				logGlobal->warn("No templates found for %d:%d", entry.first, obj.first);
 		}
 	}
 
@@ -322,7 +322,7 @@ void CObjectClassesHandler::afterLoadFinalization()
 	auto& portalVec = objects[Obj::MONOLITH_TWO_WAY]->subObjects;
 	size_t portalCount = portalVec.size();
 	size_t currentIndex = portalCount;
-	while (portalVec.size() < 100)
+	while(portalVec.size() < 100)
 	{
 		portalVec[currentIndex] = portalVec[currentIndex % portalCount];
 		currentIndex++;
@@ -333,7 +333,7 @@ std::string CObjectClassesHandler::getObjectName(si32 type) const
 {
 	if (objects.count(type))
 		return objects.at(type)->name;
-	logGlobal->errorStream() << "Access to non existing object of type "  << type;
+	logGlobal->error("Access to non existing object of type %d", type);
 	return "";
 }
 

+ 2 - 3
lib/mapObjects/CObjectHandler.cpp

@@ -196,8 +196,7 @@ void CGObjectInstance::setType(si32 ID, si32 subID)
 	auto handler = VLC->objtypeh->getHandlerFor(ID, subID);
 	if(!handler)
 	{
-		logGlobal->errorStream() << boost::format(
-			  "Unknown object type %d:%d at %s") % ID % subID % visitablePos();
+		logGlobal->error("Unknown object type %d:%d at %s", ID, subID, visitablePos().toString());
 		return;
 	}
 	if(!handler->getTemplates(tile.terType).empty())
@@ -434,7 +433,7 @@ void IBoatGenerator::getProblemText(MetaString &out, const CGHeroInstance *visit
 			out.addTxt(MetaString::ADVOB_TXT, 189);
 		break;
 	case NO_WATER:
-		logGlobal->errorStream() << "Shipyard without water!!! " << o->pos << "\t" << o->id;
+		logGlobal->error("Shipyard without water! %s \t %d", o->pos.toString(), o->id.getNum());
 		return;
 	}
 }

+ 1 - 1
lib/mapObjects/CObjectHandler.h

@@ -58,7 +58,7 @@ public:
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
-		logGlobal->errorStream() << "IObjectInterface serialized, unexpected, should not happen!";
+		logGlobal->error("IObjectInterface serialized, unexpected, should not happen!");
 	}
 };
 

+ 1 - 1
lib/mapObjects/CQuest.cpp

@@ -966,7 +966,7 @@ void CGSeerHut::serializeJsonOptions(JsonSerializeFormat & handler)
 
 		if(it == REWARD_RMAP.end())
 		{
-			logGlobal->errorStream() << instanceName << ": invalid metatype in reward item " << fullIdentifier;
+			logGlobal->error("%s: invalid metatype in reward item %s", instanceName, fullIdentifier);
 			return;
 		}
 		else

+ 4 - 4
lib/mapObjects/CRewardableObject.cpp

@@ -79,7 +79,7 @@ std::vector<ui32> CRewardableObject::getAvailableRewards(const CGHeroInstance *
 		if((visit.limiter.numOfGrants == 0 || visit.numOfGrants < visit.limiter.numOfGrants) // reward has unlimited uses or some are still available
 			&& visit.limiter.heroAllowed(hero))
 		{
-			logGlobal->debugStream() << "Reward " << i << " is allowed";
+			logGlobal->trace("Reward %d is allowed", i);
 			ret.push_back(i);
 		}
 	}
@@ -96,7 +96,7 @@ void CRewardableObject::onHeroVisit(const CGHeroInstance *h) const
 	auto grantRewardWithMessage = [&](int index) -> void
 	{
 		auto vi = getVisitInfo(index, h);
-		logGlobal->debugStream() << "Granting reward " << index << ". Message says: " << vi.message.toString();
+		logGlobal->debug("Granting reward %d. Message says: %s", index, vi.message.toString());
 		// show message only if it is not empty
 		if (!vi.message.toString().empty())
 		{
@@ -131,7 +131,7 @@ void CRewardableObject::onHeroVisit(const CGHeroInstance *h) const
 				objectRemovalPossible = true;
 		}
 
-		logGlobal->debugStream() << "Visiting object with " << rewards.size() << " possible rewards";
+		logGlobal->debug("Visiting object with %d possible rewards", rewards.size());
 		switch (rewards.size())
 		{
 			case 0: // no available rewards, e.g. empty flotsam
@@ -1166,7 +1166,7 @@ int3 CGMagicSpring::getVisitableOffset() const
 
 	if (visitableTiles.size() != info.size())
 	{
-		logGlobal->warnStream() << "Unexpected number of visitable tiles of Magic Spring at " << pos << "!";
+		logGlobal->warn("Unexpected number of visitable tiles of Magic Spring at %s", pos.toString());
 		return int3(-1,-1,-1);
 	}
 

+ 0 - 3
lib/mapObjects/CommonConstructors.cpp

@@ -300,8 +300,6 @@ BankConfig CBankInstanceConstructor::generateConfig(const JsonNode & level, CRan
 
 void CBankInstanceConstructor::configureObject(CGObjectInstance * object, CRandomGenerator & rng) const
 {
-	//logGlobal->debugStream() << "Seed used to configure bank is " << rng.nextInt();
-
 	auto bank = dynamic_cast<CBank*>(object);
 
 	bank->resetDuration = bankResetDuration;
@@ -313,7 +311,6 @@ void CBankInstanceConstructor::configureObject(CGObjectInstance * object, CRando
 	assert(totalChance != 0);
 
 	si32 selectedChance = rng.nextInt(totalChance - 1);
-	//logGlobal->debugStream() << "Selected chance for bank config is " << selectedChance;
 
 	int cumulativeChance = 0;
 	for (auto & node : levels)

+ 12 - 12
lib/mapObjects/MiscObjects.cpp

@@ -86,8 +86,8 @@ std::string CGCreature::getHoverText(PlayerColor player) const
 	if(stacks.empty())
 	{
 		//should not happen...
-		logGlobal->errorStream() << "Invalid stack at tile " << pos << ": subID=" << subID << "; id=" << id;
-		return "!!!INVALID_STACK!!!";
+		logGlobal->error("Invalid stack at tile %s: subID=%d; id=%d", pos.toString(), subID, id.getNum());
+		return "INVALID_STACK";
 	}
 
 	std::string hoverName;
@@ -231,7 +231,7 @@ void CGCreature::initObj(CRandomGenerator & rand)
 
 		if(amount == 0) //armies with 0 creatures are illegal
 		{
-			logGlobal->warnStream() << "Problem: stack " << nodeName() << " cannot have 0 creatures. Check properties of " << c.nodeName();
+			logGlobal->warn("Stack %s cannot have 0 creatures. Check properties of %s", nodeName(), c.nodeName());
 			amount = 1;
 		}
 	}
@@ -809,7 +809,7 @@ void CGMine::serializeJsonOptions(JsonSerializeFormat & handler)
 				{
 					int raw_res = vstd::find_pos(GameConstants::RESOURCE_NAMES, s);
 					if(raw_res < 0)
-						logGlobal->errorStream() << "Invalid resource name: "+s;
+						logGlobal->error("Invalid resource name: %s", s);
 					else
 						possibleResources.insert(raw_res);
 				}
@@ -1070,11 +1070,11 @@ void CGMonolith::onHeroVisit( const CGHeroInstance * h ) const
 
 		if(cb->isTeleportChannelImpassable(channel))
 		{
-			logGlobal->debugStream() << "Cannot find corresponding exit monolith for "<< id << " (obj at " << pos << ") :(";
+			logGlobal->debug("Cannot find corresponding exit monolith for %d at %s", id.getNum(), pos.toString());
 			td.impassable = true;
 		}
 		else if(getRandomExit(h) == ObjectInstanceID())
-			logGlobal->debugStream() << "All exits blocked for monolith "<< id << " (obj at " << pos << ") :(";
+			logGlobal->debug("All exits blocked for monolith %d at %s", id.getNum(), pos.toString());
 	}
 	else
 		showInfoDialog(h, 70, 0);
@@ -1134,7 +1134,7 @@ void CGSubterraneanGate::onHeroVisit( const CGHeroInstance * h ) const
 	if(cb->isTeleportChannelImpassable(channel))
 	{
 		showInfoDialog(h,153,0);//Just inside the entrance you find a large pile of rubble blocking the tunnel. You leave discouraged.
-		logGlobal->debugStream() << "Cannot find exit subterranean gate for "<< id << " (obj at " << pos << ") :(";
+		logGlobal->debug("Cannot find exit subterranean gate for  %d at %s", id.getNum(), pos.toString());
 		td.impassable = true;
 	}
 	else
@@ -1217,11 +1217,11 @@ void CGWhirlpool::onHeroVisit( const CGHeroInstance * h ) const
 	TeleportDialog td(h, channel);
 	if(cb->isTeleportChannelImpassable(channel))
 	{
-		logGlobal->debugStream() << "Cannot find exit whirlpool for "<< id << " (obj at " << pos << ") :(";
+		logGlobal->debug("Cannot find exit whirlpool for %d at %s", id.getNum(), pos.toString());
 		td.impassable = true;
 	}
 	else if(getRandomExit(h) == ObjectInstanceID())
-		logGlobal->debugStream() << "All exits are blocked for whirlpool "<< id << " (obj at " << pos << ") :(";
+		logGlobal->debug("All exits are blocked for whirlpool  %d at %s", id.getNum(), pos.toString());
 
 	if(!isProtected(h))
 	{
@@ -1727,7 +1727,7 @@ void CGScholar::onHeroVisit( const CGHeroInstance * h ) const
 		}
 		break;
 	default:
-		logGlobal->errorStream() << "Error: wrong bonus type (" << (int)type << ") for Scholar!\n";
+		logGlobal->error("Error: wrong bonus type (%d) for Scholar!\n", static_cast<int>(type));
 		return;
 	}
 
@@ -2125,8 +2125,8 @@ void CGObelisk::setPropertyDer( ui8 what, ui32 val )
 
 				if(progress > obeliskCount)
 				{
-					logGlobal->errorStream() << "Error: Visited " << progress << "\t\t" << obeliskCount;
-					assert(0);
+					logGlobal->error("Visited %d of %d", static_cast<int>(progress), obeliskCount);
+					throw std::runtime_error("internal error");
 				}
 
 				break;

+ 1 - 1
lib/mapObjects/ObjectTemplate.cpp

@@ -273,7 +273,7 @@ void ObjectTemplate::readJson(const JsonNode &node, const bool withTerrain)
 			case 'A' : return VISIBLE | BLOCKED | VISITABLE;
 			case 'T' : return BLOCKED | VISITABLE;
 			default:
-				logGlobal->errorStream() << "Unrecognized char " << ch << " in template mask";
+				logGlobal->error("Unrecognized char %s in template mask", ch);
 				return 0;
 		}
 	};

+ 3 - 3
lib/mapping/CMap.cpp

@@ -353,7 +353,7 @@ bool CMap::isCoastalTile(const int3 & pos) const
 
 	if(!isInTheMap(pos))
 	{
-		logGlobal->errorStream() << "Coastal check outside of map :"<<pos;
+		logGlobal->error("Coastal check outside of map: %s", pos.toString());
 		return false;
 	}
 
@@ -488,7 +488,7 @@ const CGObjectInstance * CMap::getObjectiveObjectFrom(int3 pos, Obj::EObj type)
 	// There is weird bug because of which sometimes heroes will not be found properly despite having correct position
 	// Try to workaround that and find closest object that we can use
 
-	logGlobal->errorStream() << "Failed to find object of type " << int(type) << " at " << pos;
+	logGlobal->error("Failed to find object of type %d at %s", int(type), pos.toString());
 	logGlobal->error("Will try to find closest matching object");
 
 	CGObjectInstance * bestMatch = nullptr;
@@ -507,7 +507,7 @@ const CGObjectInstance * CMap::getObjectiveObjectFrom(int3 pos, Obj::EObj type)
 	}
 	assert(bestMatch != nullptr); // if this happens - victory conditions or map itself is very, very broken
 
-	logGlobal->errorStream() << "Will use " << bestMatch->getObjectName() << " from " << bestMatch->pos;
+	logGlobal->error("Will use %s from %s", bestMatch->getObjectName(), bestMatch->pos.toString());
 	return bestMatch;
 }
 

+ 3 - 8
lib/mapping/CMapEditManager.cpp

@@ -660,9 +660,6 @@ void CDrawTerrainOperation::updateTerrainTypes()
 					if (addToSuitableTiles)
 					{
 						suitableTiles.insert(posToTest);
-						//logGlobal->debugStream() << boost::format(std::string("Found suitable tile '%s' for main tile '%s': ") +
-						//		"Invalid native tiles '%i', invalid foreign tiles '%i', centerPosValid '%i'") % posToTest % centerPos % testTile.nativeTiles.size() %
-						//		testTile.foreignTiles.size() % testTile.centerPosValid;
 					}
 
 					terrainTile.terType = formerTerType;
@@ -720,8 +717,6 @@ void CDrawTerrainOperation::updateTerrainViews()
 			valRslt = validateTerrainView(pos, &pattern);
 			if(valRslt.result)
 			{
-				/*logGlobal->debugStream() << boost::format("Pattern detected at pos '%s': Pattern '%s', Flip '%i', Repl. '%s'.") %
-											pos % pattern.id % valRslt.flip % valRslt.transitionReplacement;*/
 				bestPattern = k;
 				break;
 			}
@@ -730,7 +725,7 @@ void CDrawTerrainOperation::updateTerrainViews()
 		if(bestPattern == -1)
 		{
 			// This shouldn't be the case
-			logGlobal->warn("No pattern detected at pos '%s'.", pos);
+			logGlobal->warn("No pattern detected at pos '%s'.", pos.toString());
 			CTerrainViewPatternUtils::printDebuggingInfoAboutTile(map, pos);
 			continue;
 		}
@@ -1033,7 +1028,7 @@ CDrawTerrainOperation::ValidationResult::ValidationResult(bool result, const std
 
 void CTerrainViewPatternUtils::printDebuggingInfoAboutTile(const CMap * map, int3 pos)
 {
-	logGlobal->debugStream() << "Printing detailed info about nearby map tiles of pos '" << pos << "'";
+	logGlobal->debug("Printing detailed info about nearby map tiles of pos '%s'", pos.toString());
 	for(int y = pos.y - 2; y <= pos.y + 2; ++y)
 	{
 		std::string line;
@@ -1056,7 +1051,7 @@ void CTerrainViewPatternUtils::printDebuggingInfoAboutTile(const CMap * map, int
 			}
 		}
 
-		logGlobal->debugStream() << line;
+		logGlobal->debug(line);
 	}
 }
 

+ 1 - 1
lib/mapping/CMapService.cpp

@@ -135,6 +135,6 @@ std::unique_ptr<IMapPatcher> CMapService::getMapPatcher(std::string scenarioName
 		node = loadPatches("config/mapOverrides.json");
 
 	boost::to_lower(scenarioName);
-	logGlobal->debugStream() << "Request to patch map " << scenarioName;
+	logGlobal->debug("Request to patch map %s", scenarioName);
 	return std::unique_ptr<IMapPatcher>(new CMapPatcher(node[scenarioName]));
 }

+ 9 - 12
lib/mapping/MapFormatH3M.cpp

@@ -126,7 +126,7 @@ void CMapLoaderH3M::init()
 	{
 		for(MapLoadingTime & mlt : times)
 		{
-			logGlobal->debugStream() << "\tReading " << mlt.name << " took " << mlt.time << " ms.";
+			logGlobal->debug("\tReading %s took %d ms", mlt.name, mlt.time);
 		}
 	}
 	map->calculateGuardingGreaturePositions();
@@ -340,7 +340,7 @@ void CMapLoaderH3M::readVictoryLossConditions()
 
 			if (playersOnMap == 1)
 			{
-				logGlobal->warnStream() << "Map " << mapHeader->name << " has only one player but allows normal victory?";
+				logGlobal->warn("Map %s has only one player but allows normal victory?", mapHeader->name);
 				allowNormalVictory = false; // makes sense? Not much. Works as H3? Yes!
 			}
 		}
@@ -810,7 +810,7 @@ void CMapLoaderH3M::loadArtifactsOfHero(CGHeroInstance * hero)
 	{
 		if(hero->artifactsWorn.size() ||  hero->artifactsInBackpack.size())
 		{
-			logGlobal->warn("Hero %s at %s has set artifacts twice (in map properties and on adventure map instance). Using the latter set...", hero->name, hero->pos);
+			logGlobal->warn("Hero %s at %s has set artifacts twice (in map properties and on adventure map instance). Using the latter set...", hero->name, hero->pos.toString());
 			hero->artifactsInBackpack.clear();
 			while(hero->artifactsWorn.size())
 				hero->eraseArtSlot(hero->artifactsWorn.begin()->first);
@@ -888,8 +888,7 @@ bool CMapLoaderH3M::loadArtifactToSlot(CGHeroInstance * hero, int slot)
 		if(aid == 0 && slot == ArtifactPosition::MISC5)
 		{
 			//TODO: check how H3 handles it -> art 0 in slot 18 in AB map
-			logGlobal->warnStream() << "Spellbook to MISC5 slot? Putting it spellbook place. AB format peculiarity ? (format "
-				<< static_cast<int>(map->version) << ")";
+			logGlobal->warn("Spellbook to MISC5 slot? Putting it spellbook place. AB format peculiarity? (format %d)", static_cast<int>(map->version));
 			slot = ArtifactPosition::SPELLBOOK;
 		}
 
@@ -1415,11 +1414,11 @@ void CMapLoaderH3M::readObjects()
 				if(htid == 0xff)
 				{
 					hp->power = reader.readUInt8();
-					logGlobal->infoStream() << "Hero placeholder: by power at " << objPos;
+					logGlobal->info("Hero placeholder: by power at %s", objPos.toString());
 				}
 				else
 				{
-					logGlobal->infoStream() << "Hero placeholder: " << VLC->heroh->heroes[htid]->name << " at " << objPos;
+					logGlobal->info("Hero placeholder: %s at %s", VLC->heroh->heroes[htid]->name, objPos.toString());
 					hp->power = 0;
 				}
 
@@ -1463,8 +1462,7 @@ void CMapLoaderH3M::readObjects()
 				}
 				else
 				{
-					logGlobal->warnStream() << "Unrecognized object: " << objTempl.id << ":" << objTempl.subid << " at " << objPos
-											<< " on map " << map->name;
+					logGlobal->warn("Unrecognized object: %d:%d at %s on map %s", objTempl.id.toEnum(), objTempl.subid, objPos.toString(), map->name);
 					nobj = new CGObjectInstance();
 				}
 				break;
@@ -1562,7 +1560,7 @@ CGObjectInstance * CMapLoaderH3M::readHero(ObjectInstanceID idToBeGiven, const i
 	{
 		if(elem->subID == nhi->subID)
 		{
-			logGlobal->debugStream() << "Hero " << nhi->subID << " will be taken from the predefined heroes list.";
+			logGlobal->debug("Hero %d will be taken from the predefined heroes list.", nhi->subID);
 			delete nhi;
 			nhi = elem;
 			break;
@@ -2093,8 +2091,7 @@ std::set<BuildingID> CMapLoaderH3M::convertBuildings(const std::set<BuildingID>
 		}
 		else
 		{
-			logGlobal->warnStream() << "Conversion warning: unknown building " << elem << " in castle "
-				<< castleID;
+			logGlobal->warn("Conversion warning: unknown building %d in castle %d", elem.num, castleID);
 		}
 	}
 

+ 4 - 4
lib/mapping/MapFormatJson.cpp

@@ -60,7 +60,7 @@ si32 MapObjectResolver::decode(const std::string & identifier) const
 	}
 	else
 	{
-		logGlobal->errorStream() << "Object not found: " << identifier;
+		logGlobal->error("Object not found: %s", identifier);
 		return -1;
 	}
 }
@@ -82,7 +82,7 @@ std::string MapObjectResolver::encode(si32 identifier) const
 	si32 oid = id.getNum();
 	if(oid < 0  ||  oid >= owner->map->objects.size())
 	{
-        logGlobal->errorStream() << "Cannot get object with id " << oid;
+        logGlobal->error("Cannot get object with id %d", oid);
 		return "";
 	}
 
@@ -867,7 +867,7 @@ void CMapLoaderJson::readHeader(const bool complete)
 
 	if(fileVersionMajor != VERSION_MAJOR)
 	{
-		logGlobal->errorStream() << "Unsupported map format version: " << fileVersionMajor;
+		logGlobal->error("Unsupported map format version: %d", fileVersionMajor);
 		throw std::runtime_error("Unsupported map format version");
 	}
 
@@ -875,7 +875,7 @@ void CMapLoaderJson::readHeader(const bool complete)
 
 	if(fileVersionMinor > VERSION_MINOR)
 	{
-		logGlobal->warnStream() << "Too new map format revision: " << fileVersionMinor << ". This map should work but some of map features may be ignored.";
+		logGlobal->warn("Too new map format revision: %d. This map should work but some of map features may be ignored.", fileVersionMinor);
 	}
 
 	JsonDeserializer handler(mapObjectResolver.get(), header);

+ 3 - 2
lib/rmg/CMapGenOptions.cpp

@@ -218,8 +218,9 @@ const std::map<std::string, CRmgTemplate *> & CMapGenOptions::getAvailableTempla
 
 void CMapGenOptions::finalize(CRandomGenerator & rand)
 {
-	logGlobal->infoStream() << boost::format ("RMG settings: players %d, teams %d, computer players %d, computer teams %d, water %d, monsters %d")
-											% (int)getPlayerCount() % (int)getTeamCount() % (int)getCompOnlyPlayerCount() % (int)getCompOnlyTeamCount() % (int)getWaterContent() % (int)getMonsterStrength();
+	logGlobal->info("RMG settings: players %d, teams %d, computer players %d, computer teams %d, water %d, monsters %d",
+		static_cast<int>(getPlayerCount()), static_cast<int>(getTeamCount()), static_cast<int>(getCompOnlyPlayerCount()),
+		static_cast<int>(getCompOnlyTeamCount()), static_cast<int>(getWaterContent()), static_cast<int>(getMonsterStrength()));
 
 	if(!mapTemplate)
 	{

+ 2 - 8
lib/rmg/CMapGenerator.cpp

@@ -151,7 +151,7 @@ std::unique_ptr<CMap> CMapGenerator::generate(CMapGenOptions * mapGenOptions, in
 	}
 	catch (rmgException &e)
 	{
-		logGlobal->errorStream() << "Random map generation received exception: " << e.what();
+		logGlobal->error("Random map generation received exception: %s", e.what());
 	}
 	return std::move(map);
 }
@@ -703,7 +703,7 @@ void CMapGenerator::addHeaderInfo()
 void CMapGenerator::checkIsOnMap(const int3& tile) const
 {
 	if (!map->isInTheMap(tile))
-		throw  rmgException(boost::to_string(boost::format("Tile %s is outside the map") % tile));
+		throw rmgException(boost::to_string(boost::format("Tile %s is outside the map") % tile.toString()));
 }
 
 
@@ -814,13 +814,7 @@ float CMapGenerator::getNearestObjectDistance(const int3 &tile) const
 int CMapGenerator::getNextMonlithIndex()
 {
 	if (monolithIndex >= VLC->objtypeh->knownSubObjects(Obj::MONOLITH_TWO_WAY).size())
-	{
-		//logGlobal->errorStream() << boost::to_string(boost::format("RMG Error! There is no Monolith Two Way with index %d available!") % monolithIndex);
-		//monolithIndex++;
-		//return VLC->objtypeh->knownSubObjects(Obj::MONOLITH_TWO_WAY).size() - 1;
-		//TODO: interrupt map generation and report error
 		throw rmgException(boost::to_string(boost::format("There is no Monolith Two Way with index %d available!") % monolithIndex));
-	}
 	else
 		return monolithIndex++;
 }

+ 14 - 22
lib/rmg/CRmgTemplateZone.cpp

@@ -628,8 +628,6 @@ void CRmgTemplateZone::fractalize(CMapGenerator* gen)
 		}
 		out << std::endl;
 	}
-
-	//logGlobal->infoStream() << boost::format ("Zone %d subdivided fractally") %id;
 }
 
 void CRmgTemplateZone::connectLater(CMapGenerator* gen)
@@ -637,7 +635,7 @@ void CRmgTemplateZone::connectLater(CMapGenerator* gen)
 	for (const int3 node : tilesToConnectLater)
 	{
 		if (!connectWithCenter(gen, node, true))
-			logGlobal->error("Failed to connect node %s with center of the zone", node);
+			logGlobal->error("Failed to connect node %s with center of the zone", node.toString());
 	}
 }
 
@@ -839,7 +837,7 @@ bool CRmgTemplateZone::createRoad(CMapGenerator* gen, const int3& src, const int
 		}
 
 	}
-	logGlobal->warn("Failed to create road from %s to %s", src, dst);
+	logGlobal->warn("Failed to create road from %s to %s", src.toString(), dst.toString());
 	return false;
 
 }
@@ -1068,9 +1066,6 @@ bool CRmgTemplateZone::addMonster(CMapGenerator* gen, int3 &pos, si32 strength,
 	//will be set during initialization
 	guard->putStack(SlotID(0), hlp);
 
-	//logGlobal->traceStream() << boost::format ("Adding stack of %d %s. Map monster strenght %d, zone monster strength %d, base monster value %d")
-	//	% amount % VLC->creh->creatures[creId]->namePl % mapMonsterStrength % zoneMonsterStrength % strength;
-
 	placeObject(gen, guard, pos);
 
 	if (clearSurroundingTiles)
@@ -1427,7 +1422,7 @@ void CRmgTemplateZone::initTownType (CMapGenerator* gen)
 
 		if (playerInfo.canAnyonePlay()) //configure info for owning player
 		{
-			logGlobal->traceStream() << "Fill player info " << player_id;
+			logGlobal->trace("Fill player info %d", player_id);
 
 			// Update player info
 			playerInfo.allowedFactions.clear();
@@ -1577,12 +1572,12 @@ EObjectPlacingResult::EObjectPlacingResult CRmgTemplateZone::tryToPlaceObjectAnd
 	int3 accessibleOffset = getAccessibleOffset(gen, obj->appearance, pos);
 	if (!accessibleOffset.valid())
 	{
-		logGlobal->warn("Cannot access required object at position %s, retrying", pos);
+		logGlobal->warn("Cannot access required object at position %s, retrying", pos.toString());
 		return EObjectPlacingResult::CANNOT_FIT;
 	}
 	if (!connectPath(gen, accessibleOffset, true))
 	{
-		logGlobal->trace("Failed to create path to required object at position %s, retrying", pos);
+		logGlobal->trace("Failed to create path to required object at position %s, retrying", pos.toString());
 		return EObjectPlacingResult::SEALED_OFF;
 	}
 	else
@@ -1866,7 +1861,7 @@ void CRmgTemplateZone::connectRoads(CMapGenerator* gen)
 		else //no other nodes left, for example single road node in this zone
 			break;
 
-		logGlobal->debugStream() << "Building road from " << node << " to " << cross;
+		logGlobal->debug("Building road from %s to %s", node.toString(), cross.toString());
 		if (createRoad(gen, node, cross))
 		{
 			processed.insert(cross); //don't draw road starting at end point which is already connected
@@ -1916,7 +1911,7 @@ bool CRmgTemplateZone::fill(CMapGenerator* gen)
 	createRequiredObjects(gen);
 	createTreasures(gen);
 
-	logGlobal->infoStream() << boost::format ("Zone %d filled successfully") %id;
+	logGlobal->info("Zone %d filled successfully", id);
 	return true;
 }
 
@@ -2013,7 +2008,7 @@ void CRmgTemplateZone::setTemplateForObject(CMapGenerator* gen, CGObjectInstance
 	{
 		auto templates = VLC->objtypeh->getHandlerFor(obj->ID, obj->subID)->getTemplates(gen->map->getTile(getPos()).terType);
 		if (templates.empty())
-			throw rmgException(boost::to_string(boost::format("Did not find graphics for object (%d,%d) at %s") % obj->ID %obj->subID %pos));
+			throw rmgException(boost::to_string(boost::format("Did not find graphics for object (%d,%d) at %s") % obj->ID % obj->subID % pos.toString()));
 
 		obj->appearance = templates.front();
 	}
@@ -2072,15 +2067,15 @@ bool CRmgTemplateZone::findPlaceForObject(CMapGenerator* gen, CGObjectInstance*
 void CRmgTemplateZone::checkAndPlaceObject(CMapGenerator* gen, CGObjectInstance* object, const int3 &pos)
 {
 	if (!gen->map->isInTheMap(pos))
-		throw rmgException(boost::to_string(boost::format("Position of object %d at %s is outside the map") % object->id % pos));
+		throw rmgException(boost::to_string(boost::format("Position of object %d at %s is outside the map") % object->id % pos.toString()));
 	object->pos = pos;
 
 	if (object->isVisitable() && !gen->map->isInTheMap(object->visitablePos()))
-		throw rmgException(boost::to_string(boost::format("Visitable tile %s of object %d at %s is outside the map") % object->visitablePos() % object->id % object->pos()));
+		throw rmgException(boost::to_string(boost::format("Visitable tile %s of object %d at %s is outside the map") % object->visitablePos().toString() % object->id % object->pos.toString()));
 	for (auto tile : object->getBlockedPos())
 	{
 		if (!gen->map->isInTheMap(tile))
-			throw rmgException(boost::to_string(boost::format("Tile %s of object %d at %s is outside the map") % tile() % object->id % object->pos()));
+			throw rmgException(boost::to_string(boost::format("Tile %s of object %d at %s is outside the map") % tile.toString() % object->id % object->pos.toString()));
 	}
 
 	if (object->appearance.id == Obj::NO_OBJ)
@@ -2088,19 +2083,16 @@ void CRmgTemplateZone::checkAndPlaceObject(CMapGenerator* gen, CGObjectInstance*
 		auto terrainType = gen->map->getTile(pos).terType;
 		auto templates = VLC->objtypeh->getHandlerFor(object->ID, object->subID)->getTemplates(terrainType);
 		if (templates.empty())
-			throw rmgException(boost::to_string(boost::format("Did not find graphics for object (%d,%d) at %s (terrain %d)") %object->ID %object->subID %pos %terrainType));
+			throw rmgException(boost::to_string(boost::format("Did not find graphics for object (%d,%d) at %s (terrain %d)") % object->ID % object->subID % pos.toString() % terrainType));
 
 		object->appearance = templates.front();
 	}
 
 	gen->editManager->insertObject(object);
-	//logGlobal->traceStream() << boost::format ("Successfully inserted object (%d,%d) at pos %s") %object->ID %object->subID %pos();
 }
 
 void CRmgTemplateZone::placeObject(CMapGenerator* gen, CGObjectInstance* object, const int3 &pos, bool updateDistance)
 {
-	//logGlobal->trace("Inserting object at %d %d", pos.x, pos.y);
-
 	checkAndPlaceObject (gen, object, pos);
 
 	auto points = object->getBlockedPos();
@@ -2195,11 +2187,11 @@ bool CRmgTemplateZone::guardObject(CMapGenerator* gen, CGObjectInstance* object,
 	{
 		//guardTile = tiles.front();
 		guardTile = getAccessibleOffset(gen, object->appearance, object->pos);
-		logGlobal->trace("Guard object at %s", object->pos());
+		logGlobal->trace("Guard object at %s", object->pos.toString());
 	}
 	else
 	{
-		logGlobal->error("Failed to guard object at %s", object->pos());
+		logGlobal->error("Failed to guard object at %s", object->pos.toString());
 		return false;
 	}
 

+ 5 - 7
lib/rmg/CZonePlacer.cpp

@@ -151,7 +151,7 @@ void CZonePlacer::placeZones(const CMapGenOptions * mapGenOptions, CRandomGenera
 	for (auto zone : zones) //finalize zone positions
 	{
 		zone.second->setPos (cords (bestSolution[zone.second]));
-		logGlobal->traceStream() << boost::format ("Placed zone %d at relative position %s and coordinates %s") % zone.first % zone.second->getCenter() % zone.second->getPos();
+		logGlobal->trace("Placed zone %d at relative position %s and coordinates %s", zone.first, zone.second->getCenter().toString(), zone.second->getPos().toString());
 	}
 }
 
@@ -400,9 +400,8 @@ void CZonePlacer::moveOneZone(TZoneMap &zones, TForceVector &totalForces, TDista
 			{
 				float3 vec = targetZone->getCenter() - ourCenter;
 				float newDistanceBetweenZones = (std::max(misplacedZone->getSize(), targetZone->getSize())) / mapSize;
-				logGlobal->traceStream() << boost::format("Trying to move zone %d %s towards %d %s. Old distance %f") %
-					misplacedZone->getId() % ourCenter() % targetZone->getId() % targetZone->getCenter()() % maxDistance;
-				logGlobal->trace("direction is %s", vec());
+				logGlobal->trace("Trying to move zone %d %s towards %d %s. Old distance %f", misplacedZone->getId(), ourCenter.toString(), targetZone->getId(), targetZone->getCenter().toString(), maxDistance);
+				logGlobal->trace("direction is %s", vec.toString());
 
 				misplacedZone->setCenter(targetZone->getCenter() - vec.unitVector() * newDistanceBetweenZones); //zones should now overlap by half size
 				logGlobal->trace("New distance %f", targetZone->getCenter().dist2d(misplacedZone->getCenter()));
@@ -429,9 +428,8 @@ void CZonePlacer::moveOneZone(TZoneMap &zones, TForceVector &totalForces, TDista
 			{
 				float3 vec = ourCenter - targetZone->getCenter();
 				float newDistanceBetweenZones = (misplacedZone->getSize() + targetZone->getSize()) / mapSize;
-				logGlobal->traceStream() << boost::format("Trying to move zone %d %s away from %d %s. Old distance %f") %
-					misplacedZone->getId() % ourCenter() % targetZone->getId() % targetZone->getCenter()() % maxOverlap;
-				logGlobal->trace("direction is %s", vec());
+				logGlobal->trace("Trying to move zone %d %s away from %d %s. Old distance %f", misplacedZone->getId(), ourCenter.toString(), targetZone->getId(), targetZone->getCenter().toString(), maxOverlap);
+				logGlobal->trace("direction is %s", vec.toString());
 
 				misplacedZone->setCenter(targetZone->getCenter() + vec.unitVector() * newDistanceBetweenZones); //zones should now be just separated
 				logGlobal->trace("New distance %f", targetZone->getCenter().dist2d(misplacedZone->getCenter()));

+ 7 - 16
lib/rmg/float3.h

@@ -30,15 +30,15 @@ public:
 	float3 operator-(const float3 & i) const { return float3(x - i.x, y - i.y, z - i.z); }
 	// returns float3 with coordinates decreased by given numer
 	float3 operator-(const float i) const { return float3(x - i, y - i, z - (si32)i); }
-	
+
 	// returns float3 with plane coordinates decreased by given numer
 	float3 operator*(const float i) const {return float3(x * i, y * i, z);}
 	// returns float3 with plane coordinates decreased by given numer
 	float3 operator/(const float i) const {return float3(x / i, y / i, z);}
-	
+
 	// returns opposite position
 	float3 operator-() const { return float3(-x, -y, -z); }
-	
+
 	// returns squared distance on Oxy plane (z coord is not used)
 	double dist2dSQ(const float3 & o) const
 	{
@@ -58,7 +58,7 @@ public:
 	double dist2d(const float3 &other) const { return std::sqrt(dist2dSQ(other)); }
 
 	bool areNeighbours(const float3 &other) const { return (dist2dSQ(other) < 4.0) && z == other.z; }
-	
+
 	float3& operator+=(const float3 & i)
 	{
 		x += i.x;
@@ -75,7 +75,7 @@ public:
 
 		return *this;
 	}
-	
+
 	float3& operator-=(const float3 & i)
 	{
 		x -= i.x;
@@ -112,7 +112,7 @@ public:
 
 	bool operator==(const float3 & i) const { return (x == i.x) && (y == i.y) && (z == i.z); }
 	bool operator!=(const float3 & i) const { return (x != i.x) || (y != i.y) || (z != i.z); }
-	
+
 	bool operator<(const float3 & i) const
 	{
 		if (z<i.z)
@@ -131,7 +131,7 @@ public:
 		return false;
 	}
 
-	std::string operator ()() const
+	std::string toString() const
 	{
 		return	"(" + boost::lexical_cast<std::string>(x) +
 				" " + boost::lexical_cast<std::string>(y) +
@@ -151,15 +151,6 @@ public:
 	}
 };
 
-inline std::istream & operator>>(std::istream & str, float3 & dest)
-{
-	return str >> dest.x >> dest.y >> dest.z;
-}
-inline std::ostream & operator<<(std::ostream & str, const float3 & sth)
-{
-	return str << sth.x << ' ' << sth.y << ' ' << sth.z;
-}
-
 struct Shashfloat3
 {
 	size_t operator()(float3 const& pos) const

+ 5 - 6
lib/serializer/BinaryDeserializer.cpp

@@ -9,6 +9,7 @@
  */
 #include "StdInc.h"
 #include "BinaryDeserializer.h"
+#include "../filesystem/FileStream.h"
 
 #include "../registerTypes/RegisterTypes.h"
 
@@ -61,11 +62,11 @@ void CLoadFile::openNextFile(const boost::filesystem::path & fname, int minimalV
 
 			auto versionptr = (char*)&serializer.fileVersion;
 			std::reverse(versionptr, versionptr + 4);
-			logGlobal->warnStream() << "Version number reversed is " << serializer.fileVersion << ", checking...";
+			logGlobal->warn("Version number reversed is %x, checking...", serializer.fileVersion);
 
 			if(serializer.fileVersion == SERIALIZATION_VERSION)
 			{
-				logGlobal->warnStream() << fname << " seems to have different endianness! Entering reversing mode.";
+				logGlobal->warn("%s seems to have different endianness! Entering reversing mode.", fname.string());
 				serializer.reverseEndianess = true;
 			}
 			else
@@ -79,13 +80,11 @@ void CLoadFile::openNextFile(const boost::filesystem::path & fname, int minimalV
 	}
 }
 
-void CLoadFile::reportState(CLogger * out)
+void CLoadFile::reportState(vstd::CLoggerBase * out)
 {
 	out->debug("CLoadFile");
 	if(!!sfile && *sfile)
-	{
-		out->debugStream() << "\tOpened " << fName << "\n\tPosition: " << sfile->tellg();
-	}
+		out->debug("\tOpened %s Position: %d", fName, sfile->tellg());
 }
 
 void CLoadFile::clear()

+ 6 - 6
lib/serializer/BinaryDeserializer.h

@@ -15,6 +15,7 @@
 #include "../mapObjects/CGHeroInstance.h"
 
 class CStackInstance;
+class FileStream;
 
 class DLL_LINKAGE CLoaderBase
 {
@@ -115,7 +116,7 @@ class DLL_LINKAGE BinaryDeserializer : public CLoaderBase
 	load(length);				\
 	if(length > 500000)				\
 	{								\
-		logGlobal->warnStream() << "Warning: very big length: " << length;\
+		logGlobal->warn("Warning: very big length: %d", length);\
 		reader->reportState(logGlobal);			\
 	};
 
@@ -368,11 +369,10 @@ public:
 				}
 				catch(std::exception &e)
 				{
-					logGlobal->errorStream() << e.what();
-					logGlobal->errorStream() << boost::format("Failed to cast stored shared ptr. Real type: %s. Needed type %s. FIXME FIXME FIXME")
-						% itr->second.type().name() % typeid(std::shared_ptr<T>).name();
+					logGlobal->error(e.what());
+					logGlobal->error("Failed to cast stored shared ptr. Real type: %s. Needed type %s. FIXME FIXME FIXME", itr->second.type().name(), typeid(std::shared_ptr<T>).name());
 					//TODO scenario with inheritance -> we can have stored ptr to base and load ptr to derived (or vice versa)
-					assert(0);
+					throw;
 				}
 			}
 			else
@@ -522,7 +522,7 @@ public:
 
 	void openNextFile(const boost::filesystem::path & fname, int minimalVersion); //throws!
 	void clear();
-	void reportState(CLogger * out) override;
+	void reportState(vstd::CLoggerBase * out) override;
 
 	void checkMagicBytes(const std::string & text);
 

+ 4 - 3
lib/serializer/BinarySerializer.cpp

@@ -9,6 +9,7 @@
  */
 #include "StdInc.h"
 #include "BinarySerializer.h"
+#include "../filesystem/FileStream.h"
 
 #include "../registerTypes/RegisterTypes.h"
 
@@ -47,18 +48,18 @@ void CSaveFile::openNextFile(const boost::filesystem::path &fname)
 	}
 	catch(...)
 	{
-		logGlobal->errorStream() << "Failed to save to " << fname;
+		logGlobal->error("Failed to save to %s", fname.string());
 		clear();
 		throw;
 	}
 }
 
-void CSaveFile::reportState(CLogger * out)
+void CSaveFile::reportState(vstd::CLoggerBase * out)
 {
 	out->debug("CSaveFile");
 	if(sfile.get() && *sfile)
 	{
-		out->debugStream() << "\tOpened " << fName << "\n\tPosition: " << sfile->tellp();
+		out->debug("\tOpened %s \tPosition: %d", fName, sfile->tellp());
 	}
 }
 

+ 3 - 1
lib/serializer/BinarySerializer.h

@@ -12,6 +12,8 @@
 #include "CTypeList.h"
 #include "../mapObjects/CArmedInstance.h"
 
+class FileStream;
+
 class DLL_LINKAGE CSaverBase
 {
 protected:
@@ -358,7 +360,7 @@ public:
 
 	void openNextFile(const boost::filesystem::path &fname); //throws!
 	void clear();
-	void reportState(CLogger * out) override;
+	void reportState(vstd::CLoggerBase * out) override;
 
 	void putMagicBytes(const std::string &text);
 

+ 2 - 1
lib/serializer/CLoadIntegrityValidator.cpp

@@ -9,6 +9,7 @@
  */
 #include "StdInc.h"
 #include "CLoadIntegrityValidator.h"
+#include "../filesystem/FileStream.h"
 
 #include "../registerTypes/RegisterTypes.h"
 
@@ -39,7 +40,7 @@ int CLoadIntegrityValidator::read( void * data, unsigned size )
 		controlFile->read(controlData.data(), size);
 		if(std::memcmp(data, controlData.data(), size))
 		{
-			logGlobal->errorStream() << "Desync found! Position: " << primaryFile->sfile->tellg();
+			logGlobal->error("Desync found! Position: %d", primaryFile->sfile->tellg());
 			foundDesync = true;
 			//throw std::runtime_error("Savegame dsynchronized!");
 		}

+ 1 - 1
lib/serializer/CSerializer.h

@@ -84,7 +84,7 @@ public:
 	CSerializer();
 	~CSerializer();
 
-	virtual void reportState(CLogger * out){};
+	virtual void reportState(vstd::CLoggerBase * out){};
 
 	template <typename T, typename U>
 	const VectorizedObjectInfo<T, U> *getVectorizedTypeInfo()

+ 11 - 11
lib/serializer/Connection.cpp

@@ -49,7 +49,7 @@ void CConnection::init()
 	//we got connection
 	oser & std::string("Aiya!\n") & name & myEndianess; //identify ourselves
 	iser & pom & pom & contactEndianess;
-	logNetwork->infoStream() << "Established connection with "<<pom;
+	logNetwork->info("Established connection with %s", pom);
 	wmx = new boost::mutex();
 	rmx = new boost::mutex();
 
@@ -70,7 +70,7 @@ CConnection::CConnection(std::string host, ui16 port, std::string Name)
 	tcp::resolver::iterator end, pom, endpoint_iterator = resolver.resolve(tcp::resolver::query(host, std::to_string(port)),error);
 	if(error)
 	{
-		logNetwork->errorStream() << "Problem with resolving: \n" << error;
+		logNetwork->error("Problem with resolving: \n%s", error.message());
 		goto connerror1;
 	}
 	pom = endpoint_iterator;
@@ -84,13 +84,13 @@ CConnection::CConnection(std::string host, ui16 port, std::string Name)
 	i=0;
 	while(pom != end)
 	{
-		logNetwork->infoStream() << "\t" << i << ": " << (boost::asio::ip::tcp::endpoint&)*pom;
+		logNetwork->info("\t%d:%s", i, (boost::asio::ip::tcp::endpoint&)*pom);
 		pom++;
 	}
 	i=0;
 	while(endpoint_iterator != end)
 	{
-		logNetwork->infoStream() << "Trying connection to " << (boost::asio::ip::tcp::endpoint&)*endpoint_iterator << "  (" << i++ << ")";
+		logNetwork->info("Trying connection to %s(%d)", (boost::asio::ip::tcp::endpoint&)*endpoint_iterator, i++);
 		socket->connect(*endpoint_iterator, error);
 		if(!error)
 		{
@@ -99,7 +99,7 @@ CConnection::CConnection(std::string host, ui16 port, std::string Name)
 		}
 		else
 		{
-			logNetwork->errorStream() << "Problem with connecting: " <<  error;
+			logNetwork->error("Problem with connecting: %s", error.message());
 		}
 		endpoint_iterator++;
 	}
@@ -108,7 +108,7 @@ CConnection::CConnection(std::string host, ui16 port, std::string Name)
 connerror1:
 	logNetwork->error("Something went wrong... checking for error info");
 	if(error)
-		logNetwork->errorStream() << error;
+		logNetwork->error(error.message());
 	else
 		logNetwork->error("No error info. ");
 	delete io_service;
@@ -128,7 +128,7 @@ CConnection::CConnection(TAcceptor * acceptor, boost::asio::io_service *Io_servi
 	acceptor->accept(*socket,error);
 	if (error)
 	{
-		logNetwork->errorStream() << "Error on accepting: " << error;
+		logNetwork->error("Error on accepting: %s", error.message());
 		delete socket;
 		throw std::runtime_error("Can't establish connection :(");
 	}
@@ -204,13 +204,13 @@ bool CConnection::isHost() const
 	return connectionID == 1;
 }
 
-void CConnection::reportState(CLogger * out)
+void CConnection::reportState(vstd::CLoggerBase * out)
 {
 	out->debug("CConnection");
 	if(socket && socket->is_open())
 	{
 		out->debug("\tWe have an open and valid socket");
-		out->debugStream() << "\t" << socket->available() <<" bytes awaiting";
+		out->debug("\t %d bytes awaiting", socket->available());
 	}
 }
 
@@ -220,14 +220,14 @@ CPack * CConnection::retreivePack()
 	boost::unique_lock<boost::mutex> lock(*rmx);
 	logNetwork->trace("Listening... ");
 	iser & ret;
-	logNetwork->traceStream() << "\treceived server message of type " << (ret? typeid(*ret).name() : "nullptr") << ", data: " << ret;
+	logNetwork->trace("\treceived server message of type %s", (ret? typeid(*ret).name() : "nullptr"));
 	return ret;
 }
 
 void CConnection::sendPackToServer(const CPack &pack, PlayerColor player, ui32 requestID)
 {
 	boost::unique_lock<boost::mutex> lock(*wmx);
-	logNetwork->traceStream() << "Sending to server a pack of type " << typeid(pack).name();
+	logNetwork->trace("Sending to server a pack of type %s", typeid(pack).name());
 	oser & player & requestID & &pack; //packs has to be sent as polymorphic pointers!
 }
 

+ 1 - 1
lib/serializer/Connection.h

@@ -46,7 +46,7 @@ class DLL_LINKAGE CConnection
 	CConnection(void);
 
 	void init();
-	void reportState(CLogger * out) override;
+	void reportState(vstd::CLoggerBase * out) override;
 
 	int write(const void * data, unsigned size) override;
 	int read(void * data, unsigned size) override;

+ 1 - 1
lib/serializer/JsonDeserializer.cpp

@@ -224,7 +224,7 @@ void JsonDeserializer::readLICPart(const JsonNode & part, const TDecoder & decod
 			if(rawId < value.size())
 				value[rawId] = val;
 			else
-				logGlobal->errorStream() << "JsonDeserializer::serializeLIC: id out of bounds " << rawId;
+				logGlobal->error("JsonDeserializer::serializeLIC: id out of bounds %d", rawId);
 		}
 	}
 }

+ 0 - 7
lib/spells/CDefaultSpellMechanics.cpp

@@ -135,13 +135,10 @@ SpellCastContext::SpellCastContext(const DefaultSpellMechanics * mechanics_, con
 
 	if(parameters.cb->battleHasHero(otherSide))
 		otherHero = parameters.cb->battleGetFightingHero(otherSide);
-
-	logGlobal->debugStream() << "Started spell cast. Spell: " << mechanics->owner->name << "; mode:" << parameters.mode;
 }
 
 SpellCastContext::~SpellCastContext()
 {
-	logGlobal->debugStream() << "Finished spell cast. Spell: " << mechanics->owner->name << "; mode:" << parameters.mode;
 }
 
 void SpellCastContext::addDamageToDisplay(const si32 value)
@@ -201,8 +198,6 @@ void SpellCastContext::beforeCast()
 			}
 			sc.manaGained = (manaChannel * spellCost) / 100;
 		}
-
-		logGlobal->debugStream() << "spellCost: " << spellCost;
 	}
 }
 
@@ -330,8 +325,6 @@ void DefaultSpellMechanics::cast(const SpellCastEnvironment * env, const BattleS
 
 	ctx.attackedCres = owner->getAffectedStacks(parameters.cb, parameters.mode, parameters.caster, parameters.spellLvl, parameters.getFirstDestinationHex());
 
-	logGlobal->debugStream() << "will affect " << ctx.attackedCres.size() << " stacks";
-
 	handleResistance(env, ctx);
 
 	if(parameters.mode != ECastingMode::MAGIC_MIRROR)

+ 6 - 6
lib/spells/CSpellHandler.cpp

@@ -368,7 +368,7 @@ void CSpell::getEffects(std::vector<Bonus> & lst, const int level, const bool cu
 {
 	if(level < 0 || level >= GameConstants::SPELL_SCHOOL_LEVELS)
 	{
-		logGlobal->errorStream() << __FUNCTION__ << " invalid school level " << level;
+		logGlobal->error("invalid school level %d", level);
 		return;
 	}
 
@@ -376,7 +376,7 @@ void CSpell::getEffects(std::vector<Bonus> & lst, const int level, const bool cu
 
 	if(levelObject.effects.empty() && levelObject.cumulativeEffects.empty())
 	{
-		logGlobal->errorStream() << __FUNCTION__ << " This spell ("  + name + ") has no effects for level " << level;
+		logGlobal->error("This spell (%s) has no effects for level %d", name, level);
 		return;
 	}
 
@@ -819,7 +819,7 @@ CSpell * CSpellHandler::loadFromJson(const JsonNode & json, const std::string &
 
 	spell->name = json["name"].String();
 
-	logGlobal->traceStream() << __FUNCTION__ << ": loading spell " << spell->name;
+	logGlobal->trace("%s: loading spell %s", __FUNCTION__, spell->name);
 
 	const auto schoolNames = json["school"];
 
@@ -854,7 +854,7 @@ CSpell * CSpellHandler::loadFromJson(const JsonNode & json, const std::string &
 	else if(targetType == "LOCATION")
 		spell->targetType = CSpell::LOCATION;
 	else
-		logGlobal->warnStream() << "Spell " << spell->name << ": target type " << (targetType.empty() ? "empty" : "unknown ("+targetType+")") << ", assumed NO_TARGET.";
+		logGlobal->warn("Spell %s: target type %s - assumed NO_TARGET.", spell->name, (targetType.empty() ? "empty" : "unknown ("+targetType+")"));
 
 	for(const auto & counteredSpell: json["counters"].Struct())
 		if (counteredSpell.second.Bool())
@@ -899,7 +899,7 @@ CSpell * CSpellHandler::loadFromJson(const JsonNode & json, const std::string &
 	else if(!implicitPositiveness)
 	{
 		spell->positiveness = CSpell::NEUTRAL; //duplicates constructor but, just in case
-		logGlobal->errorStream() << "Spell " << spell->name << ": no positiveness specified, assumed NEUTRAL.";
+		logGlobal->error("Spell %s: no positiveness specified, assumed NEUTRAL.", spell->name);
 	}
 
 	spell->isSpecial = flags["special"].Bool();
@@ -909,7 +909,7 @@ CSpell * CSpellHandler::loadFromJson(const JsonNode & json, const std::string &
 		auto it = bonusNameMap.find(name);
 		if(it == bonusNameMap.end())
 		{
-			logGlobal->errorStream() << "Spell " << spell->name << ": invalid bonus name " << name;
+			logGlobal->error("Spell %s: invalid bonus name %s", spell->name, name);
 		}
 		else
 		{

+ 4 - 4
server/CGameHandler.cpp

@@ -1443,7 +1443,7 @@ void CGameHandler::setPortalDwelling(const CGTownInstance * town, bool forced=fa
 	const PlayerState * p = getPlayer(town->tempOwner);
 	if (!p)
 	{
-		logGlobal->warn("There is no player owner of town %s at %s", town->name, town->pos());
+		logGlobal->warn("There is no player owner of town %s at %s", town->name, town->pos.toString());
 		return;
 	}
 
@@ -2035,7 +2035,7 @@ bool CGameHandler::moveHero(ObjectInstanceID hid, int3 dst, ui8 teleporting, boo
 		return false;
 	}
 
-	logGlobal->trace("Player %d (%s) wants to move hero %d from %s to %s", asker, asker.getStr(), hid.getNum(), h->pos(), dst());
+	logGlobal->trace("Player %d (%s) wants to move hero %d from %s to %s", asker, asker.getStr(), hid.getNum(), h->pos.toString(), dst.toString());
 	const int3 hmpos = CGHeroInstance::convertPosition(dst, false);
 
 	if (!gs->map->isInTheMap(hmpos))
@@ -2103,7 +2103,7 @@ bool CGameHandler::moveHero(ObjectInstanceID hid, int3 dst, ui8 teleporting, boo
 	auto doMove = [&](TryMoveHero::EResult result, EGuardLook lookForGuards,
 								EVisitDest visitDest, ELEaveTile leavingTile) -> bool
 	{
-		LOG_TRACE_PARAMS(logGlobal, "Hero %s starts movement from %s to %s", h->name % tmh.start % tmh.end);
+		LOG_TRACE_PARAMS(logGlobal, "Hero %s starts movement from %s to %s", h->name % tmh.start.toString() % tmh.end.toString());
 
 		auto moveQuery = std::make_shared<CHeroMovementQuery>(this, tmh, h);
 		queries.addQuery(moveQuery);
@@ -6082,7 +6082,7 @@ void CGameHandler::spawnWanderingMonsters(CreatureID creatureID)
 	for (int i = 0; i < amount; ++i)
 	{
 		tile = tiles.begin();
-		logGlobal->trace("\tSpawning monster at %s",(*tile)());
+		logGlobal->trace("\tSpawning monster at %s", tile->toString());
 		putNewMonster(creatureID, cre->getRandomAmount(std::rand), *tile);
 		tiles.erase(tile); //not use it again
 	}

+ 1 - 1
server/CQuery.cpp

@@ -443,7 +443,7 @@ void CHeroMovementQuery::onExposure(QueryPtr topQuery)
 	if(visitDestAfterVictory && hero->tempOwner == players[0]) //hero still alive, so he won with the guard
 		//TODO what if there were H4-like escape? we should also check pos
 	{
-		logGlobal->trace("Hero %s after victory over guard finishes visit to %s", hero->name, tmh.end());
+		logGlobal->trace("Hero %s after victory over guard finishes visit to %s", hero->name, tmh.end.toString());
 		//finish movement
 		visitDestAfterVictory = false;
 		gh->visitObjectOnTile(*gh->getTile(CGHeroInstance::convertPosition(tmh.end, false)), hero);

+ 1 - 1
test/map/MapComparer.cpp

@@ -249,7 +249,7 @@ void MapComparer::compareTerrain()
 		for(int y = 0; y < expected->height; y++)
 		{
 			int3 coord(x,y,0);
-			SCOPED_TRACE(coord);
+			SCOPED_TRACE(coord.toString());
 			checkEqual(actual->getTile(coord), expected->getTile(coord));
 		}
 }