1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-11-25 22:42:04 +02:00

Integrate EditorCallback into mapeditor

EditorCallback being set up with std::unique_ptr stored in MapController.
This commit is contained in:
Michał Zaremba
2025-06-02 15:30:08 +02:00
parent b2e51a5fb1
commit ebe746d0cf
19 changed files with 151 additions and 46 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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"

View File

@@ -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);

View File

@@ -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);
}
};

View File

@@ -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

View File

@@ -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");

View File

@@ -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);
}
}

View File

@@ -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()));
}
}

View File

@@ -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));

View File

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

View File

@@ -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/>

View File

@@ -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)

View File

@@ -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());
}

View File

@@ -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();

View File

@@ -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;

View File

@@ -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));
}
}

View File

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