瀏覽代碼

Integrate EditorCallback into mapeditor

EditorCallback being set up with std::unique_ptr stored in MapController.
Michał Zaremba 4 月之前
父節點
當前提交
ebe746d0cf

+ 4 - 0
lib/CMakeLists.txt

@@ -486,8 +486,12 @@ set(lib_MAIN_HEADERS
 	callback/GameRandomizer.h
 	callback/MapInfoCallback.h
 	callback/EditorCallback.h
+<<<<<<< HEAD
 	
 	campaign/CampaignBonus.h
+=======
+
+>>>>>>> eeff61da6 (Integrate EditorCallback into mapeditor)
 	campaign/CampaignConstants.h
 	campaign/CampaignHandler.h
 	campaign/CampaignRegions.h

+ 13 - 5
mapeditor/EditorCallback.cpp → lib/callback/EditorCallback.cpp

@@ -1,3 +1,12 @@
+/*
+ * EditorCallback.cpp, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
 #include "StdInc.h"
 #include "EditorCallback.h"
 #include "../lib/mapping/CMap.h"
@@ -5,6 +14,8 @@
 #define THROW_EDITOR_UNSUPPORTED \
 	throw std::runtime_error(std::string("EditorCallback: ") + __func__ + " is not available in map editor")
 
+VCMI_LIB_NAMESPACE_BEGIN
+
 const CMap * EditorCallback::getMapConstPtr() const
 {
 	if(!map)
@@ -136,11 +147,6 @@ bool EditorCallback::isVisibleFor(const CGObjectInstance *obj, PlayerColor playe
 	THROW_EDITOR_UNSUPPORTED;
 }
 
-void EditorCallback::pickAllowedArtsSet(std::vector<ArtifactID> &, vstd::RNG &)
-{
-	THROW_EDITOR_UNSUPPORTED;
-}
-
 #if SCRIPTING_ENABLED
 scripting::Pool * EditorCallback::getGlobalContextPool() const
 {
@@ -187,3 +193,5 @@ int EditorCallback::getResource(PlayerColor, GameResID) const
 {
 	THROW_EDITOR_UNSUPPORTED;
 }
+
+VCMI_LIB_NAMESPACE_END

+ 9 - 5
mapeditor/EditorCallback.h → lib/callback/EditorCallback.h

@@ -11,7 +11,9 @@
 
 #include "../lib/callback/MapInfoCallback.h"
 
-class EditorCallback : public MapInfoCallback
+VCMI_LIB_NAMESPACE_BEGIN
+
+class DLL_LINKAGE EditorCallback : public MapInfoCallback
 {
 protected:
 	const CMap * getMapConstPtr() const override;
@@ -49,10 +51,8 @@ public:
 	bool isTeleportChannelUnidirectional(TeleportChannelID id, PlayerColor player) const override;
 	bool isTeleportEntrancePassable(const CGTeleport * obj, PlayerColor player) const override;
 
-	bool isVisibleFor(int3 pos, PlayerColor player) const;
-	bool isVisibleFor(const CGObjectInstance * obj, PlayerColor player) const;
-
-	void pickAllowedArtsSet(std::vector<ArtifactID> & out, vstd::RNG & rand) override;
+	bool isVisibleFor(int3 pos, PlayerColor player) const override;
+	bool isVisibleFor(const CGObjectInstance * obj, PlayerColor player) const override;
 
 // Optional scripting
 #if SCRIPTING_ENABLED
@@ -69,6 +69,10 @@ public:
 	EPlayerStatus getPlayerStatus(PlayerColor player, bool verbose) const override;
 	int getResource(PlayerColor player, GameResID which) const override;
 
+	virtual ~EditorCallback() = default;
+
 private:
 	const CMap * map;
 };
+
+VCMI_LIB_NAMESPACE_END

+ 9 - 0
lib/callback/MapInfoCallback.cpp

@@ -1,3 +1,12 @@
+/*
+ * MapInfoCallback.cpp, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
 #include "StdInc.h"
 #include "MapInfoCallback.h"
 #include "../constants/EntityIdentifiers.h"

+ 1 - 0
lib/entities/artifact/ArtSlotInfo.h

@@ -21,6 +21,7 @@ struct DLL_LINKAGE ArtSlotInfo : public GameCallbackHolder
 	ArtifactInstanceID artifactID;
 	bool locked = false; //if locked, then artifact points to the combined artifact
 
+	ArtSlotInfo() = delete;
 	explicit ArtSlotInfo(IGameInfoCallback * cb);
 	ArtSlotInfo(const CArtifactInstance * artifact, bool locked);
 

+ 4 - 0
lib/mapObjectConstructors/CDefaultObjectTypeHandler.h

@@ -29,6 +29,8 @@ class CDefaultObjectTypeHandler : public AObjectTypeHandler
 
 	std::shared_ptr<CGObjectInstance> create(IGameInfoCallback * cb, std::shared_ptr<const ObjectTemplate> tmpl) const final
 	{
+		assert(cb);
+
 		auto result = createObject(cb);
 
 		preInitObject(result.get());
@@ -46,6 +48,8 @@ protected:
 	virtual void randomizeObject(ObjectType * object, IGameRandomizer & gameRandomizer) const {}
 	virtual std::shared_ptr<ObjectType> createObject(IGameInfoCallback * cb) const
 	{
+		assert(cb);
+
 		return std::make_shared<ObjectType>(cb);
 	}
 };

+ 0 - 2
mapeditor/CMakeLists.txt

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

+ 3 - 8
mapeditor/helper.cpp

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

+ 3 - 2
mapeditor/helper.h

@@ -12,10 +12,11 @@
 
 class CMap;
 class CampaignState;
+class IGameInfoCallback;
 
 namespace Helper
 {
-	std::unique_ptr<CMap> openMapInternal(const QString &);
+	std::unique_ptr<CMap> openMapInternal(const QString &, IGameInfoCallback *);
 	std::shared_ptr<CampaignState> openCampaignInternal(const QString &);
 	void saveCampaign(std::shared_ptr<CampaignState> campaignState, const QString & filename);
-}
+}

+ 3 - 4
mapeditor/inspector/artifactwidget.cpp

@@ -43,19 +43,18 @@ ArtifactWidget::ArtifactWidget(CArtifactFittingSet & fittingSet, QWidget * paren
 	}
 	ui->possiblePositions->addItem(QString::fromStdString(NArtifactPosition::backpack), ArtifactPosition::BACKPACK_START);
 	fillArtifacts();
-
-
 }
 
 void ArtifactWidget::fillArtifacts()
 {
 	ui->artifact->clear();
 	auto currentSlot = ui->possiblePositions->currentData().toInt();
-	for (const auto& art : LIBRARY->arth->getDefaultAllowed())
+	for (const auto & art : LIBRARY->arth->getDefaultAllowed())
 	{
 		auto artifact = art.toArtifact();
 		// forbid spell scroll for now as require special handling
-		if (artifact->canBePutAt(&fittingSet, currentSlot, true) && artifact->getId() != ArtifactID::SPELL_SCROLL) {
+		if (artifact->canBePutAt(&fittingSet, currentSlot, true) && artifact->getId() != ArtifactID::SPELL_SCROLL)
+		{
 			ui->artifact->addItem(QString::fromStdString(artifact->getNameTranslated()), QVariant::fromValue(artifact->getIndex()));
 		}
 	}

+ 24 - 5
mapeditor/inspector/heroartifactswidget.cpp

@@ -28,6 +28,10 @@ HeroArtifactsWidget::HeroArtifactsWidget(MapController & controller, CGHeroInsta
 	fittingSet(CArtifactFittingSet(h))
 {
 	ui->setupUi(this);
+
+	connect(ui->saveButton, &QPushButton::clicked, this, &HeroArtifactsWidget::onSaveButtonClicked);
+	connect(ui->cancelButton, &QPushButton::clicked, this, &HeroArtifactsWidget::onCancelButtonClicked);
+
 }
 
 HeroArtifactsWidget::~HeroArtifactsWidget()
@@ -37,9 +41,10 @@ HeroArtifactsWidget::~HeroArtifactsWidget()
 
 void HeroArtifactsWidget::on_addButton_clicked()
 {
-	ArtifactWidget artifactWidget{ fittingSet, this };
-	connect(&artifactWidget, &ArtifactWidget::saveArtifact, this, &HeroArtifactsWidget::onSaveArtifact);
-	artifactWidget.exec();
+	auto * artifactWidget = new ArtifactWidget(fittingSet, this);
+	connect(artifactWidget, &ArtifactWidget::saveArtifact, this, &HeroArtifactsWidget::onSaveArtifact);
+	artifactWidget->exec();
+	artifactWidget->deleteLater();
 }
 
 void HeroArtifactsWidget::on_removeButton_clicked()
@@ -55,6 +60,16 @@ void HeroArtifactsWidget::on_removeButton_clicked()
 	ui->artifacts->removeRow(row);
 }
 
+void HeroArtifactsWidget::onSaveButtonClicked()
+{
+	accept();
+}
+
+void HeroArtifactsWidget::onCancelButtonClicked()
+{
+	reject();
+}
+
 void HeroArtifactsWidget::onSaveArtifact(int32_t artifactIndex, ArtifactPosition slot) 
 {
 	auto artifact = controller.map()->createArtifact(LIBRARY->arth->getByIndex(artifactIndex)->getId());
@@ -143,8 +158,11 @@ void HeroArtifactsDelegate::setModelData(QWidget * editor, QAbstractItemModel *
 {
 	if (auto * ed = qobject_cast<HeroArtifactsWidget *>(editor))
 	{
-		ed->commitChanges();
-		updateModelData(model, index);
+		if(ed->result() == QDialog::Accepted)
+		{
+			ed->commitChanges();
+			updateModelData(model, index);
+		}
 	}
 	else
 	{
@@ -158,6 +176,7 @@ void HeroArtifactsDelegate::updateModelData(QAbstractItemModel * model, const QM
 	for(const auto & [artPosition, artSlotInfo] : hero.artifactsWorn)
 	{
 		auto slotText = NArtifactPosition::namesHero[artPosition.num];
+
 		textList += QString("%1: %2").arg(QString::fromStdString(slotText)).arg(QString::fromStdString(artSlotInfo.getArt()->getType()->getNameTranslated()));
 	}
 	textList += QString("%1:").arg(QString::fromStdString(NArtifactPosition::backpack));

+ 4 - 0
mapeditor/inspector/heroartifactswidget.h

@@ -38,6 +38,10 @@ private slots:
 
 	void on_removeButton_clicked();
 
+	void onSaveButtonClicked();
+
+	void onCancelButtonClicked();
+
 private:
 	enum Column
 	{

+ 38 - 7
mapeditor/inspector/heroartifactswidget.ui

@@ -3,7 +3,7 @@
  <class>HeroArtifactsWidget</class>
  <widget class="QDialog" name="HeroArtifactsWidget">
   <property name="windowModality">
-   <enum>Qt::NonModal</enum>
+   <enum>Qt::WindowModality::NonModal</enum>
   </property>
   <property name="geometry">
    <rect>
@@ -46,7 +46,7 @@
      <item>
       <spacer name="horizontalSpacer">
        <property name="orientation">
-        <enum>Qt::Horizontal</enum>
+        <enum>Qt::Orientation::Horizontal</enum>
        </property>
        <property name="sizeHint" stdset="0">
         <size>
@@ -96,19 +96,19 @@
       <bool>true</bool>
      </property>
      <property name="horizontalScrollBarPolicy">
-      <enum>Qt::ScrollBarAlwaysOff</enum>
+      <enum>Qt::ScrollBarPolicy::ScrollBarAlwaysOff</enum>
      </property>
      <property name="sizeAdjustPolicy">
-      <enum>QAbstractScrollArea::AdjustToContents</enum>
+      <enum>QAbstractScrollArea::SizeAdjustPolicy::AdjustToContents</enum>
      </property>
      <property name="editTriggers">
-      <set>QAbstractItemView::NoEditTriggers</set>
+      <set>QAbstractItemView::EditTrigger::NoEditTriggers</set>
      </property>
      <property name="selectionMode">
-      <enum>QAbstractItemView::SingleSelection</enum>
+      <enum>QAbstractItemView::SelectionMode::SingleSelection</enum>
      </property>
      <property name="selectionBehavior">
-      <enum>QAbstractItemView::SelectRows</enum>
+      <enum>QAbstractItemView::SelectionBehavior::SelectRows</enum>
      </property>
      <attribute name="horizontalHeaderVisible">
       <bool>true</bool>
@@ -137,6 +137,37 @@
      </column>
     </widget>
    </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayoutBottom">
+     <item>
+      <spacer name="horizontalSpacerBottom">
+       <property name="orientation">
+        <enum>Qt::Orientation::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+     <item>
+      <widget class="QPushButton" name="saveButton">
+       <property name="text">
+        <string>Save</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="cancelButton">
+       <property name="text">
+        <string>Cancel</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
   </layout>
  </widget>
  <resources/>

+ 11 - 3
mapeditor/inspector/inspector.cpp

@@ -41,6 +41,7 @@ Initializer::Initializer(MapController & controller, CGObjectInstance * o, const
 	, defaultPlayer(pl)
 {
 	logGlobal->info("New object instance initialized");
+	o->cb = controller.getCallback();
 ///IMPORTANT! initialize order should be from base objects to derived objects
 	INIT_OBJ_TYPE(CGResource);
 	INIT_OBJ_TYPE(CGArtifact);
@@ -206,6 +207,13 @@ void Initializer::initialize(CGArtifact * o)
 		auto a = controller.map()->createScroll(*RandomGeneratorUtil::nextItem(out, CRandomGenerator::getDefault()));
 		o->setArtifactInstance(a);
 	}
+	else if(o->ID == Obj::ARTIFACT)
+	{
+		auto instance = controller.map()->createArtifact(o->getArtifactType());
+		o->setArtifactInstance(instance);
+	}
+	else
+		throw std::runtime_error("Unimplemented initializer for CGArtifact object ID = "+ std::to_string(o->ID.getNum()));
 }
 
 void Initializer::initialize(CGMine * o)
@@ -365,11 +373,11 @@ void Inspector::updateProperties(CGTownInstance * o)
 void Inspector::updateProperties(CGArtifact * o)
 {
 	if(!o) return;
-	
+
 	addProperty(QObject::tr("Message"), o->message, false);
-	
+
 	const CArtifactInstance * instance = o->getArtifactInstance();
-	if(instance)
+	if(instance && o->ID == Obj::SPELL_SCROLL)
 	{
 		SpellID spellId = instance->getScrollSpellID();
 		if(spellId != SpellID::NONE)

+ 4 - 3
mapeditor/mainwindow.cpp

@@ -395,7 +395,7 @@ bool MainWindow::openMap(const QString & filenameSelect)
 {
 	try
 	{
-		controller.setMap(Helper::openMapInternal(filenameSelect));
+		controller.setMap(Helper::openMapInternal(filenameSelect, controller.getCallback()));
 	}
 	catch(const ModIncompatibility & e)
 	{
@@ -703,7 +703,7 @@ void MainWindow::addGroupIntoCatalog(const QString & groupName, bool useCustomNa
 			}
 			
 			//create object to extract name
-			auto temporaryObj(factory->create(nullptr, templ));
+			auto temporaryObj(factory->create(controller.getCallback(), templ));
 			QString translated = useCustomName ? QString::fromStdString(temporaryObj->getObjectName().c_str()) : subGroupName;
 			itemType->setText(translated);
 			
@@ -1370,7 +1370,8 @@ void MainWindow::on_actionh3m_converter_triggered()
 		for(auto & m : mapFiles)
 		{
 			CMapService mapService;
-			auto map = Helper::openMapInternal(m);
+			auto map = Helper::openMapInternal(m, controller.getCallback());
+			controller.setCallback(std::make_unique<EditorCallback>(map.get()));
 			controller.repairMap(map.get());
 			mapService.saveMap(map, (saveDirectory + '/' + QFileInfo(m).completeBaseName() + ".vmap").toStdString());
 		}

+ 15 - 0
mapeditor/mapcontroller.cpp

@@ -51,6 +51,7 @@ MapController::MapController(MainWindow * m): main(m)
 		_miniscenes[i].reset(new MinimapScene(i));
 	}
 	connectScenes();
+	_cb = std::make_unique<EditorCallback>(nullptr);
 }
 
 void MapController::connectScenes()
@@ -70,6 +71,16 @@ MapController::~MapController()
 	main = nullptr;
 }
 
+void MapController::setCallback(std::unique_ptr<EditorCallback> cb)
+{
+	_cb = std::move(cb);
+}
+
+EditorCallback * MapController::getCallback()
+{
+	return _cb.get();
+}
+
 const std::unique_ptr<CMap> & MapController::getMapUniquePtr() const
 {
 	return _map;
@@ -104,6 +115,8 @@ void MapController::repairMap(CMap * map)
 {
 	if(!map)
 		return;
+
+	assert(map->cb);
 	
 	//make sure events/rumors has name to have proper identifiers
 	int emptyNameId = 1;
@@ -201,7 +214,9 @@ void MapController::repairMap(CMap * map)
 
 void MapController::setMap(std::unique_ptr<CMap> cmap)
 {
+	cmap->cb = _cb.get();
 	_map = std::move(cmap);
+	_cb->setMap(_map.get());
 	
 	repairMap();
 	

+ 4 - 0
mapeditor/mapcontroller.h

@@ -13,6 +13,7 @@
 #include "maphandler.h"
 #include "mapview.h"
 #include "lib/modding/ModVerificationInfo.h"
+#include "../lib/callback/EditorCallback.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 using ModCompatibilityInfo = std::map<std::string, ModVerificationInfo>;
@@ -31,6 +32,8 @@ public:
 	MapController(const MapController &&) = delete;
 	~MapController();
 	
+	void setCallback(std::unique_ptr<EditorCallback>);
+	EditorCallback * getCallback();
 	void setMap(std::unique_ptr<CMap>);
 	void initObstaclePainters(CMap * map);
 	
@@ -93,6 +96,7 @@ signals:
 	void requestModsUpdate(const ModCompatibilityInfo & mods, bool leaveCheckedUnchanged) const;
 	
 private:
+	std::unique_ptr<EditorCallback> _cb;
 	std::unique_ptr<CMap> _map;
 	std::unique_ptr<MapHandler> _mapHandler;
 	MainWindow * main;

+ 1 - 1
mapeditor/mapview.cpp

@@ -594,7 +594,7 @@ void MapView::dragEnterEvent(QDragEnterEvent * event)
 				auto factory = LIBRARY->objtypeh->getHandlerFor(objId, objSubId);
 				auto templ = factory->getTemplates()[templateId];
 				controller->discardObject(sc->level);
-				controller->createObject(sc->level, factory->create(nullptr, templ));
+				controller->createObject(sc->level, factory->create(controller->getCallback(), templ));
 			}
 		}
 		

+ 1 - 1
mapeditor/windownewmap.cpp

@@ -512,4 +512,4 @@ void WindowNewMap::on_sizeCustomRadio_toggled(bool checked)
 		ui->sizeGroup2->setEnabled(true);
 	}
 	updateTemplateList();
-}
+}