Noggit is now able to write DBC.

Add Map Creation Wizard ui.
This commit is contained in:
Skarn
2020-11-01 14:27:38 +03:00
parent eeaebefe64
commit bb0f7537ca
8 changed files with 663 additions and 24 deletions

View File

@@ -5,6 +5,19 @@
#include <noggit/MPQ.h>
#include <string>
#include <QSettings>
#include <QDir>
#include <fstream>
#include <cstdint>
#include <algorithm>
#include <cstring>
template<typename T> inline
auto write(std::ostream& stream, T const& val) -> void
{
stream.write(reinterpret_cast<char const*>(&val), sizeof(T));
}
DBCFile::DBCFile(const std::string& _filename)
: filename(_filename)
@@ -43,3 +56,115 @@ void DBCFile::open()
f.close();
}
void DBCFile::save()
{
QSettings app_settings;
QString str = app_settings.value ("project/path").toString();
if (!(str.endsWith('\\') || str.endsWith('/')))
{
str += "/";
}
std::string filename_proj = noggit::mpq::normalized_filename(str.toStdString() + filename);
QDir dir(str + "/DBFilesClient/");
if (!dir.exists())
dir.mkpath(".");
std::ofstream stream(filename_proj, std::ios_base::out | std::ios_base::trunc | std::ios_base::binary);
stream << 'W' << 'D' << 'B' << 'C';
write(stream, recordCount);
write(stream, fieldCount);
write(stream, recordSize);
write(stream, stringSize);
stream.write(reinterpret_cast<char*>(data.data()), data.size());
stream.write(stringTable.data(), stringSize);
stream.close();
}
DBCFile::Record DBCFile::addRecord(size_t id, size_t id_field)
{
recordCount++;
for (Iterator i = begin(); i != end(); ++i)
{
if (i->getUInt(id_field) == id)
throw AlreadyExists();
}
size_t old_size = data.size();
data.resize(old_size + recordSize);
*reinterpret_cast<unsigned int*>(data.data() + old_size + id_field * sizeof(std::uint32_t)) = id;
return Record(*this, data.data() + old_size);
}
DBCFile::Record DBCFile::addRecordCopy(size_t id, size_t id_from, size_t id_field)
{
recordCount++;
bool from_found = false;
size_t from_idx = 0;
for (Iterator i = begin(); i != end(); ++i)
{
if (i->getUInt(id_field) == id)
throw AlreadyExists();
if (i->getUInt(id_field) == id_from)
{
from_found = true;
}
if (!from_found)
{
from_idx++;
}
}
if (!from_found)
{
throw NotFound();
}
size_t old_size = data.size();
data.resize(old_size + recordSize);
Record record_from = getRecord(from_idx);
std::copy(data.data() + from_idx * recordSize, data.data() + from_idx * recordSize + recordSize, data.data() + old_size);
*reinterpret_cast<unsigned int*>(data.data() + old_size + id_field * sizeof(std::uint32_t)) = id;
return Record(*this, data.data() + old_size);
}
void DBCFile::removeRecord(size_t id, size_t id_field)
{
recordCount--;
size_t counter = 0;
for (Iterator i = begin(); i != end(); ++i)
{
if (i->getUInt(id_field) == id)
{
size_t initial_size = data.size();
unsigned char* record = data.data() + counter * recordSize;
std::memmove(record, record + recordSize, recordSize * (recordCount - counter + 1));
data.resize(initial_size - recordSize);
return;
}
counter++;
}
throw NotFound();
}

View File

