浏览代码

Merge pull request #2013 from krs0/feature/Split_processCommand_into_functions

Split Process console commands code into individual functions
Ivan Savenko 2 年之前
父节点
当前提交
b3d9807dd1
共有 2 个文件被更改,包括 482 次插入312 次删除
  1. 406 306
      client/ClientCommandManager.cpp
  2. 76 6
      client/ClientCommandManager.h

+ 406 - 306
client/ClientCommandManager.cpp

@@ -42,7 +42,34 @@
 
 #include <SDL_surface.h>
 
-void ClientCommandManager::handleGoSolo()
+void ClientCommandManager::handleQuitCommand()
+{
+		exit(EXIT_SUCCESS);
+}
+
+void ClientCommandManager::handleSaveCommand(std::istringstream & singleWordBuffer)
+{
+	if(!CSH->client)
+	{
+		printCommandMessage("Game is not in playing state");
+		return;
+	}
+
+	std::string saveFilename;
+	singleWordBuffer >> saveFilename;
+	CSH->client->save(saveFilename);
+	printCommandMessage("Game saved as: " + saveFilename);
+}
+
+void ClientCommandManager::handleLoadCommand(std::istringstream& singleWordBuffer)
+{
+	// TODO: this code should end the running game and manage to call startGame instead
+	//std::string fname;
+	//singleWordBuffer >> fname;
+	//CSH->client->loadGame(fname);
+}
+
+void ClientCommandManager::handleGoSoloCommand()
 {
 	Settings session = settings.write["session"];
 
@@ -80,21 +107,33 @@ void ClientCommandManager::handleGoSolo()
 	session["aiSolo"].Bool() = !session["aiSolo"].Bool();
 }
 
-void ClientCommandManager::handleControlAi(const std::string &colorName)
+void ClientCommandManager::handleAutoskipCommand()
+{
+		Settings session = settings.write["session"];
+		session["autoSkip"].Bool() = !session["autoSkip"].Bool();
+}
+
+void ClientCommandManager::handleControlaiCommand(std::istringstream& singleWordBuffer)
 {
+	std::string colorName;
+	singleWordBuffer >> colorName;
+	boost::to_lower(colorName);
+
 	boost::unique_lock<boost::recursive_mutex> un(*CPlayerInterface::pim);
 	if(!CSH->client)
 	{
 		printCommandMessage("Game is not in playing state");
 		return;
 	}
+
 	PlayerColor color;
 	if(LOCPLINT)
 		color = LOCPLINT->playerID;
+
 	for(auto & elem : CSH->client->gameState()->players)
 	{
-		if(elem.second.human || (colorName.length() &&
-								 elem.first.getNum() != vstd::find_pos(GameConstants::PLAYER_COLOR_NAMES, colorName)))
+		if(elem.second.human || 
+			(colorName.length() && elem.first.getNum() != vstd::find_pos(GameConstants::PLAYER_COLOR_NAMES, colorName)))
 		{
 			continue;
 		}
@@ -102,386 +141,319 @@ void ClientCommandManager::handleControlAi(const std::string &colorName)
 		CSH->client->removeGUI();
 		CSH->client->installNewPlayerInterface(std::make_shared<CPlayerInterface>(elem.first), elem.first);
 	}
+
 	GH.totalRedraw();
 	if(color != PlayerColor::NEUTRAL)
 		giveTurn(color);
 }
 
