diff --git a/cubiomes b/cubiomes index 3899100..e61f4f1 160000 --- a/cubiomes +++ b/cubiomes @@ -1 +1 @@ -Subproject commit 389910035a5483022e7d42e5f37bc0c9440efef0 +Subproject commit e61f4f1ebf0bda93d16309ca45a216d632c23acc diff --git a/src/configdialog.cpp b/src/configdialog.cpp index 1252045..1b366f0 100644 --- a/src/configdialog.cpp +++ b/src/configdialog.cpp @@ -23,6 +23,7 @@ ConfigDialog::~ConfigDialog() void ConfigDialog::initSettings(Config *config) { ui->checkSmooth->setChecked(config->smoothMotion); + ui->checkBBoxes->setChecked(config->showBBoxes); ui->checkRestore->setChecked(config->restoreSession); ui->checkAutosave->setChecked(config->autosaveCycle != 0); if (config->autosaveCycle) @@ -36,6 +37,7 @@ void ConfigDialog::initSettings(Config *config) Config ConfigDialog::getSettings() { conf.restoreSession = ui->checkRestore->isChecked(); + conf.showBBoxes = ui->checkBBoxes->isChecked(); conf.autosaveCycle = ui->checkAutosave->isChecked() ? ui->spinAutosave->value() : 0; conf.smoothMotion = ui->checkSmooth->isChecked(); conf.uistyle = ui->comboStyle->currentIndex(); diff --git a/src/configdialog.ui b/src/configdialog.ui index dca4587..917f1bc 100644 --- a/src/configdialog.ui +++ b/src/configdialog.ui @@ -2,14 +2,6 @@ ConfigDialog - - - 0 - 0 - 411 - 252 - - Preferences @@ -18,14 +10,14 @@ :/icons/map.png:/icons/map.png - + Maximum number of matching seeds: - + Qt::Horizontal @@ -35,7 +27,7 @@ - + Size of search item queue: @@ -43,7 +35,7 @@ - + Seeds per thread search item: @@ -60,17 +52,10 @@ - + - - - - Restore previous session at launch - - - - + @@ -80,17 +65,17 @@ - + - + Autosave every: - + min @@ -106,14 +91,14 @@ - + GUI style: - + @@ -133,6 +118,20 @@ + + + + Outline known bounding boxes + + + + + + + Restore previous session at launch + + + diff --git a/src/formgen48.cpp b/src/formgen48.cpp index 3ea5c4c..2f2506e 100644 --- a/src/formgen48.cpp +++ b/src/formgen48.cpp @@ -8,7 +8,48 @@ #include #include #include +#include +#include +#include + +class SetSpinBox : public QSpinBox +{ +public: + SetSpinBox(QWidget *parent) + : QSpinBox(parent) + { + std::set vset; + for (int i = 0, n = sizeof(g_qm_90) / sizeof(int64_t); i < n; i++) + vset.insert(qmonumentQual(g_qm_90[i])); + for (int v : vset) + vlist.push_back(v); + + setRange(vlist.front(), vlist.last()); + setValue(vlist.front()); + } + virtual ~SetSpinBox() {} + + virtual void stepBy(int steps) override + { + int val = value(); + int idx = 0; + for (int i = 0, n = vlist.size(); i < n; i++) + { + if (vlist[i] > val) + break; + idx = i; + } + idx += steps; + if (idx < 0) + idx = 0; + if (idx >= vlist.size()) + idx = vlist.size() - 1; + setValue(vlist[idx]); + } + + QList vlist; +}; FormGen48::FormGen48(MainWindow *parent) : QWidget(parent) @@ -29,7 +70,10 @@ FormGen48::FormGen48(MainWindow *parent) connect(ui->lineEditX2, SIGNAL(editingFinished()), SLOT(onChange())); connect(ui->lineEditZ2, SIGNAL(editingFinished()), SLOT(onChange())); - connect(ui->spinMonumentArea, SIGNAL(editingFinished()), SLOT(onChange())); + spinMonumentArea = new SetSpinBox(this); + ui->tabQuadM->layout()->addWidget(spinMonumentArea); + + connect(spinMonumentArea, SIGNAL(editingFinished()), SLOT(onChange())); connect(ui->lineSalt, SIGNAL(editingFinished()), SLOT(onChange())); connect(ui->lineListSalt, SIGNAL(editingFinished()), SLOT(onChange())); @@ -45,6 +89,7 @@ FormGen48::FormGen48(MainWindow *parent) FormGen48::~FormGen48() { delete ui; + delete spinMonumentArea; } bool FormGen48::setList48(QString path, bool quiet) @@ -89,7 +134,7 @@ void FormGen48::setSettings(const Gen48Settings& gen48, bool quiet) { ui->tabWidget->setCurrentIndex(gen48.mode); ui->comboLow20->setCurrentIndex(gen48.qual); - ui->spinMonumentArea->setValue(gen48.qmarea); + spinMonumentArea->setValue(gen48.qmarea); ui->lineSalt->setText(QString::number(gen48.salt)); ui->lineListSalt->setText(QString::number(gen48.listsalt)); ui->lineEditX1->setText(QString::number(gen48.x1)); @@ -113,7 +158,7 @@ Gen48Settings FormGen48::getSettings(bool resolveauto) s.mode = ui->tabWidget->currentIndex(); s.qual = ui->comboLow20->currentIndex(); - s.qmarea = ui->spinMonumentArea->value(); + s.qmarea = spinMonumentArea->value(); s.salt = ui->lineSalt->text().toLongLong(); s.listsalt = ui->lineListSalt->text().toLongLong(); s.manualarea = ui->radioManual->isChecked(); @@ -238,7 +283,7 @@ void FormGen48::updateAutoUi() if (isqh) ui->comboLow20->setCurrentIndex(cond.type - F_QH_IDEAL); else if (isqm) - ui->spinMonumentArea->setValue((int) ceil( 58*58*4 * (cond.type == F_QM_95 ? 0.95 : 0.90) )); + spinMonumentArea->setValue((int) ceil( 58*58*4 * (cond.type == F_QM_95 ? 0.95 : 0.90) )); } if (ui->radioAuto->isChecked()) { diff --git a/src/formgen48.h b/src/formgen48.h index b1dbd98..21e8a6d 100644 --- a/src/formgen48.h +++ b/src/formgen48.h @@ -12,6 +12,7 @@ class FormGen48; } class MainWindow; +class SetSpinBox; class FormGen48 : public QWidget { @@ -52,6 +53,7 @@ private slots: private: MainWindow *parent; Ui::FormGen48 *ui; + SetSpinBox *spinMonumentArea; // main condition for "auto" mode (updated when conditions change) Condition cond; diff --git a/src/formgen48.ui b/src/formgen48.ui index fc9223e..1aab511 100644 --- a/src/formgen48.ui +++ b/src/formgen48.ui @@ -20,31 +20,13 @@ Form - - 0 - - - 0 - - - 0 - - + 0 - - 0 - - - 0 - - - 0 - - + 0 @@ -57,16 +39,7 @@ Auto/None - - 4 - - - 4 - - - 4 - - + 4 @@ -90,16 +63,7 @@ Quad-feature - - 4 - - - 4 - - - 4 - - + 4 @@ -171,20 +135,8 @@ Applies only to feature-structures of region-size = 32 and chunk-gap = 8, in par Quad-monument - - - 4 - - - 4 - - - 4 - - - 4 - - + + Number of planar spawning spaces inside monuments that are within 128 blocks of a center position @@ -195,19 +147,6 @@ Applies only to feature-structures of region-size = 32 and chunk-gap = 8, in par - - - - 12115 - - - 13028 - - - 13028 - - - @@ -215,16 +154,7 @@ Applies only to feature-structures of region-size = 32 and chunk-gap = 8, in par Seed list - - 4 - - - 4 - - - 4 - - + 4 @@ -296,16 +226,7 @@ Applies only to feature-structures of region-size = 32 and chunk-gap = 8, in par QFrame::Plain - - 0 - - - 0 - - - 0 - - + 0 diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 48926e8..0b88a72 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -84,11 +84,9 @@ MainWindow::MainWindow(QWidget *parent) "The generator mode Auto is recommended for general use, which " "automatically selects suitable options based on the conditions list." "

" - "The Quad-feature generator mode uses certain low bits to " - "produce a list of candidates for structures in ideal proximity. This " - "only works for structures with uniform distributions of region-size=32 " - "and chunk-gap=8. For swamp huts this can be extended to include more " - "constellations with all bounding boxes within 128 blocks." + "The Quad-feature mode produces candidates for " + "quad‑structures that have a uniform distribution of " + "region‑size=32 and chunk‑gap=8, such as swamp huts." "

" "A perfect Quad-monument structure constellation does not " "actually exist, but some extremely rare structure seed bases get close, " @@ -280,6 +278,7 @@ void MainWindow::saveSettings() settings.setValue("mainwindow/pos", pos()); settings.setValue("mainwindow/prevdir", prevdir); settings.setValue("config/restoreSession", config.restoreSession); + settings.setValue("config/showBBoxes", config.showBBoxes); settings.setValue("config/autosaveCycle", config.autosaveCycle); settings.setValue("config/smoothMotion", config.smoothMotion); settings.setValue("config/uistyle", config.uistyle); @@ -324,6 +323,7 @@ void MainWindow::loadSettings() move(settings.value("mainwindow/pos", pos()).toPoint()); prevdir = settings.value("mainwindow/prevdir", pos()).toString(); config.smoothMotion = settings.value("config/smoothMotion", config.smoothMotion).toBool(); + config.showBBoxes = settings.value("config/showBBoxes", config.showBBoxes).toBool(); config.restoreSession = settings.value("config/restoreSession", config.restoreSession).toBool(); config.autosaveCycle = settings.value("config/autosaveCycle", config.autosaveCycle).toInt(); config.uistyle = settings.value("config/uistyle", config.uistyle).toInt(); @@ -331,6 +331,7 @@ void MainWindow::loadSettings() config.queueSize = settings.value("config/queueSize", config.queueSize).toInt(); config.maxMatching = settings.value("config/maxMatching", config.maxMatching).toInt(); + ui->mapView->setShowBB(config.showBBoxes); ui->mapView->setSmoothMotion(config.smoothMotion); onStyleChanged(config.uistyle); @@ -650,6 +651,7 @@ void MainWindow::on_actionPreferences_triggered() { Config oldConfig = config; config = dialog->getSettings(); + ui->mapView->setShowBB(config.showBBoxes); ui->mapView->setSmoothMotion(config.smoothMotion); if (oldConfig.uistyle != config.uistyle) onStyleChanged(config.uistyle); @@ -866,7 +868,7 @@ void MainWindow::on_buttonAnalysis_clicked() QTreeWidgetItem* item_cat; item_cat = new QTreeWidgetItem(tree); - item_cat->setText(0, "Biomes"); + item_cat->setText(0, "biomes"); item_cat->setData(1, Qt::DisplayRole, QVariant::fromValue(bcnt)); for (int id = 0; id < 256; id++) @@ -922,7 +924,7 @@ void MainWindow::on_buttonAnalysis_clicked() if (vp.variant) { if (stype == Village) - item->setText(1, "Abandoned"); + item->setText(1, "abandoned"); } } //tree->insertTopLevelItem(stype, item_cat); @@ -934,7 +936,7 @@ void MainWindow::on_buttonAnalysis_clicked() if (pos.x >= x1 && pos.x <= x2 && pos.z >= z1 && pos.z <= z2) { item_cat = new QTreeWidgetItem(tree); - item_cat->setText(0, "Spawn"); + item_cat->setText(0, "spawn"); item_cat->setData(1, Qt::DisplayRole, QVariant::fromValue(1)); QTreeWidgetItem* item = new QTreeWidgetItem(item_cat); item->setData(0, Qt::UserRole, QVariant::fromValue(pos)); @@ -957,7 +959,7 @@ void MainWindow::on_buttonAnalysis_clicked() if (!shp.empty()) { item_cat = new QTreeWidgetItem(tree); - item_cat->setText(0, "Stronghold"); + item_cat->setText(0, "stronghold"); item_cat->setData(1, Qt::DisplayRole, QVariant::fromValue(shp.size())); for (Pos pos : shp) { diff --git a/src/mapview.cpp b/src/mapview.cpp index a6be426..f5902ac 100644 --- a/src/mapview.cpp +++ b/src/mapview.cpp @@ -96,13 +96,6 @@ void MapView::setSeed(WorldInfo wi, int dim) update(2); } -void MapView::setShow(int stype, bool v) -{ - sshow[stype] = v; - settingsToWorld(); - update(2); -} - void MapView::setView(qreal x, qreal z, qreal scale) { if (scale > 0) @@ -115,6 +108,20 @@ void MapView::setView(qreal x, qreal z, qreal scale) update(2); } +void MapView::setShow(int stype, bool v) +{ + sshow[stype] = v; + settingsToWorld(); + update(2); +} + +void MapView::setShowBB(bool show) +{ + showBB = show; + settingsToWorld(); + update(2); +} + void MapView::setSmoothMotion(bool smooth) { hasinertia = smooth; @@ -126,6 +133,7 @@ void MapView::settingsToWorld() return; for (int s = 0; s < STRUCT_NUM; s++) world->sshow[s] = sshow[s]; + world->showBB = showBB; } qreal MapView::getX() diff --git a/src/mapview.h b/src/mapview.h index 3f01334..7cb888d 100644 --- a/src/mapview.h +++ b/src/mapview.h @@ -42,6 +42,7 @@ public: bool getShow(int stype) { return stype >= 0 && stype < STRUCT_NUM ? sshow[stype] : false; } void setShow(int stype, bool v); + void setShowBB(bool show); void setSmoothMotion(bool smooth); void timeout(); @@ -87,6 +88,7 @@ private: int updatecounter; bool sshow[STRUCT_NUM]; + bool showBB; bool hasinertia; }; diff --git a/src/quad.cpp b/src/quad.cpp index 0d8ae1f..f7a6520 100644 --- a/src/quad.cpp +++ b/src/quad.cpp @@ -409,8 +409,10 @@ QWorld::QWorld(WorldInfo wi, int dim) , cachedbiomes() , cachedstruct() , cachesize() + , showBB() , spawn() , strongholds() + , qsinfo() , isdel() , slimeimg() , slimex() @@ -509,6 +511,7 @@ QWorld::~QWorld() { delete spawn; delete strongholds; + delete qsinfo; } } @@ -642,6 +645,15 @@ struct SpawnStronghold : public QRunnable } world->strongholds = shp; + + std::vector *qsinfo = new std::vector; + + if (!world->isdel) + findQuadStructs(Swamp_Hut, wi.mc, &g, wi.seed, qsinfo); + if (!world->isdel) + findQuadStructs(Monument, wi.mc, &g, wi.seed, qsinfo); + + world->qsinfo = qsinfo; } }; @@ -738,6 +750,26 @@ void QWorld::draw(QPainter& painter, int vw, int vh, qreal focusx, qreal focusz, } + if (showBB && blocks2pix >= 1.0 && qsinfo && dim == 0) + { + for (QuadInfo qi : *qsinfo) + { + if (qi.typ == Swamp_Hut && !sshow[D_HUT]) + continue; + if (qi.typ == Monument && !sshow[D_MONUMENT]) + continue; + + qreal x = vw/2.0 + (qi.afk.x - focusx) * blocks2pix; + qreal y = vh/2.0 + (qi.afk.z - focusz) * blocks2pix; + qreal r = 128.0 * blocks2pix; + painter.setPen(QPen(QColor(192, 0, 0, 160), 1)); + painter.drawEllipse(QRectF(x-r, y-r, 2*r, 2*r)); + r = 16; + painter.drawLine(QPointF(x-r,y), QPointF(x+r,y)); + painter.drawLine(QPointF(x,y-r), QPointF(x,y+r)); + } + } + for (int sopt = D_DESERT; sopt < D_SPAWN; sopt++) { Level& l = lvs[sopt]; @@ -759,23 +791,44 @@ void QWorld::draw(QPainter& painter, int vw, int vh, qreal focusx, qreal focusz, if (x < 0 || x >= vw || y < 0 || y >= vh) continue; - QPointF d = QPointF(x, y); - QRectF r = icons[sopt].rect(); - if (sopt == D_VILLAGE) + if (showBB && blocks2pix > 1.0) { - if (vp.variant) { - painter.drawPixmap(x-r.width()/2, y-r.height()/2, iconzvil); - } else { - frags.push_back(QPainter::PixmapFragment::create(d, r)); + int sx = 0, sz = 0; + if (sopt == D_DESERT) + { + sx = 21; sz = 21; + } + else if (sopt == D_JUNGLE) + { + sx = 12; sz = 15; + } + else if (sopt == D_HUT) + { + sx = 7; sz = 9; + } + else if (sopt == D_MONUMENT) + { + x -= 29 * blocks2pix; + y -= 29 * blocks2pix; + sx = 58; sz = 58; + } + + if (sx && sz) + { // draw bounding box and move icon to its center + qreal dx = sx * blocks2pix; + qreal dy = sz * blocks2pix; + painter.setPen(QPen(QColor(192, 0, 0, 160), 1)); + painter.drawRect(QRect(x, y, dx, dy)); + x += dx / 2; + y += dy / 2; } } - else - { - frags.push_back(QPainter::PixmapFragment::create(d, r)); - } + + QPointF d = QPointF(x, y); if (seldo) - { + { // check for structure selection + QRectF r = icons[sopt].rect(); r.moveCenter(d); if (r.contains(selx, selz)) { @@ -784,6 +837,23 @@ void QWorld::draw(QPainter& painter, int vw, int vh, qreal focusx, qreal focusz, selvar = vp.variant; } } + if (seltype != sopt || selpos.x != vp.p.x || selpos.z != vp.p.z) + { // draw unselected structures + QRectF r = icons[sopt].rect(); + if (sopt == D_VILLAGE) + { + if (vp.variant) { + int ix = d.x()-r.width()/2, iy = d.y()-r.height()/2; + painter.drawPixmap(ix, iy, iconzvil); + } else { + frags.push_back(QPainter::PixmapFragment::create(d, r)); + } + } + else + { + frags.push_back(QPainter::PixmapFragment::create(d, r)); + } + } } } @@ -857,10 +927,13 @@ void QWorld::draw(QPainter& painter, int vw, int vh, qreal focusx, qreal focusz, } // start the spawn and stronghold worker thread if this is the first run - if (spawn == NULL && (sshow[D_SPAWN] || sshow[D_STRONGHOLD])) + if (spawn == NULL) { - spawn = (Pos*) -1; - QThreadPool::globalInstance()->start(new SpawnStronghold(this, wi)); + if (sshow[D_SPAWN] || sshow[D_STRONGHOLD] || (showBB && blocks2pix >= 1.0)) + { + spawn = (Pos*) -1; + QThreadPool::globalInstance()->start(new SpawnStronghold(this, wi)); + } } if (seldo) diff --git a/src/quad.h b/src/quad.h index 3010d0d..464fd2d 100644 --- a/src/quad.h +++ b/src/quad.h @@ -2,6 +2,7 @@ #define QUAD_H #include "settings.h" +#include "search.h" #include #include @@ -222,10 +223,13 @@ struct QWorld unsigned int cachesize; bool sshow[STRUCT_NUM]; + bool showBB; - // spawn and strongholds will be filled by a designated worker thread once results are done + // some features such as the world spawn and strongholds will be filled by + // a designated worker thread once results are done QAtomicPointer spawn; QAtomicPointer> strongholds; + QAtomicPointer> qsinfo; // isdel is a flag for the worker thread to stop std::atomic_bool isdel; diff --git a/src/quadlistdialog.cpp b/src/quadlistdialog.cpp index f53a24a..da18185 100644 --- a/src/quadlistdialog.cpp +++ b/src/quadlistdialog.cpp @@ -21,9 +21,10 @@ QuadListDialog::QuadListDialog(MainWindow *mainwindow) QFont mono = QFont("Monospace", 9); mono.setStyleHint(QFont::TypeWriter); ui->listQuadStruct->setFont(mono); - ui->listQuadStruct->setColumnWidth(0, 100); + ui->listQuadStruct->setColumnWidth(0, 120); ui->listQuadStruct->setColumnWidth(1, 80); ui->listQuadStruct->setColumnWidth(2, 160); + ui->listQuadStruct->setColumnWidth(3, 120); loadSeed(); refresh(); @@ -89,120 +90,57 @@ void QuadListDialog::refresh() LayerStack g; setupGeneratorLargeBiomes(&g, wi.mc, wi.large); - StructureConfig sconf; - getStructureConfig_override(Swamp_Hut, wi.mc, &sconf); + std::vector qsinfo; - const int maxq = 1000; - Pos *qlist = new Pos[maxq]; - int r = 3e7 / 512; - int qcnt; + findQuadStructs(Swamp_Hut, wi.mc, &g, wi.seed, &qsinfo); + findQuadStructs(Monument, wi.mc, &g, wi.seed, &qsinfo); - qcnt = scanForQuads( - sconf, 128, (wi.seed) & MASK48, - low20QuadHutBarely, sizeof(low20QuadHutBarely) / sizeof(uint64_t), 20, sconf.salt, - -r, -r, 2*r, 2*r, qlist, maxq); - - if (qcnt >= maxq) - QMessageBox::warning(this, "Warning", "Quad-hut scanning buffer exhausted, results will be incomplete."); - - ui->listQuadStruct->setSortingEnabled(false); int row = 0, qhn = 0, qmn = 0; - for (int i = 0; i < qcnt; i++) + for (QuadInfo& qi : qsinfo) { - Pos qh[4]; - getStructurePos(sconf.structType, wi.mc, wi.seed, qlist[i].x+0, qlist[i].z+0, qh+0); - getStructurePos(sconf.structType, wi.mc, wi.seed, qlist[i].x+0, qlist[i].z+1, qh+1); - getStructurePos(sconf.structType, wi.mc, wi.seed, qlist[i].x+1, qlist[i].z+0, qh+2); - getStructurePos(sconf.structType, wi.mc, wi.seed, qlist[i].x+1, qlist[i].z+1, qh+3); - if (isViableStructurePos(sconf.structType, wi.mc, &g, wi.seed, qh[0].x, qh[0].z) && - isViableStructurePos(sconf.structType, wi.mc, &g, wi.seed, qh[1].x, qh[1].z) && - isViableStructurePos(sconf.structType, wi.mc, &g, wi.seed, qh[2].x, qh[2].z) && - isViableStructurePos(sconf.structType, wi.mc, &g, wi.seed, qh[3].x, qh[3].z)) + const char *label; + if (qi.typ == Swamp_Hut) { - ui->listQuadStruct->insertRow(row); - Pos afk; - afk = getOptimalAfk(qh, 7,7,9, 0); - float rad = isQuadBase(sconf, moveStructure(wi.seed, -qlist[i].x, -qlist[i].z), 128); - int dist = (int) round(sqrt(afk.x * (qreal)afk.x + afk.z * (qreal)afk.z)); - QVariant var = QVariant::fromValue(afk); - - QTableWidgetItem* stritem = new QTableWidgetItem("Quad-Hut"); - stritem->setData(Qt::UserRole, var); - ui->listQuadStruct->setItem(row, 0, stritem); - - QTableWidgetItem* distitem = new QTableWidgetItem(); - distitem->setData(Qt::UserRole, var); - distitem->setData(Qt::DisplayRole, dist); - ui->listQuadStruct->setItem(row, 1, distitem); - - QTableWidgetItem* afkitem = new QTableWidgetItem(); - afkitem->setData(Qt::UserRole, var); - afkitem->setText(QString::asprintf("(%d,%d)", afk.x, afk.z)); - ui->listQuadStruct->setItem(row, 2, afkitem); - - QTableWidgetItem* raditem = new QTableWidgetItem(); - raditem->setData(Qt::UserRole, var); - raditem->setText(QString::asprintf("%.1f", rad)); - ui->listQuadStruct->setItem(row, 3, raditem); - row++; + label = "Quad-Hut"; + qhn++; } - } - qhn = row; - - if (wi.mc >= MC_1_8) - { - getStructureConfig_override(Monument, wi.mc, &sconf); - qcnt = scanForQuads( - sconf, 160, wi.seed & MASK48, - g_qm_90, sizeof(g_qm_90) / sizeof(uint64_t), 48, sconf.salt, - -r, -r, 2*r, 2*r, qlist, maxq); - - if (qcnt >= maxq) - QMessageBox::warning(this, "Warning", "Quad-monument scanning buffer exhausted, results will be incomplete."); - - for (int i = 0; i < qcnt; i++) + else { - Pos qm[4]; - getStructurePos(sconf.structType, wi.mc, wi.seed, qlist[i].x+0, qlist[i].z+0, qm+0); - getStructurePos(sconf.structType, wi.mc, wi.seed, qlist[i].x+0, qlist[i].z+1, qm+1); - getStructurePos(sconf.structType, wi.mc, wi.seed, qlist[i].x+1, qlist[i].z+0, qm+2); - getStructurePos(sconf.structType, wi.mc, wi.seed, qlist[i].x+1, qlist[i].z+1, qm+3); - if (isViableStructurePos(sconf.structType, wi.mc, &g, wi.seed, qm[0].x, qm[0].z) && - isViableStructurePos(sconf.structType, wi.mc, &g, wi.seed, qm[1].x, qm[1].z) && - isViableStructurePos(sconf.structType, wi.mc, &g, wi.seed, qm[2].x, qm[2].z) && - isViableStructurePos(sconf.structType, wi.mc, &g, wi.seed, qm[3].x, qm[3].z)) - { - ui->listQuadStruct->insertRow(row); - Pos afk; - afk = getOptimalAfk(qm, 58,23,58, 0); - afk.x -= 29; afk.z -= 29; // monuments position is centered - float rad = isQuadBase(sconf, moveStructure(wi.seed, -qlist[i].x, -qlist[i].z), 160); - int dist = (int) round(sqrt(afk.x * (qreal)afk.x + afk.z * (qreal)afk.z)); - QVariant var = QVariant::fromValue(afk); - - QTableWidgetItem* stritem = new QTableWidgetItem("Quad-Monument"); - stritem->setData(Qt::UserRole, var); - ui->listQuadStruct->setItem(row, 0, stritem); - - QTableWidgetItem* distitem = new QTableWidgetItem(); - distitem->setData(Qt::UserRole, var); - distitem->setData(Qt::DisplayRole, dist); - ui->listQuadStruct->setItem(row, 1, distitem); - - QTableWidgetItem* afkitem = new QTableWidgetItem(); - afkitem->setData(Qt::UserRole, var); - afkitem->setText(QString::asprintf("(%d,%d)", afk.x, afk.z)); - ui->listQuadStruct->setItem(row, 2, afkitem); - - QTableWidgetItem* raditem = new QTableWidgetItem(); - raditem->setData(Qt::UserRole, var); - raditem->setText(QString::asprintf("%.1f", rad)); - ui->listQuadStruct->setItem(row, 3, raditem); - row++; - } + label = "Quad-Monument"; + qmn++; } + + QVariant var = QVariant::fromValue(qi.afk); + qreal dist = qi.afk.x*(qreal)qi.afk.x + qi.afk.z*(qreal)qi.afk.z; + dist = sqrt(dist); + + ui->listQuadStruct->insertRow(row); + + QTableWidgetItem* stritem = new QTableWidgetItem(label); + stritem->setData(Qt::UserRole, var); + ui->listQuadStruct->setItem(row, 0, stritem); + + QTableWidgetItem* distitem = new QTableWidgetItem(); + distitem->setData(Qt::UserRole, var); + distitem->setData(Qt::DisplayRole, (int)round(dist)); + ui->listQuadStruct->setItem(row, 1, distitem); + + QTableWidgetItem* afkitem = new QTableWidgetItem(); + afkitem->setData(Qt::UserRole, var); + afkitem->setText(QString::asprintf("(%d,%d)", qi.afk.x, qi.afk.z)); + ui->listQuadStruct->setItem(row, 2, afkitem); + + QTableWidgetItem* raditem = new QTableWidgetItem(); + raditem->setData(Qt::UserRole, var); + raditem->setText(QString::asprintf("%.1f", qi.rad)); + ui->listQuadStruct->setItem(row, 3, raditem); + + QTableWidgetItem* cntitem = new QTableWidgetItem(); + cntitem->setData(Qt::UserRole, var); + cntitem->setText(QString::asprintf("%d", qi.spcnt)); + ui->listQuadStruct->setItem(row, 4, cntitem); + row++; } - qmn = row - qhn; ui->listQuadStruct->setSortingEnabled(true); ui->listQuadStruct->sortByColumn(1, Qt::AscendingOrder); @@ -215,8 +153,6 @@ void QuadListDialog::refresh() ui->labelMsg->setText(QString::asprintf("World contains %d quad-hut%s.", qhn, qhn==1?"":"s")); else if (qmn) ui->labelMsg->setText(QString::asprintf("World contains %d quad-monument%s.", qmn, qmn==1?"":"s")); - - delete[] qlist; } void QuadListDialog::on_buttonGo_clicked() diff --git a/src/quadlistdialog.ui b/src/quadlistdialog.ui index 8721d02..2d28556 100644 --- a/src/quadlistdialog.ui +++ b/src/quadlistdialog.ui @@ -6,8 +6,8 @@ 0 0 - 540 - 333 + 700 + 321 @@ -21,7 +21,7 @@ - Quad-Huts + Quad-Structures @@ -43,6 +43,9 @@ QAbstractItemView::SelectRows + + QAbstractItemView::ScrollPerPixel + true @@ -57,7 +60,7 @@ Structure - AlignLeading|AlignVCenter + AlignLeft|AlignVCenter @@ -68,7 +71,7 @@ distance to origin - AlignLeading|AlignVCenter + AlignLeft|AlignVCenter @@ -79,18 +82,29 @@ optimal AFK location - AlignLeading|AlignVCenter + AlignLeft|AlignVCenter - Spawn range + Enclosing range distance to furthest spawning space from optimal AFK position - AlignLeading|AlignVCenter + AlignLeft|AlignVCenter + + + + + Spawn area + + + horizontal area in a 128 block range + + + AlignLeft|AlignVCenter @@ -223,7 +237,8 @@ - .. + + diff --git a/src/search.cpp b/src/search.cpp index 5edf82a..fd1d916 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -61,7 +61,12 @@ static bool isInnerRingOk(int mc, uint64_t seed, int x1, int z1, int x2, int z2, } -int testCond(StructPos *spos, uint64_t seed, const Condition *cond, int mc, LayerStack *g, std::atomic_bool *abort) +int +testCond( + StructPos *spos, const Condition *cond, + int mc, LayerStack *g, uint64_t seed, + std::atomic_bool *abort + ) { int x1, x2, z1, z2; int rx1, rx2, rz1, rz2, rx, rz; @@ -607,3 +612,94 @@ L_nether_end: return 1; } + + +void findQuadStructs( + int styp, int mc, LayerStack *g, uint64_t seed, + std::vector *out + ) +{ + StructureConfig sconf; + if (!getStructureConfig_override(styp, mc, &sconf)) + return; + + int qmax = 1000; + Pos *qlist = new Pos[qmax]; + int r = 3e7 / 512; + int qcnt; + + if (styp == Swamp_Hut) + { + qcnt = scanForQuads( + sconf, 128, seed & MASK48, + low20QuadHutBarely, sizeof(low20QuadHutBarely) / sizeof(uint64_t), + 20, sconf.salt, + -r, -r, 2*r, 2*r, qlist, qmax + ); + + for (int i = 0; i < qcnt; i++) + { + Pos qr = qlist[i]; + Pos qs[4]; + getStructurePos(styp, mc, seed, qr.x+0, qr.z+0, qs+0); + getStructurePos(styp, mc, seed, qr.x+0, qr.z+1, qs+1); + getStructurePos(styp, mc, seed, qr.x+1, qr.z+0, qs+2); + getStructurePos(styp, mc, seed, qr.x+1, qr.z+1, qs+3); + if (isViableStructurePos(styp, mc, g, seed, qs[0].x, qs[0].z) && + isViableStructurePos(styp, mc, g, seed, qs[1].x, qs[1].z) && + isViableStructurePos(styp, mc, g, seed, qs[2].x, qs[2].z) && + isViableStructurePos(styp, mc, g, seed, qs[3].x, qs[3].z)) + { + QuadInfo qinfo; + for (int j = 0; j < 4; j++) + qinfo.p[j] = qs[j]; + qinfo.typ = styp; + qinfo.afk = getOptimalAfk(qs, 7,7,9, &qinfo.spcnt); + qinfo.rad = isQuadBase(sconf, moveStructure(seed,-qr.x,-qr.z), 160); + out->push_back(qinfo); + } + } + } + else if (styp == Monument) + { + qcnt = scanForQuads( + sconf, 160, seed & MASK48, + g_qm_90, sizeof(g_qm_90) / sizeof(uint64_t), + 48, sconf.salt, + -r, -r, 2*r, 2*r, qlist, qmax + ); + + for (int i = 0; i < qcnt; i++) + { + Pos qr = qlist[i]; + Pos qs[4]; + getStructurePos(styp, mc, seed, qr.x+0, qr.z+0, qs+0); + getStructurePos(styp, mc, seed, qr.x+0, qr.z+1, qs+1); + getStructurePos(styp, mc, seed, qr.x+1, qr.z+0, qs+2); + getStructurePos(styp, mc, seed, qr.x+1, qr.z+1, qs+3); + if (isViableStructurePos(styp, mc, g, seed, qs[0].x, qs[0].z) && + isViableStructurePos(styp, mc, g, seed, qs[1].x, qs[1].z) && + isViableStructurePos(styp, mc, g, seed, qs[2].x, qs[2].z) && + isViableStructurePos(styp, mc, g, seed, qs[3].x, qs[3].z)) + { + QuadInfo qinfo; + for (int j = 0; j < 4; j++) + qinfo.p[j] = qs[j]; + qinfo.typ = styp; + qinfo.afk = getOptimalAfk(qs, 58,0/*23*/,58, &qinfo.spcnt); + qinfo.afk.x -= 29; + qinfo.afk.z -= 29; + qinfo.rad = isQuadBase(sconf, moveStructure(seed,-qr.x,-qr.z), 160); + out->push_back(qinfo); + } + } + } + + delete[] qlist; +} + + + + + + diff --git a/src/search.h b/src/search.h index 6335c3c..10d1f03 100644 --- a/src/search.h +++ b/src/search.h @@ -4,6 +4,7 @@ #include "cubiomes/finders.h" #include +#include #define PRECOMPUTE48_BUFSIZ ((int64_t)1 << 30) @@ -442,8 +443,22 @@ struct StructPos int cx, cz; // effective center position }; +int testCond( + StructPos *spos, const Condition *cond, + int mc, LayerStack *g, uint64_t seed, std::atomic_bool *abort); -int testCond(StructPos *spos, uint64_t seed, const Condition *cond, int mc, LayerStack *g, std::atomic_bool *abort); +struct QuadInfo +{ + Pos p[4]; // individual positions + Pos afk; // optimal afk position + int typ; // type of structure + int spcnt; // number of planar spawning spaces + float rad; // enclosing radius +}; + +void findQuadStructs( + int styp, int mc, LayerStack *g, uint64_t seed, + std::vector *out); #endif // SEARCH_H diff --git a/src/searchitem.cpp b/src/searchitem.cpp index e2638ff..aad9f38 100644 --- a/src/searchitem.cpp +++ b/src/searchitem.cpp @@ -425,7 +425,7 @@ static bool isCandidate(uint64_t s48, int mc, const Condition *c, const Conditio { StructPos spos[100] = {}; for (; c != ce; c++) - if (!testCond(spos, s48, c, mc, NULL, abort)) + if (!testCond(spos, c, mc, NULL, s48, abort)) return false; return true; } diff --git a/src/searchitem.h b/src/searchitem.h index 1ba5514..eba8141 100644 --- a/src/searchitem.h +++ b/src/searchitem.h @@ -31,14 +31,14 @@ public: if (s48check) { for (c = cond; c != ce; c++) - if (!testCond(spos, seed, c, mc, NULL, abort)) + if (!testCond(spos, c, mc, NULL, seed, abort)) return false; } for (c = cond; c != ce; c++) { if (g_filterinfo.list[c->type].cat == CAT_QUAD) continue; - if (!testCond(spos, seed, c, mc, g, abort)) + if (!testCond(spos, c, mc, g, seed, abort)) return false; } return true; diff --git a/src/seedtables.h b/src/seedtables.h index d33baed..c0c0530 100644 --- a/src/seedtables.h +++ b/src/seedtables.h @@ -120,11 +120,16 @@ static const uint64_t g_qm_95[] = { 40643008242473ULL, 75345282835555ULL, 85241165147001ULL, - 143737608964985ULL, + 117558666299491ULL, + 141849622061865ULL, + 157050661340383ULL, + 184103120915339ULL, + 197672678105184ULL, 201305970722015ULL, - 206145729365528ULL, 220178926586908ULL, + 206145729365528ULL, 226043537443714ULL, + 143737608964985ULL, }; @@ -169,6 +174,7 @@ static int qhutQual(int low20) } } + // returns for a >90% quadmonument the number of blocks, by area, in spawn range __attribute__((const, used)) static int qmonumentQual(uint64_t s48) @@ -224,24 +230,24 @@ static int qmonumentQual(uint64_t s48) case 96363295408208ULL: return 12253; case 96666172090448ULL: return 12470; case 97326737469569ULL: return 12165; - case 108818308997907ULL: return 12150; - case 110070523643664ULL: return 12400; - case 110929723321216ULL: return 12348; - case 113209246256383ULL: return 12130; - case 117558666299491ULL: return 12687; - case 121197818285311ULL: return 12130; - case 141209514904082ULL: return 12147; - case 141849622061865ULL: return 12630; - case 143737608964985ULL: return 12938; - case 152637010423035ULL: return 12130; - case 157050661340383ULL: return 12588; - case 170156314248098ULL: return 12348; - case 177801560427026ULL: return 12389; - case 183906223213433ULL: return 12358; - case 184103120915339ULL: return 12630; - case 185417015970809ULL: return 12186; - case 195760082985897ULL: return 12118; - case 197672678105184ULL: return 12553; + case 108818308997907ULL: return 12609; + case 110070523643664ULL: return 12758; + case 110929723321216ULL: return 12780; + case 113209246256383ULL: return 12499; + case 117558666299491ULL: return 12948; + case 121197818285311ULL: return 12499; + case 141209514904082ULL: return 12583; + case 141849622061865ULL: return 12983; + case 143737608964985ULL: return 13188; // < best + case 152637010423035ULL: return 12499; + case 157050661340383ULL: return 12912; + case 170156314248098ULL: return 12780; + case 177801560427026ULL: return 12762; + case 183906223213433ULL: return 12748; + case 184103120915339ULL: return 12983; + case 185417015970809ULL: return 12632; + case 195760082985897ULL: return 12589; + case 197672678105184ULL: return 12895; case 201305970722015ULL: return 12948; case 206145729365528ULL: return 12796; case 208212283032595ULL: return 12317; @@ -257,7 +263,7 @@ static int qmonumentQual(uint64_t s48) case 222407767385304ULL: return 12458; case 222506989413161ULL: return 12632; case 223366727763152ULL: return 12296; - case 226043537443714ULL: return 13028; // best + case 226043537443714ULL: return 13028; case 226089485745383ULL: return 12285; case 226837069851090ULL: return 12305; case 228023683672163ULL: return 12742; diff --git a/src/settings.h b/src/settings.h index 8b1220b..2c782cf 100644 --- a/src/settings.h +++ b/src/settings.h @@ -51,6 +51,7 @@ enum { STYLE_SYSTEM, STYLE_DARK }; struct Config { bool smoothMotion; + bool showBBoxes; bool restoreSession; int autosaveCycle; int uistyle; @@ -63,6 +64,7 @@ struct Config void reset() { smoothMotion = true; + showBBoxes = true; restoreSession = true; autosaveCycle = 10; uistyle = STYLE_SYSTEM;