@@ -6,6 +6,8 @@
#include <string>
#include <vector>
#include <stdexcept>
#include <cstring>
#include <algorithm>
class DBCFile
{
@@ -14,11 +16,19 @@ public:
// Open database. It must be openened before it can be used.
void open();
void save();
class NotFound : public std::runtime_error
{
public:
NotFound() : std::runtime_error("Key was not found")
NotFound() : std::runtime_error("Key was not found.")
{ }
};
class AlreadyExists : public std::runtime_error
{
public:
AlreadyExists() : std::runtime_error("Key already exists.")
{ }
};
@@ -26,35 +36,35 @@ public:
class Record
{
public:
const float& getFloat(size_t field) const
float& getFloat(size_t field)
{
assert(field < file.fieldCount);
return *reinterpret_cast<float*>(offset + field * 4);
}
const unsigned int& getUInt(size_t field) const
unsigned int& getUInt(size_t field)
{
assert(field < file.fieldCount);
return *reinterpret_cast<unsigned int*>(offset + field * 4);
}
const int& getInt(size_t field) const
int& getInt(size_t field)
{
assert(field < file.fieldCount);
return *reinterpret_cast<int*>(offset + field * 4);
}
const char *getString(size_t field) const
char *getString(size_t field)
{
assert(field < file.fieldCount);
size_t stringOffset = getUInt(field);
assert(stringOffset < file.stringSize);
return file.stringTable.data() + stringOffset;
}
const char *getLocalizedString(size_t field, int locale = -1) const
char *getLocalizedString(size_t field, int locale = -1)
{
int loc = locale;
if (locale == -1)
{
assert(field < file.fieldCount - 8);
for (loc = 0; loc < 9; loc++)
for (loc = 0; loc < 16; loc++)
{
size_t stringOffset = getUInt(field + loc);
if (stringOffset != 0)
@@ -67,9 +77,38 @@ public:
assert(stringOffset < file.stringSize);
return file.stringTable.data() + stringOffset;
}
template<typename T> inline
void write(size_t field, T val)
{
static_assert(sizeof(T) == 4, "This function only writes int/uint/float values.");
assert(field < file.fieldCount);
*reinterpret_cast<T*>(offset + field * 4) = val;
}
void writeString(size_t field, std::string& val)
{
assert(field < file.fieldCount);
size_t old_size = file.stringTable.size();
*reinterpret_cast<unsigned int*>(offset + field * 4) = file.stringTable.size();
file.stringTable.resize(old_size + val.size() + 1);
std::copy(val.c_str(), val.c_str() + val.size() + 1, file.stringTable.data() + old_size);
}
void writeLocalizedString(size_t field, std::string& val, int locale)
{
assert(field < file.fieldCount);
size_t old_size = file.stringTable.size();
*reinterpret_cast<unsigned int*>(offset + field + locale * 4) = file.stringTable.size();
file.stringTable.resize(old_size + val.size() + 1);
std::copy(val.c_str(), val.c_str() + val.size() + 1, file.stringTable.data() + old_size);
}
private:
Record(const DBCFile &pfile, unsigned char *poffset) : file(pfile), offset(poffset) {}
const DBCFile &file;
Record(DBCFile &pfile, unsigned char *poffset) : file(pfile), offset(poffset) {}
DBCFile &file;
unsigned char *offset;
friend class DBCFile;
@@ -80,7 +119,7 @@ public:
class Iterator
{
public:
Iterator(const DBCFile &file, unsigned char *offset) :
Iterator(DBCFile &file, unsigned char *offset) :
record(file, offset) {}
/// Advance (prefix only)
Iterator & operator++() {
@@ -88,16 +127,16 @@ public:
return *this;
}
/// Return address of current instance
Record const & operator*() const { return record; }
const Record* operator->() const {
Record & operator*() { return record; }
Record* operator->() {
return &record;
}
/// Comparison
bool operator==(const Iterator &b) const
bool operator==( Iterator const &b)
{
return record.offset == b.record.offset;
}
bool operator!=(const Iterator &b) const
bool operator!=( Iterator const &b)
{
return record.offset != b.record.offset;
}
@@ -119,8 +158,8 @@ public:
return Iterator(*this, data.data() + data.size());
}
inline size_t getRecordCount() const { return recordCount; }
inline size_t getFieldCount() const { return fieldCount; }
inline size_t getRecordCount() { return recordCount; }
inline size_t getFieldCount() { return fieldCount; }
inline Record getByID(unsigned int id, size_t field = 0)
{
for (Iterator i = begin(); i != end(); ++i)
@@ -131,12 +170,16 @@ public:
throw NotFound();
}
Record addRecord(size_t id, size_t id_field = 0);
Record addRecordCopy(size_t id, size_t id_from, size_t id_field = 0);
void removeRecord(size_t id, size_t id_field = 0);
private:
std::string filename;
size_t recordSize;
size_t recordCount;
size_t fieldCount;
size_t stringSize;
std::uint32_t recordSize;
std::uint32_t recordCount;
std::uint32_t fieldCount;
std::uint32_t stringSize;
std::vector<unsigned char> data;
std::vector<char> stringTable;
};

View File

@@ -1605,6 +1605,8 @@ void MapView::saveMinimap(MinimapRenderSettings* settings)
// And we do, to avoid loading geometry twice. Even though, offscreen one in the background would be nice.
// The idea is, if rendering fails due to unfinished loading, we skip to the next frame until we are able to render.
opengl::context::scoped_setter const _ (::gl, context());
switch (settings->export_mode)
{
case MinimapGenMode::CURRENT_ADT:

View File

@@ -0,0 +1,350 @@
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
#include "MapCreationWizard.hpp"
#include <noggit/ui/font_awesome.hpp>
#include <noggit/MapView.h>
#include <noggit/World.h>
#include <noggit/Log.h>
#include <util/qt/overload.hpp>
#include <QFormLayout>
#include <QGridLayout>
#include <QGroupBox>
#include <QCheckBox>
#include <QButtonGroup>
#include <QPushButton>
#include <QScrollArea>
#include <QWheelEvent>
#include <QApplication>
#include <QComboBox>
#include <QStackedWidget>
using namespace noggit::Red::MapCreationWizard::Ui;
MapCreationWizard::MapCreationWizard(QWidget* parent) : noggit::ui::widget(parent)
{
setWindowTitle ("Map Creation Wizard");
setWindowIcon (QIcon (":/icon"));
setWindowFlags(Qt::Window | Qt::WindowStaysOnTopHint);
//setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
auto layout = new QHBoxLayout(this);
// Left side
auto layout_left = new QFormLayout (this);
layout->addLayout(layout_left);
auto scroll_minimap = new QScrollArea(this);
scroll_minimap->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
_minimap_widget = new noggit::ui::minimap_widget(this);
_minimap_widget->draw_boundaries(true);
layout_left->addWidget(scroll_minimap);
scroll_minimap->setAlignment(Qt::AlignCenter);
scroll_minimap->setWidget(_minimap_widget);
scroll_minimap->setWidgetResizable(true);
scroll_minimap->setFixedSize(QSize(512, 512));
// Right side
auto layout_right = new QVBoxLayout (this);
layout->addLayout(layout_right);
auto layout_selector = new QHBoxLayout(this);
layout_right->addItem(layout_selector);
_selected_map = new QComboBox(this);
layout_selector->addWidget(new QLabel("Map:"));
layout_selector->addWidget(_selected_map);
_corpse_map_id = new QComboBox(this);
_corpse_map_id->addItem("None");
_corpse_map_id->setItemData(0, QVariant (-1));
// Fill selector combo
int count = 0;
for (DBCFile::Iterator i = gMapDB.begin(); i != gMapDB.end(); ++i)
{
int map_id = i->getInt(MapDB::MapID);
std::string name = i->getLocalizedString(MapDB::Name);
int area_type = i->getUInt(MapDB::AreaType);
if (area_type < 0 ||area_type > 4 || !World::IsEditableWorld(map_id))
continue;
_selected_map->addItem(QString::number(map_id) + " - " + QString::fromUtf8 (name.c_str()));
_selected_map->setItemData(count, QVariant (map_id));
_corpse_map_id->addItem(QString::number(map_id) + " - " + QString::fromUtf8 (name.c_str()));
_corpse_map_id->setItemData(count + 1, QVariant (map_id));
count++;
}
auto add_btn = new QPushButton(this);
add_btn->setIcon(noggit::ui::font_awesome_icon(noggit::ui::font_awesome::plus));
layout_selector->addWidget(add_btn);
auto remove_btn = new QPushButton(this);
remove_btn->setIcon(noggit::ui::font_awesome_icon(noggit::ui::font_awesome::timescircle));
layout_selector->addWidget(remove_btn);
_map_settings = new QGroupBox("Map settings", this);
layout_right->addWidget(_map_settings);
auto map_settings_layout = new QFormLayout(_map_settings);
_map_settings->setLayout(map_settings_layout);
_directory = new QLineEdit(_map_settings);
map_settings_layout->addRow("Map directory:", _directory);
_instance_type = new QComboBox(_map_settings);
_instance_type->addItem("None");
_instance_type->setItemData(0, QVariant(0));
_instance_type->addItem("Instance Crusade");
_instance_type->setItemData(1, QVariant(1));
_instance_type->addItem("Raid");
_instance_type->setItemData(2, QVariant(2));
_instance_type->addItem("Battleground");
_instance_type->setItemData(3, QVariant(3));
_instance_type->addItem("Arena");
_instance_type->setItemData(4, QVariant(4));
map_settings_layout->addRow("Map type:",_instance_type);
_map_name = new LocaleDBCEntry(_map_settings);
map_settings_layout->addRow("Map name:",_map_name);
_area_table_id = new QSpinBox(_map_settings);
map_settings_layout->addRow("Area ID:",_area_table_id);
_map_desc_alliance = new LocaleDBCEntry(_map_settings);
map_settings_layout->addRow("Description (Alliance):",_map_desc_alliance);
_map_desc_horde = new LocaleDBCEntry(_map_settings);
map_settings_layout->addRow("Description (Horde):",_map_desc_horde);
_loading_screen = new QSpinBox(_map_settings);
map_settings_layout->addRow("Loading screen:",_loading_screen);
_minimap_icon_scale = new QDoubleSpinBox(_map_settings);
map_settings_layout->addRow("Minimap icon scale:",_minimap_icon_scale);
_corpse_map_id->setCurrentText("None");
map_settings_layout->addRow("Corpse map:",_corpse_map_id);
_corpse_x = new QDoubleSpinBox(_map_settings);
map_settings_layout->addRow("Corpse X:",_corpse_x);
_corpse_y = new QDoubleSpinBox(_map_settings);
map_settings_layout->addRow("Corpse Y:",_corpse_y);
_time_of_day_override = new QSpinBox(_map_settings);
_time_of_day_override->setMinimum(-1);
_time_of_day_override->setValue(-1);
map_settings_layout->addRow("Daytime override:",_time_of_day_override);
_expansion_id = new QComboBox(_map_settings);
_expansion_id->addItem("Classic");
_expansion_id->setItemData(0, QVariant(0));
_expansion_id->addItem("Burning Crusade");
_expansion_id->setItemData(1, QVariant(1));
_expansion_id->addItem("Wrath of the Lich King");
_expansion_id->setItemData(2, QVariant(2));
map_settings_layout->addRow("Expansion:",_expansion_id);
_raid_offset = new QSpinBox(_map_settings);
map_settings_layout->addRow("Raid offset:",_raid_offset);
_max_players = new QSpinBox(_map_settings);
map_settings_layout->addRow("Max players:",_max_players);
selectMap(_selected_map->itemData(_selected_map->currentIndex()).toInt());
// Connections
connect(_selected_map, QOverload<int>::of(&QComboBox::currentIndexChanged)
, [&] (int index)
{
selectMap(_selected_map->itemData(index).toInt());
}
);
}
void MapCreationWizard::selectMap(int map_id)
{
DBCFile::Record record = gMapDB.getByID(map_id);
_world = std::make_unique<World>(record.getString(MapDB::InternalName), map_id); // verify if leaks here
_minimap_widget->world(_world.get());
_directory->setText(record.getString(1));
_instance_type->setCurrentIndex(record.getInt(2));
_map_name->fill(record, 5);
_area_table_id->setValue(record.getInt(22));
_map_desc_alliance->fill(record, 23);
_map_desc_horde->fill(record, 40);
_loading_screen->setValue(record.getInt(57));
_minimap_icon_scale->setValue(record.getFloat(58));
int corpse_map_idx = record.getInt(59);
for (int i = 0; i < _corpse_map_id->count(); ++i)
{
if (_corpse_map_id->itemData(i) == corpse_map_idx)
{
_corpse_map_id->setCurrentIndex(i);
}
}
_corpse_x->setValue(record.getFloat(60));
_corpse_y->setValue(record.getFloat(61));
_time_of_day_override->setValue(record.getInt(62));
_expansion_id->setCurrentIndex(record.getInt(63));
_raid_offset->setValue(record.getInt(64));
_max_players->setValue(record.getInt(65));
}
void MapCreationWizard::wheelEvent(QWheelEvent* event)
{
if (QApplication::keyboardModifiers().testFlag(Qt::ControlModifier))
{
const int degrees = event->angleDelta().y() / 8;
int steps = degrees / 15;
auto base_size = _minimap_widget->width();
if (steps > 0)
{
auto new_size = std::max(512, base_size + 64);
_minimap_widget->setFixedSize(new_size, new_size);
} else
{
auto new_size = std::min(4096, base_size - 64);
_minimap_widget->setFixedSize(new_size, new_size);
}
event->ignore();
}
}
LocaleDBCEntry::LocaleDBCEntry(QWidget* parent) : QWidget(parent)
{
auto layout = new QHBoxLayout(this);
layout->setContentsMargins(0, 0, 0, 0);
_show_entry = new QStackedWidget(this);
_en = new QLineEdit(this);
_kr = new QLineEdit(this);
_fr = new QLineEdit(this);
_de = new QLineEdit(this);
_cn = new QLineEdit(this);
_tw = new QLineEdit(this);
_es = new QLineEdit(this);
_mx = new QLineEdit(this);
_ru = new QLineEdit(this);
_jp = new QLineEdit(this);
_pt = new QLineEdit(this);
_it = new QLineEdit(this);
_unk1 = new QLineEdit(this);
_unk2 = new QLineEdit(this);
_unk3 = new QLineEdit(this);
_unk4 = new QLineEdit(this);
_flags = new QSpinBox(this);
_flags->setVisible(false);
_show_entry->addWidget(_en);
_show_entry->addWidget(_kr);
_show_entry->addWidget(_fr);
_show_entry->addWidget(_de);
_show_entry->addWidget(_cn);
_show_entry->addWidget(_tw);
_show_entry->addWidget(_es);
_show_entry->addWidget(_mx);
_show_entry->addWidget(_ru);
_show_entry->addWidget(_jp);
_show_entry->addWidget(_pt);
_show_entry->addWidget(_it);
_show_entry->addWidget(_unk1);
_show_entry->addWidget(_unk2);
_show_entry->addWidget(_unk3);
_show_entry->addWidget(_unk4);
layout->addWidget(_show_entry);
_current_locale = new QComboBox(this);
for (auto const &loc : _locale_names)
{
_current_locale->addItem(QString::fromStdString(loc));
}
_widget_map = {
{"enUS", _en},
{"koKR", _kr},
{"frFR", _fr},
{"deDE", _de},
{"zhCN", _cn},
{"zhTW", _tw},
{"esES", _es},
{"esMX", _mx},
{"ruRU", _ru},
{"jaJP", _jp},
{"ptPT", _pt},
{"itIT", _it},
{"Unknown 1", _unk1},
{"Unknown 2", _unk2},
{"Unknown 3", _unk3},
{"Unknown 4", _unk4}
};
layout->addWidget(_current_locale);
// Connect
connect ( _current_locale, &QComboBox::currentTextChanged
, [&] (QString s)
{
setCurrentLocale(_current_locale->currentText().toStdString());
}
);
}
void LocaleDBCEntry::setCurrentLocale(const std::string& locale)
{
_show_entry->setCurrentWidget(_widget_map.at(locale));
}
void LocaleDBCEntry::fill(DBCFile::Record& record, size_t field, size_t id_field)
{
for (int loc = 0; loc < 16; ++loc)
{
setValue(record.getLocalizedString(field, loc), loc);
}
_flags->setValue(record.getInt(field + 16));
}

View File

@@ -0,0 +1,113 @@
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
#pragma once
#include <unordered_map>
#include <vector>
#include <QWidget>
#include <QLineEdit>
#include <QComboBox>
#include <QGroupBox>
#include <QSpinBox>
#include <QDoubleSpinBox>
#include <QHBoxLayout>
#include <QStackedWidget>
#include <noggit/DBC.h>
#include <noggit/DBCFile.h>
#include <noggit/ui/minimap_widget.hpp>
#include <noggit/ui/widget.hpp>
class World;
namespace noggit
{
namespace Red::MapCreationWizard::Ui
{
class LocaleDBCEntry : public QWidget
{
public:
LocaleDBCEntry(QWidget *parent = nullptr);
void setCurrentLocale(const std::string& locale);
void setValue(const std::string& val, int locale)
{
_widget_map.at(_locale_names[locale])->setText(QString::fromStdString(val));
}
void fill(DBCFile::Record& record, size_t field, size_t id_field = 0);
private:
QComboBox* _current_locale;
QStackedWidget* _show_entry;
std::unordered_map<std::string, QLineEdit*> _widget_map;
std::vector<std::string> _locale_names = {"enUS", "koKR", "frFR", "deDE", "zhCN",
"zhTW", "esES", "esMX", "ruRU", "jaJP", "ptPT", "itIT",
"Unknown 1", "Unknown 2", "Unknown 3", "Unknown 4"};
QLineEdit* _en;
QLineEdit* _kr;
QLineEdit* _fr;
QLineEdit* _de;
QLineEdit* _cn; // + nCN
QLineEdit* _tw;
QLineEdit* _es;
QLineEdit* _mx;
QLineEdit* _ru;
QLineEdit* _jp;
QLineEdit* _pt;
QLineEdit* _it;
QLineEdit* _unk1;
QLineEdit* _unk2;
QLineEdit* _unk3;
QLineEdit* _unk4;
QSpinBox* _flags;
};
class MapCreationWizard : public ui::widget
{
public:
MapCreationWizard(QWidget *parent = nullptr);
void wheelEvent(QWheelEvent *event) override;
private:
ui::minimap_widget *_minimap_widget;
QComboBox *_selected_map;
QGroupBox* _map_settings;
// Map settings
QLineEdit* _directory;
QComboBox* _instance_type;
LocaleDBCEntry* _map_name;
QSpinBox* _area_table_id;
LocaleDBCEntry* _map_desc_alliance;
LocaleDBCEntry* _map_desc_horde;
QSpinBox* _loading_screen;
QDoubleSpinBox* _minimap_icon_scale;
QComboBox *_corpse_map_id;
QDoubleSpinBox* _corpse_x;
QDoubleSpinBox* _corpse_y;
QSpinBox* _time_of_day_override;
QComboBox* _expansion_id;
QSpinBox* _raid_offset;
QSpinBox* _max_players;
std::unique_ptr<World> _world;
void selectMap(int map_id);
};
}
}

View File

@@ -2186,6 +2186,7 @@ bool World::saveMinimap(tile_index const& tile_idx, MinimapRenderSettings* setti
gl.colorMask(true, true, true, true);
QImage image = pixel_buffer.toImage();
image = image.convertToFormat(QImage::Format_RGBA8888);
QSettings app_settings;
QString str = app_settings.value ("project/path").toString();
@@ -2203,12 +2204,13 @@ bool World::saveMinimap(tile_index const& tile_idx, MinimapRenderSettings* setti
buffer.open( QIODevice::WriteOnly );
image.save( &buffer, "PNG" );
image.save(std::string(basename + "_" + std::to_string(tile_idx.x) + "_" + std::to_string(tile_idx.z) + ".png").c_str());
auto blp = Png2Blp();
blp.load(reinterpret_cast<const void*>(bytes.constData()), bytes.size());
uint32_t file_size;
void* blp_image = blp.createBlpDxtInMemory(true, FORMAT_DXT5, file_size);
void* blp_image = blp.createBlpUncompressedInMemory(true, file_size);
std::string tex_name = std::string(basename + "_" + std::to_string(tile_idx.x) + "_" + std::to_string(tile_idx.z) + ".blp");
@@ -2232,12 +2234,12 @@ bool World::saveMinimap(tile_index const& tile_idx, MinimapRenderSettings* setti
if (combined_image.width() != 8192 | combined_image.height() != 8192)
{
combined_image = QImage(8192, 8192, QImage::Format_ARGB32);
combined_image = QImage(8192, 8192, QImage::Format_RGBA8888);
}
}
else
{
combined_image = QImage(8192, 8192, QImage::Format_ARGB32);
combined_image = QImage(8192, 8192, QImage::Format_RGBA8888);
}
QImage scaled_image = image.scaled(128, 128, Qt::KeepAspectRatio);

View File

@@ -10,6 +10,7 @@
#include <noggit/ui/minimap_widget.hpp>
#include <noggit/ui/uid_fix_window.hpp>
#include <noggit/uid_storage.hpp>
#include <noggit/Red/MapCreationWizard/UI/MapCreationWizard.hpp>
#include <QtGui/QCloseEvent>
#include <QtWidgets/QHBoxLayout>
@@ -261,6 +262,9 @@ namespace noggit
layout->addWidget (_minimap);
setCentralWidget (widget);
auto test = new noggit::Red::MapCreationWizard::Ui::MapCreationWizard();
test->show();
}
void main_window::rebuild_menu()

View File

@@ -187,7 +187,7 @@ namespace noggit
void minimap_widget::mouseDoubleClickEvent (QMouseEvent* event)
{
if (event->button() != Qt::LeftButton)
if (event->button() != Qt::LeftButton || !_world)
{
event->ignore();
return;