-void ClientCommandManager::processCommand(const std::string &message, bool calledFromIngameConsole)
+void ClientCommandManager::handleSetBattleAICommand(std::istringstream& singleWordBuffer)
 {
-	std::istringstream singleWordBuffer;
-	singleWordBuffer.str(message);
-	std::string commandName;
-	singleWordBuffer >> commandName;
-	currentCallFromIngameConsole = calledFromIngameConsole;
+	std::string aiName;
+	singleWordBuffer >> aiName;
 
-	if(message==std::string("die, fool"))
+	printCommandMessage("Will try loading that AI to see if it is correct name...\n");
+	try
 	{
-		exit(EXIT_SUCCESS);
+		if(auto ai = CDynLibHandler::getNewBattleAI(aiName)) //test that given AI is indeed available... heavy but it is easy to make a typo and break the game
+		{
+			Settings neutralAI = settings.write["server"]["neutralAI"];
+			neutralAI->String() = aiName;
+			printCommandMessage("Setting changed, from now the battle ai will be " + aiName + "!\n");
+		}
 	}
-	else if(commandName == "redraw")
+	catch(std::exception &e)
 	{
-		GH.totalRedraw();
+		printCommandMessage("Failed opening " + aiName + ": " + e.what(), ELogLevel::WARN);
+		printCommandMessage("Setting not changed, AI not found or invalid!", ELogLevel::WARN);
 	}
-	else if(commandName == "screen")
-	{
-		printCommandMessage("Screenbuf points to ");
+}
 
-		if(screenBuf == screen)
-			printCommandMessage("screen", ELogLevel::ERROR);
-		else if(screenBuf == screen2)
-			printCommandMessage("screen2", ELogLevel::ERROR);
-		else
-			printCommandMessage("?!?", ELogLevel::ERROR);
+void ClientCommandManager::handleRedrawCommand()
+{
+	GH.totalRedraw();
+}
 
-		SDL_SaveBMP(screen, "Screen_c.bmp");
-		SDL_SaveBMP(screen2, "Screen2_c.bmp");
-	}
-	else if(commandName == "save")
+void ClientCommandManager::handleScreenCommand()
+{
+	printCommandMessage("Screenbuf points to ");
+
+	if(screenBuf == screen)
+		printCommandMessage("screen", ELogLevel::ERROR);
+	else if(screenBuf == screen2)
+		printCommandMessage("screen2", ELogLevel::ERROR);
+	else
+		printCommandMessage("?!?", ELogLevel::ERROR);
+
+	SDL_SaveBMP(screen, "Screen_c.bmp");
+	SDL_SaveBMP(screen2, "Screen2_c.bmp");
+}
+
+void ClientCommandManager::handleNotDialogCommand()
+{
+	LOCPLINT->showingDialog->setn(false);
+}
+
+void ClientCommandManager::handleGuiCommand()
+{
+	for(const auto & child : GH.listInt)
 	{
-		if(!CSH->client)
-		{
-			printCommandMessage("Game is not in playing state");
-			return;
-		}
-		std::string fname;
-		singleWordBuffer >> fname;
-		CSH->client->save(fname);
+		const auto childPtr = child.get();
+		if(const CIntObject * obj = dynamic_cast<const CIntObject*>(childPtr))
+			printInfoAboutInterfaceObject(obj, 0);
+		else
+			printCommandMessage(std::string(typeid(childPtr).name()) + "\n");
 	}
-//	else if(commandName=="load")
-//	{
-//		// TODO: this code should end the running game and manage to call startGame instead
-//		std::string fname;
-//		singleWordBuffer >> fname;
-//		CSH->client->loadGame(fname);
-//	}
-	else if(message=="convert txt")
+}
+
+void ClientCommandManager::handleConvertTextCommand()
+{
+	logGlobal->info("Searching for available maps");
+	std::unordered_set<ResourceID> mapList = CResourceHandler::get()->getFilteredFiles([&](const ResourceID & ident)
 	{
-		logGlobal->info("Searching for available maps");
-		std::unordered_set<ResourceID> mapList = CResourceHandler::get()->getFilteredFiles([&](const ResourceID & ident)
-		{
-			return ident.getType() == EResType::MAP;
-		});
+		return ident.getType() == EResType::MAP;
+	});
 
-		std::unordered_set<ResourceID> campaignList = CResourceHandler::get()->getFilteredFiles([&](const ResourceID & ident)
-		{
-			return ident.getType() == EResType::CAMPAIGN;
-		});
+	std::unordered_set<ResourceID> campaignList = CResourceHandler::get()->getFilteredFiles([&](const ResourceID & ident)
+	{
+		return ident.getType() == EResType::CAMPAIGN;
+	});
 
-		CMapService mapService;
+	CMapService mapService;
 
-		logGlobal->info("Loading maps for export");
-		for (auto const & mapName : mapList)
+	logGlobal->info("Loading maps for export");
+	for (auto const & mapName : mapList)
+	{
+		try
 		{
-			try
-			{
-				// load and drop loaded map - we only need loader to run over all maps
-				mapService.loadMap(mapName);
-			}
-			catch(std::exception & e)
-			{
-				logGlobal->error("Map %s is invalid. Message: %s", mapName.getName(), e.what());
-			}
+			// load and drop loaded map - we only need loader to run over all maps
+			mapService.loadMap(mapName);
 		}
-
-		logGlobal->info("Loading campaigns for export");
-		for (auto const & campaignName : campaignList)
+		catch(std::exception & e)
 		{
-			CCampaignState state(CCampaignHandler::getCampaign(campaignName.getName()));
-			for (auto const & part : state.camp->mapPieces)
-				delete state.getMap(part.first);
+			logGlobal->error("Map %s is invalid. Message: %s", mapName.getName(), e.what());
 		}
-
-		VLC->generaltexth->dumpAllTexts();
 	}
-	else if(message=="get config")
+
+	logGlobal->info("Loading campaigns for export");
+	for (auto const & campaignName : campaignList)
 	{
-		printCommandMessage("Command accepted.\t");
+		CCampaignState state(CCampaignHandler::getCampaign(campaignName.getName()));
+		for (auto const & part : state.camp->mapPieces)
+			delete state.getMap(part.first);
+	}
 
-		const boost::filesystem::path outPath =
-				VCMIDirs::get().userExtractedPath() / "configuration";
+	VLC->generaltexth->dumpAllTexts();
+}
 
-		boost::filesystem::create_directories(outPath);
+void ClientCommandManager::handleGetConfigCommand()
+{
+	printCommandMessage("Command accepted.\t");
 
-		const std::vector<std::string> contentNames = {"heroClasses", "artifacts", "creatures", "factions", "objects", "heroes", "spells", "skills"};
+	const boost::filesystem::path outPath = VCMIDirs::get().userExtractedPath() / "configuration";
 
-		for(auto contentName : contentNames)
-		{
-			auto & content = (*VLC->modh->content)[contentName];
+	boost::filesystem::create_directories(outPath);
 
-			auto contentOutPath = outPath / contentName;
-			boost::filesystem::create_directories(contentOutPath);
+	const std::vector<std::string> contentNames = { "heroClasses", "artifacts", "creatures", "factions", "objects", "heroes", "spells", "skills" };
 
-			for(auto & iter : content.modData)
-			{
-				const JsonNode & modData = iter.second.modData;
+	for(auto contentName : contentNames)
+	{
+		auto& content = (*VLC->modh->content)[contentName];
 
-				for(auto & nameAndObject : modData.Struct())
-				{
-					const JsonNode & object = nameAndObject.second;
+		auto contentOutPath = outPath / contentName;
+		boost::filesystem::create_directories(contentOutPath);
 
-					std::string name = CModHandler::makeFullIdentifier(object.meta, contentName, nameAndObject.first);
+		for(auto& iter : content.modData)
+		{
+			const JsonNode& modData = iter.second.modData;
+
+			for(auto& nameAndObject : modData.Struct())
+			{
+				const JsonNode& object = nameAndObject.second;
 
-					boost::algorithm::replace_all(name,":","_");
+				std::string name = CModHandler::makeFullIdentifier(object.meta, contentName, nameAndObject.first);
 
-					const boost::filesystem::path filePath = contentOutPath / (name + ".json");
-					boost::filesystem::ofstream file(filePath);
-					file << object.toJson();
-				}
+				boost::algorithm::replace_all(name, ":", "_");
+
+				const boost::filesystem::path filePath = contentOutPath / (name + ".json");
+				boost::filesystem::ofstream file(filePath);
+				file << object.toJson();
 			}
 		}
-
-		printCommandMessage("\rExtracting done :)\n");
-		printCommandMessage("Extracted files can be found in " + outPath.string() + " directory\n");
 	}
+
+	printCommandMessage("\rExtracting done :)\n");
+	printCommandMessage("Extracted files can be found in " + outPath.string() + " directory\n");
+}
+
+void ClientCommandManager::handleGetScriptsCommand()
+{
 #if SCRIPTING_ENABLED
-		else if(message=="get scripts")
-	{
-		printCommandMessage("Command accepted.\t");
+	printCommandMessage("Command accepted.\t");
 
-		const boost::filesystem::path outPath =
-			VCMIDirs::get().userExtractedPath() / "scripts";
+	const boost::filesystem::path outPath = VCMIDirs::get().userExtractedPath() / "scripts";
 
-		boost::filesystem::create_directories(outPath);
+	boost::filesystem::create_directories(outPath);
 
-		for(auto & kv : VLC->scriptHandler->objects)
-		{
-			std::string name = kv.first;
-			boost::algorithm::replace_all(name,":","_");
+	for(auto & kv : VLC->scriptHandler->objects)
+	{
+		std::string name = kv.first;
+		boost::algorithm::replace_all(name,":","_");
 
-			const scripting::ScriptImpl * script = kv.second.get();
-			boost::filesystem::path filePath = outPath / (name + ".lua");
-			boost::filesystem::ofstream file(filePath);
-			file << script->getSource();
-		}
-		printCommandMessage("\rExtracting done :)\n");
-		printCommandMessage("Extracted files can be found in " + outPath.string() + " directory\n");
+		const scripting::ScriptImpl * script = kv.second.get();
+		boost::filesystem::path filePath = outPath / (name + ".lua");
+		boost::filesystem::ofstream file(filePath);
+		file << script->getSource();
 	}
+	printCommandMessage("\rExtracting done :)\n");
+	printCommandMessage("Extracted files can be found in " + outPath.string() + " directory\n");
 #endif
-	else if(message=="get txt")
-	{
-		printCommandMessage("Command accepted.\t");
+}
 
-		const boost::filesystem::path outPath =
-				VCMIDirs::get().userExtractedPath();
+void ClientCommandManager::handleGetTextCommand()
+{
+	printCommandMessage("Command accepted.\t");
 
-		auto list =
-				CResourceHandler::get()->getFilteredFiles([](const ResourceID & ident)
-				{
-					return ident.getType() == EResType::TEXT && boost::algorithm::starts_with(ident.getName(), "DATA/");
-				});
+	const boost::filesystem::path outPath =
+			VCMIDirs::get().userExtractedPath();
 
-		for (auto & filename : list)
-		{
-			const boost::filesystem::path filePath = outPath / (filename.getName() + ".TXT");
+	auto list =
+			CResourceHandler::get()->getFilteredFiles([](const ResourceID & ident)
+			{
+				return ident.getType() == EResType::TEXT && boost::algorithm::starts_with(ident.getName(), "DATA/");
+			});
 
-			boost::filesystem::create_directories(filePath.parent_path());
+	for (auto & filename : list)
+	{
+		const boost::filesystem::path filePath = outPath / (filename.getName() + ".TXT");
 
-			boost::filesystem::ofstream file(filePath);
-			auto text = CResourceHandler::get()->load(filename)->readAll();
+		boost::filesystem::create_directories(filePath.parent_path());
 
-			file.write((char*)text.first.get(), text.second);
-		}
+		boost::filesystem::ofstream file(filePath);
+		auto text = CResourceHandler::get()->load(filename)->readAll();
 
-		printCommandMessage("\rExtracting done :)\n");
-		printCommandMessage("Extracted files can be found in " + outPath.string() + " directory\n");
-	}
-	else if(commandName == "crash")
-	{
-		int *ptr = nullptr;
-		*ptr = 666;
-		//disaster!
-	}
-	else if(commandName == "mp" && adventureInt)
-	{
-		if(const CGHeroInstance *h = adventureInt->curHero())
-			printCommandMessage(std::to_string(h->movement) + "; max: " + std::to_string(h->maxMovePoints(true)) + "/" + std::to_string(h->maxMovePoints(false)) + "\n");
-	}
-	else if(commandName == "bonuses")
-	{
-		bool jsonFormat = (message == "bonuses json");
-		auto format = [jsonFormat](const BonusList & b) -> std::string
-		{
-			if(jsonFormat)
-				return b.toJsonNode().toJson(true);
-			std::ostringstream ss;
-			ss << b;
-			return ss.str();
-		};
-		printCommandMessage("Bonuses of " + adventureInt->curArmy()->getObjectName() + "\n");
-		printCommandMessage(format(adventureInt->curArmy()->getBonusList()) + "\n");
-
-		printCommandMessage("\nInherited bonuses:\n");
-		TCNodes parents;
-		adventureInt->curArmy()->getParents(parents);
-		for(const CBonusSystemNode *parent : parents)
-		{
-			printCommandMessage(std::string("\nBonuses from ") + typeid(*parent).name() + "\n" + format(*parent->getAllBonuses(Selector::all, Selector::all)) + "\n");
-		}
-	}
-	else if(commandName == "not dialog")
-	{
-		LOCPLINT->showingDialog->setn(false);
+		file.write((char*)text.first.get(), text.second);
 	}
-	else if(commandName == "gui")
-	{
-		for(auto & child : GH.listInt)
-		{
-			const auto childPtr = child.get();
-			if(const CIntObject * obj = dynamic_cast<const CIntObject *>(childPtr))
-				printInfoAboutInterfaceObject(obj, 0);
-			else
-				printCommandMessage(std::string(typeid(childPtr).name()) + "\n");
-		}
-	}
-	else if(commandName == "tell")
-	{
-		std::string what;
-		int id1, id2;
-		singleWordBuffer >> what >> id1 >> id2;
-		if(what == "hs")
-		{
-			for(const CGHeroInstance *h : LOCPLINT->cb->getHeroesInfo())
-				if(h->type->getIndex() == id1)
-					if(const CArtifactInstance *a = h->getArt(ArtifactPosition(id2)))
-						printCommandMessage(a->nodeName());
-		}
-	}
-	else if (commandName == "set")
-	{
-		std::string what, value;
-		singleWordBuffer >> what;
 
-		Settings config = settings.write["session"][what];
+	printCommandMessage("\rExtracting done :)\n");
+	printCommandMessage("Extracted files can be found in " + outPath.string() + " directory\n");
+}
 
-		singleWordBuffer >> value;
+void ClientCommandManager::handleDef2bmpCommand(std::istringstream& singleWordBuffer)
+{
+	std::string URI;
+	singleWordBuffer >> URI;
+	std::unique_ptr<CAnimation> anim = std::make_unique<CAnimation>(URI);
+	anim->preload();
+	anim->exportBitmaps(VCMIDirs::get().userExtractedPath());
+}
 
-		if (value == "on")
-		{
-			config->Bool() = true;
-			printCommandMessage("Option " + what + " enabled!", ELogLevel::INFO);
-		}
-		else if (value == "off")
-		{
-			config->Bool() = false;
-			printCommandMessage("Option " + what + " disabled!", ELogLevel::INFO);
-		}
-	}
-	else if(commandName == "unlock")
-	{
-		std::string mxname;
-		singleWordBuffer >> mxname;
-		if(mxname == "pim" && LOCPLINT)
-			LOCPLINT->pim->unlock();
-	}
-	else if(commandName == "def2bmp")
-	{
-		std::string URI;
-		singleWordBuffer >> URI;
-		std::unique_ptr<CAnimation> anim = std::make_unique<CAnimation>(URI);
-		anim->preload();
-		anim->exportBitmaps(VCMIDirs::get().userExtractedPath());
-	}
-	else if(commandName == "extract")
-	{
-		std::string URI;
-		singleWordBuffer >> URI;
+void ClientCommandManager::handleExtractCommand(std::istringstream& singleWordBuffer)
+{
+	std::string URI;
+	singleWordBuffer >> URI;
 
-		if (CResourceHandler::get()->existsResource(ResourceID(URI)))
-		{
-			const boost::filesystem::path outPath = VCMIDirs::get().userExtractedPath() / URI;
+	if(CResourceHandler::get()->existsResource(ResourceID(URI)))
+	{
+		const boost::filesystem::path outPath = VCMIDirs::get().userExtractedPath() / URI;
 
-			auto data = CResourceHandler::get()->load(ResourceID(URI))->readAll();
+		auto data = CResourceHandler::get()->load(ResourceID(URI))->readAll();
 
-			boost::filesystem::create_directories(outPath.parent_path());
-			boost::filesystem::ofstream outFile(outPath, boost::filesystem::ofstream::binary);
-			outFile.write((char*)data.first.get(), data.second);
-		}
-		else
-			printCommandMessage("File not found!", ELogLevel::ERROR);
+		boost::filesystem::create_directories(outPath.parent_path());
+		boost::filesystem::ofstream outFile(outPath, boost::filesystem::ofstream::binary);
+		outFile.write((char*)data.first.get(), data.second);
 	}
-	else if(commandName == "setBattleAI")
+	else
+		printCommandMessage("File not found!", ELogLevel::ERROR);
+}
+
+void ClientCommandManager::handleBonusesCommand(std::istringstream & singleWordBuffer)
+{
+	if(currentCallFromIngameConsole)
 	{
-		std::string fname;
-		singleWordBuffer >> fname;
-		printCommandMessage("Will try loading that AI to see if it is correct name...\n");
-		try
-		{
-			if(auto ai = CDynLibHandler::getNewBattleAI(fname)) //test that given AI is indeed available... heavy but it is easy to make a typo and break the game
-			{
-				Settings neutralAI = settings.write["server"]["neutralAI"];
-				neutralAI->String() = fname;
-				printCommandMessage("Setting changed, from now the battle ai will be " + fname + "!\n");
-			}
-		}
-		catch(std::exception &e)
-		{
-			printCommandMessage("Failed opening " + fname + ": " + e.what(), ELogLevel::WARN);
-			printCommandMessage("Setting not changed, AI not found or invalid!", ELogLevel::WARN);
-		}
+		printCommandMessage("Output for this command is too large for ingame chat! Please run it from client console.\n");
+		return;
 	}
-	else if(commandName == "autoskip")
+
+	std::string outputFormat;
+	singleWordBuffer >> outputFormat;
+
+	auto format = [outputFormat](const BonusList & b) -> std::string
 	{
-		Settings session = settings.write["session"];
-		session["autoSkip"].Bool() = !session["autoSkip"].Bool();
-	}
-	else if(commandName == "gosolo")
+		if(outputFormat == "json")
+			return b.toJsonNode().toJson(true);
+
+		std::ostringstream ss;
+		ss << b;
+		return ss.str();
+	};
+	printCommandMessage("Bonuses of " + adventureInt->curArmy()->getObjectName() + "\n");
+	printCommandMessage(format(adventureInt->curArmy()->getBonusList()) + "\n");
+
+	printCommandMessage("\nInherited bonuses:\n");
+	TCNodes parents;
+	adventureInt->curArmy()->getParents(parents);
+	for(const CBonusSystemNode *parent : parents)
 	{
-		ClientCommandManager::handleGoSolo();
+		printCommandMessage(std::string("\nBonuses from ") + typeid(*parent).name() + "\n" + format(*parent->getAllBonuses(Selector::all, Selector::all)) + "\n");
 	}
-	else if(commandName == "controlai")
-	{
-		std::string colorName;
-		singleWordBuffer >> colorName;
-		boost::to_lower(colorName);
+}
 
-		ClientCommandManager::handleControlAi(colorName);
-	}
-	else
+void ClientCommandManager::handleTellCommand(std::istringstream& singleWordBuffer)
+{
+	std::string what;
+	int id1, id2;
+	singleWordBuffer >> what >> id1 >> id2;
+
+	if(what == "hs")
 	{
-		if (!commandName.empty() && !vstd::iswithin(commandName[0], 0, ' ')) // filter-out debugger/IDE noise
-			printCommandMessage("Command not found :(", ELogLevel::ERROR);
+		for(const CGHeroInstance* h : LOCPLINT->cb->getHeroesInfo())
+			if(h->type->getIndex() == id1)
+				if(const CArtifactInstance* a = h->getArt(ArtifactPosition(id2)))
+					printCommandMessage(a->nodeName());
 	}
 }
 
-void ClientCommandManager::giveTurn(const PlayerColor &colorIdentifier)
+void ClientCommandManager::handleMpCommand()
 {
-	YourTurn yt;
-	yt.player = colorIdentifier;
-	yt.daysWithoutCastle = CSH->client->getPlayerState(colorIdentifier)->daysWithoutCastle;
-
-	ApplyClientNetPackVisitor visitor(*CSH->client, *CSH->client->gameState());
-	yt.visit(visitor);
+	if(const CGHeroInstance* h = adventureInt->curHero())
+		printCommandMessage(std::to_string(h->movement) + "; max: " + std::to_string(h->maxMovePoints(true)) + "/" + std::to_string(h->maxMovePoints(false)) + "\n");
 }
 
-void ClientCommandManager::printInfoAboutInterfaceObject(const CIntObject *obj, int level)
+void ClientCommandManager::handleSetCommand(std::istringstream& singleWordBuffer)
 {
-	std::stringstream sbuffer;
-	sbuffer << std::string(level, '\t');
+	std::string what, value;
+	singleWordBuffer >> what;
 
-	sbuffer << typeid(*obj).name() << " *** ";
-	if (obj->active)
+	Settings config = settings.write["session"][what];
+
+	singleWordBuffer >> value;
+
+	if(value == "on")
 	{
-#define PRINT(check, text) if (obj->active & CIntObject::check) sbuffer << text
-		PRINT(LCLICK, 'L');
-		PRINT(RCLICK, 'R');
-		PRINT(HOVER, 'H');
-		PRINT(MOVE, 'M');
-		PRINT(KEYBOARD, 'K');
-		PRINT(TIME, 'T');
-		PRINT(GENERAL, 'A');
-		PRINT(WHEEL, 'W');
-		PRINT(DOUBLECLICK, 'D');
-#undef  PRINT
+		config->Bool() = true;
+		printCommandMessage("Option " + what + " enabled!", ELogLevel::INFO);
 	}
-	else
-		sbuffer << "inactive";
-	sbuffer << " at " << obj->pos.x <<"x"<< obj->pos.y;
-	sbuffer << " (" << obj->pos.w <<"x"<< obj->pos.h << ")";
-	printCommandMessage(sbuffer.str(), ELogLevel::INFO);
+	else if(value == "off")
+	{
+		config->Bool() = false;
+		printCommandMessage("Option " + what + " disabled!", ELogLevel::INFO);
+	}
+}
 
-	for(const CIntObject *child : obj->children)
-		printInfoAboutInterfaceObject(child, level+1);
+void ClientCommandManager::handleUnlockCommand(std::istringstream& singleWordBuffer)
+{
+	std::string mxname;
+	singleWordBuffer >> mxname;
+	if(mxname == "pim" && LOCPLINT)
+		LOCPLINT->pim->unlock();
+}
+
+void ClientCommandManager::handleCrashCommand()
+{
+	int* ptr = nullptr;
+	*ptr = 666;
+	//disaster!
 }
 
 void ClientCommandManager::printCommandMessage(const std::string &commandMessage, ELogLevel::ELogLevel messageType)
@@ -520,3 +492,131 @@ void ClientCommandManager::printCommandMessage(const std::string &commandMessage
 		}
 	}
 }
+
+void ClientCommandManager::printInfoAboutInterfaceObject(const CIntObject *obj, int level)
+{
+	std::stringstream sbuffer;
+	sbuffer << std::string(level, '\t');
+
+	sbuffer << typeid(*obj).name() << " *** ";
+	if (obj->active)
+	{
+#define PRINT(check, text) if (obj->active & CIntObject::check) sbuffer << text
+		PRINT(LCLICK, 'L');
+		PRINT(RCLICK, 'R');
+		PRINT(HOVER, 'H');
+		PRINT(MOVE, 'M');
+		PRINT(KEYBOARD, 'K');
+		PRINT(TIME, 'T');
+		PRINT(GENERAL, 'A');
+		PRINT(WHEEL, 'W');
+		PRINT(DOUBLECLICK, 'D');
+#undef  PRINT
+	}
+	else
+		sbuffer << "inactive";
+	sbuffer << " at " << obj->pos.x <<"x"<< obj->pos.y;
+	sbuffer << " (" << obj->pos.w <<"x"<< obj->pos.h << ")";
+	printCommandMessage(sbuffer.str(), ELogLevel::INFO);
+
+	for(const CIntObject *child : obj->children)
+		printInfoAboutInterfaceObject(child, level+1);
+}
+
+void ClientCommandManager::giveTurn(const PlayerColor &colorIdentifier)
+{
+	YourTurn yt;
+	yt.player = colorIdentifier;
+	yt.daysWithoutCastle = CSH->client->getPlayerState(colorIdentifier)->daysWithoutCastle;
+
+	ApplyClientNetPackVisitor visitor(*CSH->client, *CSH->client->gameState());
+	yt.visit(visitor);
+}
+
+void ClientCommandManager::processCommand(const std::string & message, bool calledFromIngameConsole)
+{
+	// split the message into individual words
+	std::istringstream singleWordBuffer;
+	singleWordBuffer.str(message);
+
+	// get command name, to be used for single word commands
+	std::string commandName;
+	singleWordBuffer >> commandName;
+
+	currentCallFromIngameConsole = calledFromIngameConsole;
+
+	if(message == std::string("die, fool"))
+		handleQuitCommand();
+
+	else if(commandName == "save")
+		handleSaveCommand(singleWordBuffer);
+
+	else if(commandName=="load")
+		handleLoadCommand(singleWordBuffer); // not implemented
+
+	else if(commandName == "gosolo")
+		handleGoSoloCommand();
+
+	else if(commandName == "autoskip")
+		handleAutoskipCommand();
+
+	else if(commandName == "controlai")
+		handleControlaiCommand(singleWordBuffer);
+
+	else if(commandName == "setBattleAI")
+		handleSetBattleAICommand(singleWordBuffer);
+
+	else if(commandName == "redraw")
+		handleRedrawCommand();
+
+	else if(commandName == "screen")
+		handleScreenCommand();
+
+	else if(commandName == "not dialog")
+		handleNotDialogCommand();
+
+	else if(commandName == "gui")
+		handleGuiCommand();
+
+	else if(message=="convert txt")
+		handleConvertTextCommand();
+
+	else if(message=="get config")
+		handleGetConfigCommand();
+
+	else if(message=="get scripts")
+		handleGetScriptsCommand();
+
+	else if(message=="get txt")
+		handleGetTextCommand();
+
+	else if(commandName == "def2bmp")
+		handleDef2bmpCommand(singleWordBuffer);
+
+	else if(commandName == "extract")
+		handleExtractCommand(singleWordBuffer);
+
+	else if(commandName == "bonuses")
+		handleBonusesCommand(singleWordBuffer);
+
+	else if(commandName == "tell")
+		handleTellCommand(singleWordBuffer);
+
+	else if(commandName == "mp" && adventureInt)
+		handleMpCommand();
+
+	else if (commandName == "set")
+		handleSetCommand(singleWordBuffer);
+
+	else if(commandName == "unlock")
+		handleUnlockCommand(singleWordBuffer);
+
+	else if(commandName == "crash")
+		handleCrashCommand();
+
+	else
+	{
+		if (!commandName.empty() && !vstd::iswithin(commandName[0], 0, ' ')) // filter-out debugger/IDE noise
+			printCommandMessage("Command not found :(", ELogLevel::ERROR);
+	}
+}

+ 76 - 6
client/ClientCommandManager.h

@@ -17,15 +17,85 @@ class CIntObject;
 
 class ClientCommandManager //take mantis #2292 issue about account if thinking about handling cheats from command-line
 {
-	bool currentCallFromIngameConsole = false;
+	bool currentCallFromIngameConsole = false; // commands can come from 2 sources: ingame console (chat) and client console
+	
+	// Quits the game (die, fool command)
+	void handleQuitCommand();
 
-	void giveTurn(const PlayerColor &color);
-	void printInfoAboutInterfaceObject(const CIntObject *obj, int level);
+	// Saves current game under the given filename
+	void handleSaveCommand(std::istringstream & singleWordBuffer);
+
+	// Loads a game with the given filename
+	void handleLoadCommand(std::istringstream & singleWordBuffer);
+
+	// AI takes over until the end of turn (unlike original H3 currently causes AI to take over until typed again)
+	void handleGoSoloCommand();
+
+	// Toggles autoskip mode on and off. In this mode, player turns are automatically skipped and only AI moves.
+	// However, GUI is still present and allows to observe AI moves. After this option is activated, you need to end first turn manually.
+	// Press [Shift] before your turn starts to not skip it.
+	void handleAutoskipCommand();
+
+	// Gives you control over specified AI player. If none is specified gives you control over all AI players
+	void handleControlaiCommand(std::istringstream& singleWordBuffer);
+
+	// Change battle AI used by neutral creatures to the one specified. Persists through game quit
+	void handleSetBattleAICommand(std::istringstream& singleWordBuffer);
+
+	// Redraw the current screen
+	void handleRedrawCommand();
+
+	// Prints information about current screen, and saves both screens as .bmp in root folder
+	void handleScreenCommand();
+
+	// Set the state indicating if dialog box is active to "no"
+	void handleNotDialogCommand();
+
+	// Displays tree view of currently present VCMI common GUI elements
+	void handleGuiCommand();
+
+	// Dumps all game text, maps text and campaign maps text into Client log between BEGIN TEXT EXPORT and END TEXT EXPORT
+	void handleConvertTextCommand();
+
+	// Saves current game configuration into extracted/configuration folder
+	void handleGetConfigCommand();
+
+	// Dumps all scripts in Extracted/Scripts
+	void handleGetScriptsCommand();
+
+	// Dumps all .txt files from DATA into Extracted/DATA
+	void handleGetTextCommand();
+
+	// Extract .def animation as BMP files
+	void handleDef2bmpCommand(std::istringstream& singleWordBuffer);
+
+	// Export file into Extracted directory
+	void handleExtractCommand(std::istringstream& singleWordBuffer);
+
+	// Print in console the current bonuses for curent army
+	void handleBonusesCommand(std::istringstream & singleWordBuffer);
+
+	// Get what artifact is present on artifact slot with specified ID for hero with specified ID
+	void handleTellCommand(std::istringstream& singleWordBuffer);
+
+	// Show current movement points, max movement points on land / max movement points on water.
+	void handleMpCommand();
+
+	// set <command> <on/off> - sets special temporary settings that reset on game quit.
+	void handleSetCommand(std::istringstream& singleWordBuffer);
+
+	// Unlocks specific mutex known in VCMI code as "pim"
+	void handleUnlockCommand(std::istringstream& singleWordBuffer);
+
+	// Crashes the game forcing an exception
+	void handleCrashCommand();
+
+	// Prints in Chat the given message
 	void printCommandMessage(const std::string &commandMessage, ELogLevel::ELogLevel messageType = ELogLevel::NOT_SET);
-	void handleGoSolo();
-	void handleControlAi(const std::string &colorName);
+	void printInfoAboutInterfaceObject(const CIntObject *obj, int level);
+	void giveTurn(const PlayerColor &color);
 
 public:
 	ClientCommandManager() = default;
-	void processCommand(const std::string &message, bool calledFromIngameConsole);
+	void processCommand(const std::string & message, bool calledFromIngameConsole);
 };